diff --git a/application/src/test/java/org/thingsboard/server/controller/HomePageApiTest.java b/application/src/test/java/org/thingsboard/server/controller/HomePageApiTest.java index 88aa903c76..e9c1aebf58 100644 --- a/application/src/test/java/org/thingsboard/server/controller/HomePageApiTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/HomePageApiTest.java @@ -416,6 +416,9 @@ public class HomePageApiTest extends AbstractControllerTest { Assert.assertEquals(DEFAULT_DASHBOARDS_COUNT, usageInfo.getDashboards()); Assert.assertEquals(configuration.getMaxDashboards(), usageInfo.getMaxDashboards()); + Assert.assertEquals(0, usageInfo.getEdges()); + Assert.assertEquals(configuration.getMaxEdges(), usageInfo.getMaxEdges()); + Assert.assertEquals(0, usageInfo.getTransportMessages()); Assert.assertEquals(configuration.getMaxTransportMessages(), usageInfo.getMaxTransportMessages()); diff --git a/application/src/test/java/org/thingsboard/server/service/notification/NotificationRuleApiTest.java b/application/src/test/java/org/thingsboard/server/service/notification/NotificationRuleApiTest.java index 852ddd757c..a5fb3b05bf 100644 --- a/application/src/test/java/org/thingsboard/server/service/notification/NotificationRuleApiTest.java +++ b/application/src/test/java/org/thingsboard/server/service/notification/NotificationRuleApiTest.java @@ -50,6 +50,7 @@ import org.thingsboard.server.common.data.device.profile.AlarmConditionKeyType; import org.thingsboard.server.common.data.device.profile.AlarmRule; import org.thingsboard.server.common.data.device.profile.DeviceProfileAlarm; import org.thingsboard.server.common.data.device.profile.SimpleAlarmConditionSpec; +import org.thingsboard.server.common.data.edge.Edge; import org.thingsboard.server.common.data.id.AlarmId; import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.common.data.id.TenantId; @@ -125,7 +126,8 @@ import static org.thingsboard.server.common.data.notification.rule.trigger.confi @DaoSqlTest @TestPropertySource(properties = { "transport.http.enabled=true", - "notification_system.rules.deduplication_durations=RATE_LIMITS:10000" + "notification_system.rules.deduplication_durations=RATE_LIMITS:10000", + "edges.enabled=true" }) public class NotificationRuleApiTest extends AbstractNotificationApiTest { @@ -372,6 +374,7 @@ public class NotificationRuleApiTest extends AbstractNotificationApiTest { profileConfiguration.setMaxUsers(limit); profileConfiguration.setMaxDashboards(limit); profileConfiguration.setMaxRuleChains(limit); + profileConfiguration.setMaxEdges(limit); }); EntitiesLimitNotificationRuleTriggerConfig triggerConfig = EntitiesLimitNotificationRuleTriggerConfig.builder() @@ -419,6 +422,19 @@ public class NotificationRuleApiTest extends AbstractNotificationApiTest { assertThat(notification.getText()).isEqualTo("Rule chains usage: " + threshold + "/" + limit + " (80%)"); }); + checkNotificationAfter(() -> { + for (int i = 1; i <= threshold; i++) { + Edge edge = new Edge(); + edge.setName(i + ""); + edge.setType("default"); + edge.setSecret("secret_" + i); + edge.setRoutingKey("routingKey_" + i); + doPost("/api/edge", edge); + } + }, notification -> { + assertThat(notification.getText()).isEqualTo("Edges usage: " + threshold + "/" + limit + " (80%)"); + }); + triggerConfig.setThreshold(1.0f); rule.setTriggerConfig(triggerConfig); loginSysAdmin(); diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/UsageInfo.java b/common/data/src/main/java/org/thingsboard/server/common/data/UsageInfo.java index c2ce47fdb0..037a26ba4c 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/UsageInfo.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/UsageInfo.java @@ -19,6 +19,7 @@ import lombok.Data; @Data public class UsageInfo { + private long devices; private long maxDevices; private long assets; @@ -29,6 +30,8 @@ public class UsageInfo { private long maxUsers; private long dashboards; private long maxDashboards; + private long edges; + private long maxEdges; private long transportMessages; private long maxTransportMessages; @@ -43,4 +46,5 @@ public class UsageInfo { private Boolean smsEnabled; private long alarms; private long maxAlarms; -} \ No newline at end of file + +} diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/tenant/profile/DefaultTenantProfileConfiguration.java b/common/data/src/main/java/org/thingsboard/server/common/data/tenant/profile/DefaultTenantProfileConfiguration.java index 51738c75be..1e4ea75f3f 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/tenant/profile/DefaultTenantProfileConfiguration.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/tenant/profile/DefaultTenantProfileConfiguration.java @@ -24,6 +24,8 @@ import org.thingsboard.server.common.data.ApiUsageRecordKey; import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.TenantProfileType; +import java.io.Serial; + @Schema @AllArgsConstructor @NoArgsConstructor @@ -31,6 +33,7 @@ import org.thingsboard.server.common.data.TenantProfileType; @Data public class DefaultTenantProfileConfiguration implements TenantProfileConfiguration { + @Serial private static final long serialVersionUID = -7134932690332578595L; private long maxDevices; @@ -39,6 +42,7 @@ public class DefaultTenantProfileConfiguration implements TenantProfileConfigura private long maxUsers; private long maxDashboards; private long maxRuleChains; + private long maxEdges; private long maxResourcesInBytes; private long maxOtaPackagesInBytes; private long maxResourceSize; @@ -131,27 +135,18 @@ public class DefaultTenantProfileConfiguration implements TenantProfileConfigura @Override public long getProfileThreshold(ApiUsageRecordKey key) { - switch (key) { - case TRANSPORT_MSG_COUNT: - return maxTransportMessages; - case TRANSPORT_DP_COUNT: - return maxTransportDataPoints; - case JS_EXEC_COUNT: - return maxJSExecutions; - case TBEL_EXEC_COUNT: - return maxTbelExecutions; - case RE_EXEC_COUNT: - return maxREExecutions; - case STORAGE_DP_COUNT: - return maxDPStorageDays; - case EMAIL_EXEC_COUNT: - return maxEmails; - case SMS_EXEC_COUNT: - return maxSms; - case CREATED_ALARMS_COUNT: - return maxCreatedAlarms; - } - return 0L; + return switch (key) { + case TRANSPORT_MSG_COUNT -> maxTransportMessages; + case TRANSPORT_DP_COUNT -> maxTransportDataPoints; + case JS_EXEC_COUNT -> maxJSExecutions; + case TBEL_EXEC_COUNT -> maxTbelExecutions; + case RE_EXEC_COUNT -> maxREExecutions; + case STORAGE_DP_COUNT -> maxDPStorageDays; + case EMAIL_EXEC_COUNT -> maxEmails; + case SMS_EXEC_COUNT -> maxSms; + case CREATED_ALARMS_COUNT -> maxCreatedAlarms; + default -> 0L; + }; } @Override @@ -170,22 +165,16 @@ public class DefaultTenantProfileConfiguration implements TenantProfileConfigura } public long getEntitiesLimit(EntityType entityType) { - switch (entityType) { - case DEVICE: - return maxDevices; - case ASSET: - return maxAssets; - case CUSTOMER: - return maxCustomers; - case USER: - return maxUsers; - case DASHBOARD: - return maxDashboards; - case RULE_CHAIN: - return maxRuleChains; - default: - return 0; - } + return switch (entityType) { + case DEVICE -> maxDevices; + case ASSET -> maxAssets; + case CUSTOMER -> maxCustomers; + case USER -> maxUsers; + case DASHBOARD -> maxDashboards; + case RULE_CHAIN -> maxRuleChains; + case EDGE -> maxEdges; + default -> 0; + }; } @Override @@ -197,4 +186,5 @@ public class DefaultTenantProfileConfiguration implements TenantProfileConfigura public int getMaxRuleNodeExecsPerMessage() { return maxRuleNodeExecutionsPerMessage; } + } diff --git a/dao/src/main/java/org/thingsboard/server/dao/edge/EdgeDao.java b/dao/src/main/java/org/thingsboard/server/dao/edge/EdgeDao.java index e012766a8f..d813d2e3c9 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/edge/EdgeDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/edge/EdgeDao.java @@ -25,6 +25,7 @@ import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.dao.Dao; +import org.thingsboard.server.dao.TenantEntityDao; import java.util.List; import java.util.Optional; @@ -34,7 +35,7 @@ import java.util.UUID; * The Interface EdgeDao. * */ -public interface EdgeDao extends Dao { +public interface EdgeDao extends Dao, TenantEntityDao { Edge save(TenantId tenantId, Edge edge); diff --git a/dao/src/main/java/org/thingsboard/server/dao/edge/EdgeServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/edge/EdgeServiceImpl.java index c9b465b178..51999bcd36 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/edge/EdgeServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/edge/EdgeServiceImpl.java @@ -61,6 +61,7 @@ import org.thingsboard.server.common.data.rule.RuleChain; import org.thingsboard.server.common.data.rule.RuleNode; import org.thingsboard.server.dao.attributes.AttributesService; import org.thingsboard.server.dao.entity.AbstractCachedEntityService; +import org.thingsboard.server.dao.entity.EntityCountService; import org.thingsboard.server.dao.eventsourcing.ActionEntityEvent; import org.thingsboard.server.dao.eventsourcing.DeleteEntityEvent; import org.thingsboard.server.dao.eventsourcing.SaveEntityEvent; @@ -127,6 +128,9 @@ public class EdgeServiceImpl extends AbstractCachedEntityService> findEntity(TenantId tenantId, EntityId entityId) { return Optional.ofNullable(findEdgeById(tenantId, new EdgeId(entityId.getId()))); diff --git a/dao/src/main/java/org/thingsboard/server/dao/service/validator/EdgeDataValidator.java b/dao/src/main/java/org/thingsboard/server/dao/service/validator/EdgeDataValidator.java index b6050e74bb..1d3b4a39d3 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/service/validator/EdgeDataValidator.java +++ b/dao/src/main/java/org/thingsboard/server/dao/service/validator/EdgeDataValidator.java @@ -18,6 +18,7 @@ package org.thingsboard.server.dao.service.validator; import lombok.AllArgsConstructor; import org.springframework.stereotype.Component; import org.thingsboard.server.common.data.Customer; +import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.StringUtils; import org.thingsboard.server.common.data.edge.Edge; import org.thingsboard.server.common.data.id.CustomerId; @@ -40,6 +41,7 @@ public class EdgeDataValidator extends DataValidator { @Override protected void validateCreate(TenantId tenantId, Edge edge) { + validateNumberOfEntitiesPerTenant(tenantId, EntityType.EDGE); } @Override @@ -76,4 +78,5 @@ public class EdgeDataValidator extends DataValidator { } } } + } diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/edge/EdgeRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/edge/EdgeRepository.java index 79c3e93170..1bcfab7ab3 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/edge/EdgeRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/edge/EdgeRepository.java @@ -143,6 +143,9 @@ public interface EdgeRepository extends JpaRepository { @Query("SELECT DISTINCT d.type FROM EdgeEntity d WHERE d.tenantId = :tenantId") List findTenantEdgeTypes(@Param("tenantId") UUID tenantId); + @Query("SELECT count(*) FROM EdgeEntity e WHERE e.tenantId = :tenantId") + Long countByTenantId(@Param("tenantId") UUID tenantId); + EdgeEntity findByTenantIdAndName(UUID tenantId, String name); List findEdgesByTenantIdAndCustomerIdAndIdIn(UUID tenantId, UUID customerId, List edgeIds); diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/edge/JpaEdgeDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/edge/JpaEdgeDao.java index b02a28fee4..2249ced97c 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/edge/JpaEdgeDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/edge/JpaEdgeDao.java @@ -214,6 +214,11 @@ public class JpaEdgeDao extends JpaAbstractDao implements Edge DaoUtil.toPageable(pageLink))); } + @Override + public Long countByTenantId(TenantId tenantId) { + return edgeRepository.countByTenantId(tenantId.getId()); + } + @Override public EntityType getEntityType() { return EntityType.EDGE; diff --git a/dao/src/main/java/org/thingsboard/server/dao/usage/BasicUsageInfoService.java b/dao/src/main/java/org/thingsboard/server/dao/usage/BasicUsageInfoService.java index d9b495337c..c685c94ee3 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/usage/BasicUsageInfoService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/usage/BasicUsageInfoService.java @@ -63,6 +63,8 @@ public class BasicUsageInfoService implements UsageInfoService { usageInfo.setMaxUsers(profileConfiguration.getMaxUsers()); usageInfo.setDashboards(countService.countByTenantIdAndEntityType(tenantId, EntityType.DASHBOARD)); usageInfo.setMaxDashboards(profileConfiguration.getMaxDashboards()); + usageInfo.setEdges(countService.countByTenantIdAndEntityType(tenantId, EntityType.EDGE)); + usageInfo.setMaxEdges(profileConfiguration.getMaxEdges()); usageInfo.setMaxAlarms(profileConfiguration.getMaxCreatedAlarms()); usageInfo.setMaxTransportMessages(profileConfiguration.getMaxTransportMessages()); diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/EdgeServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/EdgeServiceTest.java index 3944aa2ae5..1e88d7b501 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/EdgeServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/EdgeServiceTest.java @@ -17,6 +17,7 @@ package org.thingsboard.server.dao.service; import com.datastax.oss.driver.api.core.uuid.Uuids; import com.fasterxml.jackson.databind.node.ObjectNode; +import org.junit.After; import org.junit.Assert; import org.junit.Test; import org.junit.jupiter.api.Assertions; @@ -26,6 +27,7 @@ import org.thingsboard.server.common.data.Customer; import org.thingsboard.server.common.data.EntitySubtype; import org.thingsboard.server.common.data.StringUtils; import org.thingsboard.server.common.data.Tenant; +import org.thingsboard.server.common.data.TenantProfile; import org.thingsboard.server.common.data.edge.Edge; import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.TenantId; @@ -35,10 +37,13 @@ import org.thingsboard.server.common.data.rule.RuleChain; import org.thingsboard.server.common.data.rule.RuleChainMetaData; import org.thingsboard.server.common.data.rule.RuleChainType; import org.thingsboard.server.common.data.rule.RuleNode; +import org.thingsboard.server.common.data.tenant.profile.DefaultTenantProfileConfiguration; import org.thingsboard.server.dao.customer.CustomerService; import org.thingsboard.server.dao.edge.EdgeService; import org.thingsboard.server.dao.exception.DataValidationException; import org.thingsboard.server.dao.rule.RuleChainService; +import org.thingsboard.server.dao.tenant.TbTenantProfileCache; +import org.thingsboard.server.dao.tenant.TenantProfileService; import java.util.ArrayList; import java.util.Arrays; @@ -51,6 +56,10 @@ import static org.thingsboard.server.dao.model.ModelConstants.NULL_UUID; @DaoSqlTest public class EdgeServiceTest extends AbstractServiceTest { + @Autowired + TbTenantProfileCache tbTenantProfileCache; + @Autowired + TenantProfileService tenantProfileService; @Autowired CustomerService customerService; @Autowired @@ -58,7 +67,13 @@ public class EdgeServiceTest extends AbstractServiceTest { @Autowired RuleChainService ruleChainService; - private IdComparator idComparator = new IdComparator<>(); + private final IdComparator idComparator = new IdComparator<>(); + + @After + public void after() { + tenantService.deleteTenant(tenantId); + tenantProfileService.deleteTenantProfiles(tenantId); + } @Test public void testSaveEdge() { @@ -113,6 +128,34 @@ public class EdgeServiceTest extends AbstractServiceTest { }); } + @Test + public void testSaveEdgesWithInfiniteMaxEdgeLimit() { + TenantProfile defaultTenantProfile = tenantProfileService.findDefaultTenantProfile(tenantId); + defaultTenantProfile.getProfileData().setConfiguration(DefaultTenantProfileConfiguration.builder().maxEdges(Long.MAX_VALUE).build()); + tenantProfileService.saveTenantProfile(tenantId, defaultTenantProfile); + + Edge savedEdge = edgeService.saveEdge(constructEdge("My edge", "default")); + edgeService.deleteEdge(tenantId, savedEdge.getId()); + } + + @Test + public void testSaveEdgesWithMaxEdgeOutOfLimit() { + TenantProfile defaultTenantProfile = tenantProfileService.findDefaultTenantProfile(tenantId); + defaultTenantProfile.getProfileData().setConfiguration(DefaultTenantProfileConfiguration.builder().maxEdges(1).build()); + tenantProfileService.saveTenantProfile(tenantId, defaultTenantProfile); + tbTenantProfileCache.evict(defaultTenantProfile.getId()); + + Assert.assertEquals(0, edgeService.countByTenantId(tenantId)); + + Edge savedEdge = edgeService.saveEdge(constructEdge("My first edge", "default")); + Assert.assertEquals(1, edgeService.countByTenantId(tenantId)); + + Assertions.assertThrows(DataValidationException.class, () -> { + edgeService.saveEdge(constructEdge("My second edge that out of maxEdgeCount limit", "default")); + }); + edgeService.deleteEdge(tenantId, savedEdge.getId()); + } + @Test public void testAssignEdgeToNonExistentCustomer() { Edge edge = constructEdge("My edge", "default"); @@ -668,5 +711,8 @@ public class EdgeServiceTest extends AbstractServiceTest { PageData edgesPageData = edgeService.findEdgesByTenantProfileId(tenant2.getTenantProfileId(), new PageLink(1000)); Assert.assertEquals(2, edgesPageData.getTotalElements()); + tenantService.deleteTenant(tenant1.getId()); + tenantService.deleteTenant(tenant2.getId()); } + } diff --git a/ui-ngx/src/app/modules/home/components/profile/tenant/default-tenant-profile-configuration.component.html b/ui-ngx/src/app/modules/home/components/profile/tenant/default-tenant-profile-configuration.component.html index d511125eec..12a2bcaf7c 100644 --- a/ui-ngx/src/app/modules/home/components/profile/tenant/default-tenant-profile-configuration.component.html +++ b/ui-ngx/src/app/modules/home/components/profile/tenant/default-tenant-profile-configuration.component.html @@ -111,6 +111,22 @@ +
+ + tenant-profile.maximum-edges + + + {{ 'tenant-profile.maximum-edges-required' | translate }} + + + {{ 'tenant-profile.maximum-edges-range' | translate }} + + + +
+
diff --git a/ui-ngx/src/app/modules/home/components/profile/tenant/default-tenant-profile-configuration.component.ts b/ui-ngx/src/app/modules/home/components/profile/tenant/default-tenant-profile-configuration.component.ts index f7261e7957..4d72205108 100644 --- a/ui-ngx/src/app/modules/home/components/profile/tenant/default-tenant-profile-configuration.component.ts +++ b/ui-ngx/src/app/modules/home/components/profile/tenant/default-tenant-profile-configuration.component.ts @@ -65,6 +65,7 @@ export class DefaultTenantProfileConfigurationComponent implements ControlValueA maxUsers: [null, [Validators.required, Validators.min(0)]], maxDashboards: [null, [Validators.required, Validators.min(0)]], maxRuleChains: [null, [Validators.required, Validators.min(0)]], + maxEdges: [null, [Validators.required, Validators.min(0)]], maxResourcesInBytes: [null, [Validators.required, Validators.min(0)]], maxOtaPackagesInBytes: [null, [Validators.required, Validators.min(0)]], maxResourceSize: [null, [Validators.required, Validators.min(0)]], diff --git a/ui-ngx/src/assets/locale/locale.constant-ar_AE.json b/ui-ngx/src/assets/locale/locale.constant-ar_AE.json index 0afd671082..1cf43d72bc 100644 --- a/ui-ngx/src/assets/locale/locale.constant-ar_AE.json +++ b/ui-ngx/src/assets/locale/locale.constant-ar_AE.json @@ -5146,6 +5146,9 @@ "maximum-dashboards": "الحد الأقصى لعدد لوحات التحكم", "maximum-dashboards-required": "الحد الأقصى لعدد لوحات التحكم مطلوب.", "maximum-dashboards-range": "لا يمكن أن يكون الحد الأقصى لعدد لوحات التحكم سالبًا", + "maximum-edges": "الحد الأقصى لعدد الحواف", + "maximum-edges-required": "يجب أن يكون الحد الأقصى لعدد الحواف.", + "maximum-edges-range": "لا يمكن أن يكون الحد الأقصى لعدد الحواف سالبًا", "maximum-rule-chains": "الحد الأقصى لعدد سلاسل القواعد", "maximum-rule-chains-required": "الحد الأقصى لعدد سلاسل القواعد مطلوب.", "maximum-rule-chains-range": "لا يمكن أن يكون الحد الأقصى لعدد سلاسل القواعد سالبًا", diff --git a/ui-ngx/src/assets/locale/locale.constant-ca_ES.json b/ui-ngx/src/assets/locale/locale.constant-ca_ES.json index 9d92babd82..c04c0e12cf 100644 --- a/ui-ngx/src/assets/locale/locale.constant-ca_ES.json +++ b/ui-ngx/src/assets/locale/locale.constant-ca_ES.json @@ -4142,6 +4142,9 @@ "maximum-dashboards": "Nº Màxim de panells (0 - sense límit)", "maximum-dashboards-required": "Cal Nº Màxim de panells.", "maximum-dashboards-range": "Nº Màxim de panells no pot ser negatiu", + "maximum-edges": "Nº Màxim de d'arestes (0 - sense límit)", + "maximum-edges-required": "Cal Nº Màxim de d'arestes.", + "maximum-edges-range": "Nº Màxim de d'arestes no pot ser negatiu", "maximum-rule-chains": "Nº Màxim de cadenes de regles (0 - sense límit)", "maximum-rule-chains-required": "Cal Nº Màxim de cadenes de regles.", "maximum-rule-chains-range": "Nº Màxim de cadenes de regles no pot ser negatiu", diff --git a/ui-ngx/src/assets/locale/locale.constant-cs_CZ.json b/ui-ngx/src/assets/locale/locale.constant-cs_CZ.json index 169dfc4096..67b8b22005 100644 --- a/ui-ngx/src/assets/locale/locale.constant-cs_CZ.json +++ b/ui-ngx/src/assets/locale/locale.constant-cs_CZ.json @@ -2522,6 +2522,9 @@ "maximum-dashboards": "Maximální počet dashboardů (0 - neomezeno)", "maximum-dashboards-required": "Maximální počet dashboardů je povinný.", "maximum-dashboards-range": "Maximální počet dashboardů nemůže být záporný", + "maximum-edges": "Maximální počet hran (0 - neomezeno)", + "maximum-edges-required": "Maximální počet hran je povinný.", + "maximum-edges-range": "Maximální počet hran nemůže být záporný", "maximum-rule-chains": "Maximální počet řetězů pravidel (0 - neomezeno)", "maximum-rule-chains-required": "Maximální počet řetězů pravidel je povinný.", "maximum-rule-chains-range": "Maximální počet řetězů pravidel nemůže být záporný", diff --git a/ui-ngx/src/assets/locale/locale.constant-da_DK.json b/ui-ngx/src/assets/locale/locale.constant-da_DK.json index 53695ddfa1..9d08a72085 100644 --- a/ui-ngx/src/assets/locale/locale.constant-da_DK.json +++ b/ui-ngx/src/assets/locale/locale.constant-da_DK.json @@ -3038,6 +3038,9 @@ "maximum-dashboards": "Maks. antal dashboards (0 – ubegrænset)", "maximum-dashboards-required": "Maks. antal dashboards er påkrævet.", "maximum-dashboards-range": "Maks. antal dashboards kan ikke være negativt", + "maximum-edges": "Maks. antal edges (0 – ubegrænset)", + "maximum-edges-required": "Maks. antal edges er påkrævet.", + "maximum-edges-range": "Maks. antal edges kan ikke være negativt", "maximum-rule-chains": "Maks. antal regelkæder (0 – ubegrænset)", "maximum-rule-chains-required": "Maks. antal regelkæder er påkrævet.", "maximum-rule-chains-range": "Maks. antal regelkæder kan ikke være negativt", 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 bc6874d5ff..153e314e4a 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -4447,6 +4447,9 @@ "maximum-dashboards": "Dashboards maximum number", "maximum-dashboards-required": "Dashboards maximum number is required.", "maximum-dashboards-range": "Dashboards maximum number can't be negative", + "maximum-edges": "Edges maximum number", + "maximum-edges-required": "Edges maximum number is required.", + "maximum-edges-range": "Edges maximum number can't be negative", "maximum-rule-chains": "Rule chains maximum number", "maximum-rule-chains-required": "Rule chains maximum number is required.", "maximum-rule-chains-range": "Rule chains maximum number can't be negative", diff --git a/ui-ngx/src/assets/locale/locale.constant-es_ES.json b/ui-ngx/src/assets/locale/locale.constant-es_ES.json index f653e7179a..0979697471 100644 --- a/ui-ngx/src/assets/locale/locale.constant-es_ES.json +++ b/ui-ngx/src/assets/locale/locale.constant-es_ES.json @@ -3739,6 +3739,9 @@ "maximum-dashboards": "Nº Máximo de paneles (0 - sin límite)", "maximum-dashboards-required": "Nº Máximo de paneles requerido.", "maximum-dashboards-range": "Nº Máximo de paneles no puede ser negativo", + "maximum-edges": "Nº Máximo de bordes (0 - sin límite)", + "maximum-edges-required": "Nº Máximo de bordes requerido.", + "maximum-edges-range": "Nº Máximo de bordes no puede ser negativo", "maximum-rule-chains": "Nº Máximo de cadenas de reglas (0 - sin límite)", "maximum-rule-chains-required": "Nº Máximo de cadenas de reglas requerido.", "maximum-rule-chains-range": "Nº Máximo de cadenas de reglas no puede ser negativo", diff --git a/ui-ngx/src/assets/locale/locale.constant-ko_KR.json b/ui-ngx/src/assets/locale/locale.constant-ko_KR.json index 8d2a1647a4..9235fc9e95 100644 --- a/ui-ngx/src/assets/locale/locale.constant-ko_KR.json +++ b/ui-ngx/src/assets/locale/locale.constant-ko_KR.json @@ -1967,6 +1967,9 @@ "maximum-dashboards": "Maximum number of dashboards (0 - unlimited)", "maximum-dashboards-required": "Maximum number of dashboards is required.", "maximum-dashboards-range": "Maximum number of dashboards can't be negative", + "maximum-edges": "Edges maximum number (0 - unlimited)", + "maximum-edges-required": "Edges maximum number is required.", + "maximum-edges-range": "Edges maximum number can't be negative", "maximum-rule-chains": "Maximum number of rule chains (0 - unlimited)", "maximum-rule-chains-required": "Maximum number of rule chains is required.", "maximum-rule-chains-range": "Maximum number of rule chains can't be negative", diff --git a/ui-ngx/src/assets/locale/locale.constant-lt_LT.json b/ui-ngx/src/assets/locale/locale.constant-lt_LT.json index cb3a96f989..9fd04689c2 100644 --- a/ui-ngx/src/assets/locale/locale.constant-lt_LT.json +++ b/ui-ngx/src/assets/locale/locale.constant-lt_LT.json @@ -5042,6 +5042,9 @@ "maximum-dashboards": "Dashboards maximum number", "maximum-dashboards-required": "Dashboards maximum number is required.", "maximum-dashboards-range": "Dashboards maximum number can't be negative", + "maximum-edges": "Edges maximum number", + "maximum-edges-required": "Edges maximum number is required.", + "maximum-edges-range": "Edges maximum number can't be negative", "maximum-rule-chains": "Rule chains maximum number", "maximum-rule-chains-required": "Rule chains maximum number is required.", "maximum-rule-chains-range": "Rule chains maximum number can't be negative", diff --git a/ui-ngx/src/assets/locale/locale.constant-nl_BE.json b/ui-ngx/src/assets/locale/locale.constant-nl_BE.json index c16c9c5e40..c542f0273e 100644 --- a/ui-ngx/src/assets/locale/locale.constant-nl_BE.json +++ b/ui-ngx/src/assets/locale/locale.constant-nl_BE.json @@ -4841,6 +4841,9 @@ "maximum-dashboards": "Dashboards maximaal aantal", "maximum-dashboards-required": "Het maximale aantal dashboards is vereist.", "maximum-dashboards-range": "Het maximumaantal dashboards mag niet negatief zijn", + "maximum-edges": "Randen maximaal aantal", + "maximum-edges-required": "Het maximale aantal randen is vereist.", + "maximum-edges-range": "Het maximumaantal randen mag niet negatief zijn", "maximum-rule-chains": "Maximaal aantal rule chains", "maximum-rule-chains-required": "Het maximale aantal rule chains is vereist.", "maximum-rule-chains-range": "Het maximale aantal rule chains mag niet negatief zijn", diff --git a/ui-ngx/src/assets/locale/locale.constant-pl_PL.json b/ui-ngx/src/assets/locale/locale.constant-pl_PL.json index ac27313248..a09907560d 100644 --- a/ui-ngx/src/assets/locale/locale.constant-pl_PL.json +++ b/ui-ngx/src/assets/locale/locale.constant-pl_PL.json @@ -5059,6 +5059,9 @@ "maximum-dashboards": "Maksymalna liczba paneli", "maximum-dashboards-required": "Maksymalna liczba paneli jest wymagana.", "maximum-dashboards-range": "Maksymalna liczba paneli nie może być ujemna", + "maximum-edges": "Maksymalna liczba krawędzi", + "maximum-edges-required": "Maksymalna liczba krawędzi jest wymagana.", + "maximum-edges-range": "Maksymalna liczba krawędzi nie może być ujemna", "maximum-rule-chains": "Maksymalna liczba łańcuchów reguł", "maximum-rule-chains-required": "Maksymalna liczba łańcuchów reguł jest wymagana.", "maximum-rule-chains-range": "Maksymalna liczba łańcuchów reguł nie może być ujemna", diff --git a/ui-ngx/src/assets/locale/locale.constant-sl_SI.json b/ui-ngx/src/assets/locale/locale.constant-sl_SI.json index b705358124..ff23223107 100644 --- a/ui-ngx/src/assets/locale/locale.constant-sl_SI.json +++ b/ui-ngx/src/assets/locale/locale.constant-sl_SI.json @@ -1968,6 +1968,9 @@ "maximum-dashboards": "Maximum number of dashboards (0 - unlimited)", "maximum-dashboards-required": "Maximum number of dashboards is required.", "maximum-dashboards-range": "Maximum number of dashboards can't be negative", + "maximum-edges": "Edges maximum number (0 - unlimited)", + "maximum-edges-required": "Edges maximum number is required.", + "maximum-edges-range": "Edges maximum number can't be negative", "maximum-rule-chains": "Maximum number of rule chains (0 - unlimited)", "maximum-rule-chains-required": "Maximum number of rule chains is required.", "maximum-rule-chains-range": "Maximum number of rule chains can't be negative", diff --git a/ui-ngx/src/assets/locale/locale.constant-tr_TR.json b/ui-ngx/src/assets/locale/locale.constant-tr_TR.json index 175d4f1b02..e954e8f2e1 100644 --- a/ui-ngx/src/assets/locale/locale.constant-tr_TR.json +++ b/ui-ngx/src/assets/locale/locale.constant-tr_TR.json @@ -2543,6 +2543,9 @@ "maximum-dashboards": "Maksimum gösterge paneli sayısı (0 - sınırsız)", "maximum-dashboards-required": "Maksimum gösterge paneli sayısı gerekli.", "maximum-dashboards-range": "Maksimum gösterge paneli sayısı negatif olamaz", + "maximum-edges": "Maksimum gösterge kenar sayısı (0 - sınırsız)", + "maximum-edges-required": "Maksimum gösterge kenar sayısı gerekli.", + "maximum-edges-range": "Maksimum gösterge kenar sayısı negatif olamaz", "maximum-rule-chains": "Maksimum kural zinciri sayısı (0 - sınırsız)", "maximum-rule-chains-required": "Maksimum kural zinciri sayısı gerekli.", "maximum-rule-chains-range": "Maksimum kural zinciri sayısı negatif olamaz", diff --git a/ui-ngx/src/assets/locale/locale.constant-zh_CN.json b/ui-ngx/src/assets/locale/locale.constant-zh_CN.json index ac302a78bb..b1ec1e0a75 100644 --- a/ui-ngx/src/assets/locale/locale.constant-zh_CN.json +++ b/ui-ngx/src/assets/locale/locale.constant-zh_CN.json @@ -4234,6 +4234,9 @@ "maximum-dashboards": "最大仪表板数", "maximum-dashboards-required": "最大仪表板数必填。", "maximum-dashboards-range": "最大仪表板数不能为负数", + "maximum-edges": "最大边数", + "maximum-edges-required": "需要最大边数。", + "maximum-edges-range": "边的最大数量不能为负数", "maximum-rule-chains": "最大规则链数", "maximum-rule-chains-required": "最大规则链数必填。", "maximum-rule-chains-range": "最大规则链数不能为负数", diff --git a/ui-ngx/src/assets/locale/locale.constant-zh_TW.json b/ui-ngx/src/assets/locale/locale.constant-zh_TW.json index 9782faf351..a100d95fa4 100644 --- a/ui-ngx/src/assets/locale/locale.constant-zh_TW.json +++ b/ui-ngx/src/assets/locale/locale.constant-zh_TW.json @@ -2972,6 +2972,9 @@ "maximum-dashboards": "儀表板最大數量", "maximum-dashboards-required": "儀表板最大數量必填", "maximum-dashboards-range": "儀表板最大數量不可為否", + "maximum-edges": "最大邊數", + "maximum-edges-required": "需要最大邊數。", + "maximum-edges-range": "邊數最大不能為負數", "maximum-rule-chains": "規則鏈最大數量", "maximum-rule-chains-required": "規則鏈最大數量必填", "maximum-rule-chains-range": "規則鏈最大數量不可為否",