From c653a2b695aee491bb7950d68c76c54b418e83a6 Mon Sep 17 00:00:00 2001 From: Dmytro Skarzhynets Date: Mon, 23 Jun 2025 20:06:39 +0300 Subject: [PATCH] AI rule node: add version control support --- .../main/data/upgrade/basic/schema_update.sql | 4 +- .../controller/AiModelSettingsController.java | 4 +- .../controller/ControllerConstants.java | 2 +- .../entitiy/AbstractTbEntityService.java | 4 +- .../ai/DefaultTbAiModelSettingsService.java | 1 + .../DefaultEntitiesExportImportService.java | 3 +- .../impl/AiModelSettingsExportService.java | 36 +++++++++ .../impl/AiModelSettingsImportService.java | 77 +++++++++++++++++++ .../DefaultEntitiesVersionControlService.java | 7 +- .../vc/EntitiesVersionControlService.java | 4 +- .../common/data/ai/AiModelSettings.java | 26 +++++-- .../server/common/data/sync/JsonTbEntity.java | 7 +- .../server/dao/ai/AiModelSettingsDao.java | 4 +- .../dao/ai/AiModelSettingsServiceImpl.java | 4 +- .../dao/model/sql/AiModelSettingsEntity.java | 5 ++ .../dao/sql/ai/AiModelSettingsRepository.java | 13 +++- ...ngsDao.java => JpaAiModelSettingsDao.java} | 31 +++++++- .../main/resources/sql/schema-entities.sql | 4 +- .../app/shared/models/entity-type.models.ts | 4 +- 19 files changed, 207 insertions(+), 33 deletions(-) create mode 100644 application/src/main/java/org/thingsboard/server/service/sync/ie/exporting/impl/AiModelSettingsExportService.java create mode 100644 application/src/main/java/org/thingsboard/server/service/sync/ie/importing/impl/AiModelSettingsImportService.java rename dao/src/main/java/org/thingsboard/server/dao/sql/ai/{JpaAiSettingsDao.java => JpaAiModelSettingsDao.java} (69%) diff --git a/application/src/main/data/upgrade/basic/schema_update.sql b/application/src/main/data/upgrade/basic/schema_update.sql index f77c8dce67..3aa5a03b11 100644 --- a/application/src/main/data/upgrade/basic/schema_update.sql +++ b/application/src/main/data/upgrade/basic/schema_update.sql @@ -16,10 +16,12 @@ CREATE TABLE ai_model_settings ( id UUID NOT NULL PRIMARY KEY, + external_id UUID, created_time BIGINT NOT NULL, tenant_id UUID NOT NULL, version BIGINT NOT NULL DEFAULT 1, name VARCHAR(255) NOT NULL, configuration JSONB NOT NULL, - CONSTRAINT ai_model_settings_name_unq_key UNIQUE (tenant_id, name) + CONSTRAINT ai_model_settings_name_unq_key UNIQUE (tenant_id, name), + CONSTRAINT ai_model_settings_external_id_unq_key UNIQUE (tenant_id, external_id) ); diff --git a/application/src/main/java/org/thingsboard/server/controller/AiModelSettingsController.java b/application/src/main/java/org/thingsboard/server/controller/AiModelSettingsController.java index 891f6b176c..69c3181e26 100644 --- a/application/src/main/java/org/thingsboard/server/controller/AiModelSettingsController.java +++ b/application/src/main/java/org/thingsboard/server/controller/AiModelSettingsController.java @@ -38,7 +38,7 @@ import java.util.Optional; import java.util.Set; import java.util.UUID; -import static org.thingsboard.server.controller.ControllerConstants.AI_SETTINGS_TEXT_SEARCH_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.AI_MODEL_SETTINGS_TEXT_SEARCH_DESCRIPTION; import static org.thingsboard.server.controller.ControllerConstants.PAGE_DATA_PARAMETERS; import static org.thingsboard.server.controller.ControllerConstants.PAGE_NUMBER_DESCRIPTION; import static org.thingsboard.server.controller.ControllerConstants.PAGE_SIZE_DESCRIPTION; @@ -99,7 +99,7 @@ public class AiModelSettingsController extends BaseController { @RequestParam int pageSize, @Parameter(description = PAGE_NUMBER_DESCRIPTION, required = true) @RequestParam int page, - @Parameter(description = AI_SETTINGS_TEXT_SEARCH_DESCRIPTION) + @Parameter(description = AI_MODEL_SETTINGS_TEXT_SEARCH_DESCRIPTION) @RequestParam(required = false) String textSearch, @Parameter(description = SORT_PROPERTY_DESCRIPTION, schema = @Schema(allowableValues = {"createdTime", "name"})) @RequestParam(required = false) String sortProperty, diff --git a/application/src/main/java/org/thingsboard/server/controller/ControllerConstants.java b/application/src/main/java/org/thingsboard/server/controller/ControllerConstants.java index a46455a47b..20e350f0b8 100644 --- a/application/src/main/java/org/thingsboard/server/controller/ControllerConstants.java +++ b/application/src/main/java/org/thingsboard/server/controller/ControllerConstants.java @@ -90,7 +90,7 @@ public class ControllerConstants { protected static final String TENANT_PROFILE_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'substring' filter based on the tenant profile name."; protected static final String RULE_CHAIN_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'substring' filter based on the rule chain name."; protected static final String DEVICE_PROFILE_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'substring' filter based on the device profile name."; - protected static final String AI_SETTINGS_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'substring' filter based on the AI model settings name, provider and model ID."; + protected static final String AI_MODEL_SETTINGS_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'substring' filter based on the AI model settings name, provider and model ID."; protected static final String ASSET_PROFILE_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'substring' filter based on the asset profile name."; protected static final String CUSTOMER_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'substring' filter based on the customer title."; diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/AbstractTbEntityService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/AbstractTbEntityService.java index 476a4ef5ca..81fd1478b5 100644 --- a/application/src/main/java/org/thingsboard/server/service/entitiy/AbstractTbEntityService.java +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/AbstractTbEntityService.java @@ -97,7 +97,7 @@ public abstract class AbstractTbEntityService { return (I) EntityIdFactory.getByTypeAndUuid(entityType, ModelConstants.NULL_UUID); } - protected ListenableFuture autoCommit(User user, EntityId entityId) throws Exception { + protected ListenableFuture autoCommit(User user, EntityId entityId) { if (vcService != null) { return vcService.autoCommit(user, entityId); } else { @@ -106,7 +106,7 @@ public abstract class AbstractTbEntityService { } } - protected ListenableFuture autoCommit(User user, EntityType entityType, List entityIds) throws Exception { + protected ListenableFuture autoCommit(User user, EntityType entityType, List entityIds) { if (vcService != null) { return vcService.autoCommit(user, entityType, entityIds); } else { diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/ai/DefaultTbAiModelSettingsService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/ai/DefaultTbAiModelSettingsService.java index 5a41d83eed..69f130461c 100644 --- a/application/src/main/java/org/thingsboard/server/service/entitiy/ai/DefaultTbAiModelSettingsService.java +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/ai/DefaultTbAiModelSettingsService.java @@ -44,6 +44,7 @@ class DefaultTbAiModelSettingsService extends AbstractTbEntityService implements AiModelSettings savedSettings; try { savedSettings = aiModelSettingsService.save(settings); + autoCommit(user, savedSettings.getId()); } catch (Exception e) { logEntityActionService.logEntityAction(tenantId, requireNonNullElseGet(settings.getId(), () -> emptyId(EntityType.AI_MODEL_SETTINGS)), settings, actionType, user, e); throw e; diff --git a/application/src/main/java/org/thingsboard/server/service/sync/ie/DefaultEntitiesExportImportService.java b/application/src/main/java/org/thingsboard/server/service/sync/ie/DefaultEntitiesExportImportService.java index db7e37b368..82f855b7c2 100644 --- a/application/src/main/java/org/thingsboard/server/service/sync/ie/DefaultEntitiesExportImportService.java +++ b/application/src/main/java/org/thingsboard/server/service/sync/ie/DefaultEntitiesExportImportService.java @@ -69,7 +69,8 @@ public class DefaultEntitiesExportImportService implements EntitiesExportImportS EntityType.DASHBOARD, EntityType.ASSET_PROFILE, EntityType.ASSET, EntityType.DEVICE_PROFILE, EntityType.DEVICE, EntityType.ENTITY_VIEW, EntityType.WIDGET_TYPE, EntityType.WIDGETS_BUNDLE, - EntityType.NOTIFICATION_TEMPLATE, EntityType.NOTIFICATION_TARGET, EntityType.NOTIFICATION_RULE + EntityType.NOTIFICATION_TEMPLATE, EntityType.NOTIFICATION_TARGET, EntityType.NOTIFICATION_RULE, + EntityType.AI_MODEL_SETTINGS ); @Override diff --git a/application/src/main/java/org/thingsboard/server/service/sync/ie/exporting/impl/AiModelSettingsExportService.java b/application/src/main/java/org/thingsboard/server/service/sync/ie/exporting/impl/AiModelSettingsExportService.java new file mode 100644 index 0000000000..a5ba16e9b1 --- /dev/null +++ b/application/src/main/java/org/thingsboard/server/service/sync/ie/exporting/impl/AiModelSettingsExportService.java @@ -0,0 +1,36 @@ +/** + * 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. + */ +package org.thingsboard.server.service.sync.ie.exporting.impl; + +import org.springframework.stereotype.Service; +import org.thingsboard.server.common.data.EntityType; +import org.thingsboard.server.common.data.ai.AiModelSettings; +import org.thingsboard.server.common.data.id.AiModelSettingsId; +import org.thingsboard.server.common.data.sync.ie.EntityExportData; +import org.thingsboard.server.queue.util.TbCoreComponent; + +import java.util.Set; + +@Service +@TbCoreComponent +class AiModelSettingsExportService extends BaseEntityExportService> { + + @Override + public Set getSupportedEntityTypes() { + return Set.of(EntityType.AI_MODEL_SETTINGS); + } + +} diff --git a/application/src/main/java/org/thingsboard/server/service/sync/ie/importing/impl/AiModelSettingsImportService.java b/application/src/main/java/org/thingsboard/server/service/sync/ie/importing/impl/AiModelSettingsImportService.java new file mode 100644 index 0000000000..e5666e5003 --- /dev/null +++ b/application/src/main/java/org/thingsboard/server/service/sync/ie/importing/impl/AiModelSettingsImportService.java @@ -0,0 +1,77 @@ +/** + * 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. + */ +package org.thingsboard.server.service.sync.ie.importing.impl; + +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.thingsboard.server.common.data.EntityType; +import org.thingsboard.server.common.data.ai.AiModelSettings; +import org.thingsboard.server.common.data.id.AiModelSettingsId; +import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.sync.ie.EntityExportData; +import org.thingsboard.server.dao.ai.AiModelSettingsService; +import org.thingsboard.server.queue.util.TbCoreComponent; +import org.thingsboard.server.service.sync.vc.data.EntitiesImportCtx; + +@Service +@TbCoreComponent +@RequiredArgsConstructor +class AiModelSettingsImportService extends BaseEntityImportService> { + + private final AiModelSettingsService aiModelSettingsService; + + @Override + protected void setOwner( + TenantId tenantId, + AiModelSettings settings, + BaseEntityImportService>.IdProvider idProvider + ) { + settings.setTenantId(tenantId); + } + + @Override + protected AiModelSettings prepare( + EntitiesImportCtx ctx, + AiModelSettings settings, + AiModelSettings oldEntity, + EntityExportData exportData, + BaseEntityImportService>.IdProvider idProvider + ) { + return settings; + } + + @Override + protected AiModelSettings deepCopy(AiModelSettings settings) { + return new AiModelSettings(settings); + } + + @Override + protected AiModelSettings saveOrUpdate( + EntitiesImportCtx ctx, + AiModelSettings settings, + EntityExportData exportData, + BaseEntityImportService>.IdProvider idProvider, + CompareResult compareResult + ) { + return aiModelSettingsService.save(settings); + } + + @Override + public EntityType getEntityType() { + return EntityType.AI_MODEL_SETTINGS; + } + +} 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 420e85dc6c..5fe891c847 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 @@ -114,9 +114,8 @@ public class DefaultEntitiesVersionControlService implements EntitiesVersionCont private final TbTransactionalCache taskCache; private final VersionControlExecutor executor; - @SuppressWarnings("UnstableApiUsage") @Override - public ListenableFuture saveEntitiesVersion(User user, VersionCreateRequest request) throws Exception { + public ListenableFuture saveEntitiesVersion(User user, VersionCreateRequest request) { checkBranchName(request.getBranch()); var pendingCommit = gitServiceQueue.prepareCommit(user, request); DonAsynchron.withCallback(pendingCommit, commit -> { @@ -546,7 +545,7 @@ public class DefaultEntitiesVersionControlService implements EntitiesVersionCont } @Override - public ListenableFuture autoCommit(User user, EntityId entityId) throws Exception { + public ListenableFuture autoCommit(User user, EntityId entityId) { var repositorySettings = repositorySettingsService.get(user.getTenantId()); if (repositorySettings == null || repositorySettings.isReadOnly()) { return Futures.immediateFuture(null); @@ -573,7 +572,7 @@ public class DefaultEntitiesVersionControlService implements EntitiesVersionCont } @Override - public ListenableFuture autoCommit(User user, EntityType entityType, List entityIds) throws Exception { + public ListenableFuture autoCommit(User user, EntityType entityType, List entityIds) { var repositorySettings = repositorySettingsService.get(user.getTenantId()); if (repositorySettings == null || repositorySettings.isReadOnly()) { return Futures.immediateFuture(null); diff --git a/application/src/main/java/org/thingsboard/server/service/sync/vc/EntitiesVersionControlService.java b/application/src/main/java/org/thingsboard/server/service/sync/vc/EntitiesVersionControlService.java index 3f22120d9c..e5ff89ebbd 100644 --- a/application/src/main/java/org/thingsboard/server/service/sync/vc/EntitiesVersionControlService.java +++ b/application/src/main/java/org/thingsboard/server/service/sync/vc/EntitiesVersionControlService.java @@ -69,9 +69,9 @@ public interface EntitiesVersionControlService { ListenableFuture checkVersionControlAccess(TenantId tenantId, RepositorySettings settings) throws Exception; - ListenableFuture autoCommit(User user, EntityId entityId) throws Exception; + ListenableFuture autoCommit(User user, EntityId entityId); - ListenableFuture autoCommit(User user, EntityType entityType, List entityIds) throws Exception; + ListenableFuture autoCommit(User user, EntityType entityType, List entityIds); ListenableFuture getEntityDataInfo(User user, EntityId entityId, String versionId); diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/ai/AiModelSettings.java b/common/data/src/main/java/org/thingsboard/server/common/data/ai/AiModelSettings.java index df1dbe4d7e..750f779e68 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/ai/AiModelSettings.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/ai/AiModelSettings.java @@ -21,7 +21,7 @@ import lombok.Builder; import lombok.Data; import lombok.EqualsAndHashCode; import org.thingsboard.server.common.data.BaseData; -import org.thingsboard.server.common.data.HasName; +import org.thingsboard.server.common.data.ExportableEntity; import org.thingsboard.server.common.data.HasTenantId; import org.thingsboard.server.common.data.HasVersion; import org.thingsboard.server.common.data.ai.model.AiModel; @@ -34,7 +34,7 @@ import java.io.Serial; @Builder @AllArgsConstructor @EqualsAndHashCode(callSuper = true) -public final class AiModelSettings extends BaseData implements HasTenantId, HasVersion, HasName { +public final class AiModelSettings extends BaseData implements HasTenantId, HasVersion, ExportableEntity { @Serial private static final long serialVersionUID = 9017108678716011604L; @@ -45,7 +45,7 @@ public final class AiModelSettings extends BaseData implement description = "JSON object representing the ID of the tenant associated with these AI model settings", example = "e3c4b7d2-5678-4a9b-0c1d-2e3f4a5b6c7d" ) - TenantId tenantId; + private TenantId tenantId; @Schema( requiredMode = Schema.RequiredMode.REQUIRED, @@ -54,22 +54,24 @@ public final class AiModelSettings extends BaseData implement example = "7", defaultValue = "1" ) - Long version; + private Long version; @Schema( requiredMode = Schema.RequiredMode.REQUIRED, accessMode = Schema.AccessMode.READ_WRITE, description = "Human-readable name of the AI model settings; must be unique within the scope of the tenant", - example = "Default AI Settings" + example = "Rule node assistant" ) - String name; + private String name; @Schema( requiredMode = Schema.RequiredMode.NOT_REQUIRED, accessMode = Schema.AccessMode.READ_WRITE, description = "Configuration of the AI model" ) - AiModel configuration; + private AiModel configuration; + + private AiModelSettingsId externalId; public AiModelSettings() {} @@ -77,4 +79,14 @@ public final class AiModelSettings extends BaseData implement super(id); } + public AiModelSettings(AiModelSettings settings) { + super(settings.getId()); + createdTime = settings.getCreatedTime(); + tenantId = settings.getTenantId(); + version = settings.getVersion(); + name = settings.getName(); + configuration = settings.getConfiguration(); + externalId = settings.getExternalId() == null ? null : new AiModelSettingsId(settings.getExternalId().getId()); + } + } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/sync/JsonTbEntity.java b/common/data/src/main/java/org/thingsboard/server/common/data/sync/JsonTbEntity.java index c763daeb7f..6914b75636 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/sync/JsonTbEntity.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/sync/JsonTbEntity.java @@ -26,6 +26,7 @@ import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.DeviceProfile; import org.thingsboard.server.common.data.EntityView; import org.thingsboard.server.common.data.TbResource; +import org.thingsboard.server.common.data.ai.AiModelSettings; import org.thingsboard.server.common.data.asset.Asset; import org.thingsboard.server.common.data.asset.AssetProfile; import org.thingsboard.server.common.data.notification.rule.NotificationRule; @@ -58,8 +59,8 @@ import java.lang.annotation.Target; @Type(name = "NOTIFICATION_TEMPLATE", value = NotificationTemplate.class), @Type(name = "NOTIFICATION_TARGET", value = NotificationTarget.class), @Type(name = "NOTIFICATION_RULE", value = NotificationRule.class), - @Type(name = "TB_RESOURCE", value = TbResource.class) + @Type(name = "TB_RESOURCE", value = TbResource.class), + @Type(name = "AI_MODEL_SETTINGS", value = AiModelSettings.class) }) @JsonIgnoreProperties(value = {"tenantId", "createdTime", "version"}, ignoreUnknown = true) -public @interface JsonTbEntity { -} +public @interface JsonTbEntity {} diff --git a/dao/src/main/java/org/thingsboard/server/dao/ai/AiModelSettingsDao.java b/dao/src/main/java/org/thingsboard/server/dao/ai/AiModelSettingsDao.java index ae47af0db2..5ee0d49121 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/ai/AiModelSettingsDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/ai/AiModelSettingsDao.java @@ -18,12 +18,12 @@ package org.thingsboard.server.dao.ai; import org.thingsboard.server.common.data.ai.AiModelSettings; import org.thingsboard.server.common.data.id.AiModelSettingsId; import org.thingsboard.server.common.data.id.TenantId; -import org.thingsboard.server.dao.Dao; +import org.thingsboard.server.dao.ExportableEntityDao; import org.thingsboard.server.dao.TenantEntityDao; import java.util.Optional; -public interface AiModelSettingsDao extends Dao, TenantEntityDao { +public interface AiModelSettingsDao extends TenantEntityDao, ExportableEntityDao { Optional findByTenantIdAndId(TenantId tenantId, AiModelSettingsId settingsId); diff --git a/dao/src/main/java/org/thingsboard/server/dao/ai/AiModelSettingsServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/ai/AiModelSettingsServiceImpl.java index 2fa47bf60f..3875169305 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/ai/AiModelSettingsServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/ai/AiModelSettingsServiceImpl.java @@ -65,7 +65,9 @@ class AiModelSettingsServiceImpl extends CachedVersionedEntityService @Column(name = ModelConstants.AI_MODEL_SETTINGS_CONFIGURATION_COLUMN_NAME, nullable = false, columnDefinition = "JSONB") private AiModel configuration; + @Column(name = ModelConstants.EXTERNAL_ID_PROPERTY, columnDefinition = "UUID") + private UUID externalId; + public AiModelSettingsEntity() {} public AiModelSettingsEntity(AiModelSettings aiModelSettings) { @@ -63,6 +66,7 @@ public class AiModelSettingsEntity extends BaseVersionedEntity tenantId = getTenantUuid(aiModelSettings.getTenantId()); name = aiModelSettings.getName(); configuration = aiModelSettings.getConfiguration(); + externalId = getUuid(aiModelSettings.getExternalId()); } @Override @@ -73,6 +77,7 @@ public class AiModelSettingsEntity extends BaseVersionedEntity settings.setTenantId(TenantId.fromUUID(tenantId)); settings.setName(name); settings.setConfiguration(configuration); + settings.setExternalId(getEntityId(externalId, AiModelSettingsId::new)); return settings; } diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/ai/AiModelSettingsRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/ai/AiModelSettingsRepository.java index b645db8d66..e5909c5818 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/ai/AiModelSettingsRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/ai/AiModelSettingsRepository.java @@ -22,13 +22,18 @@ import org.springframework.data.jpa.repository.Modifying; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; import org.springframework.transaction.annotation.Transactional; +import org.thingsboard.server.dao.ExportableEntityRepository; import org.thingsboard.server.dao.model.sql.AiModelSettingsEntity; import java.util.Optional; import java.util.Set; import java.util.UUID; -interface AiModelSettingsRepository extends JpaRepository { +interface AiModelSettingsRepository extends JpaRepository, ExportableEntityRepository { + + Optional findByTenantIdAndId(UUID tenantId, UUID id); + + Optional findByTenantIdAndName(UUID tenantId, String name); @Query(nativeQuery = true, value = """ SELECT * @@ -41,7 +46,11 @@ interface AiModelSettingsRepository extends JpaRepository findByTenantId(@Param("tenantId") UUID tenantId, @Param("textSearch") String textSearch, Pageable pageable); - Optional findByTenantIdAndId(UUID tenantId, UUID id); + @Query("SELECT ai_model.id FROM AiModelSettingsEntity ai_model WHERE ai_model.tenantId = :tenantId") + Page findIdsByTenantId(@Param("tenantId") UUID tenantId, Pageable pageable); + + @Query("SELECT externalId FROM AiModelSettingsEntity WHERE id = :id") + Optional getExternalIdById(@Param("id") UUID id); long countByTenantId(UUID tenantId); diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/ai/JpaAiSettingsDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/ai/JpaAiModelSettingsDao.java similarity index 69% rename from dao/src/main/java/org/thingsboard/server/dao/sql/ai/JpaAiSettingsDao.java rename to dao/src/main/java/org/thingsboard/server/dao/sql/ai/JpaAiModelSettingsDao.java index e5d7df2ee9..e7b87b0a1a 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/ai/JpaAiSettingsDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/ai/JpaAiModelSettingsDao.java @@ -38,7 +38,7 @@ import java.util.UUID; @SqlDao @Component @RequiredArgsConstructor -class JpaAiSettingsDao extends JpaAbstractDao implements AiModelSettingsDao { +class JpaAiModelSettingsDao extends JpaAbstractDao implements AiModelSettingsDao { private final AiModelSettingsRepository aiModelSettingsRepository; @@ -47,13 +47,40 @@ class JpaAiSettingsDao extends JpaAbstractDao findAllByTenantId(TenantId tenantId, PageLink pageLink) { + return findByTenantId(tenantId.getId(), pageLink); + } + + @Override + public PageData findByTenantId(UUID tenantId, PageLink pageLink) { return DaoUtil.toPageData(aiModelSettingsRepository.findByTenantId( - tenantId.getId(), StringUtils.defaultIfEmpty(pageLink.getTextSearch(), null), DaoUtil.toPageable(pageLink, AiModelSettingsEntity.COLUMN_MAP)) + tenantId, StringUtils.defaultIfEmpty(pageLink.getTextSearch(), null), DaoUtil.toPageable(pageLink, AiModelSettingsEntity.COLUMN_MAP)) + ); + } + + @Override + public PageData findIdsByTenantId(UUID tenantId, PageLink pageLink) { + return DaoUtil.pageToPageData( + aiModelSettingsRepository.findIdsByTenantId(tenantId, DaoUtil.toPageable(pageLink, AiModelSettingsEntity.COLUMN_MAP)).map(AiModelSettingsId::new) ); } + @Override + public AiModelSettingsId getExternalIdByInternal(AiModelSettingsId internalId) { + return aiModelSettingsRepository.getExternalIdById(internalId.getId()).map(AiModelSettingsId::new).orElse(null); + } + @Override public Long countByTenantId(TenantId tenantId) { return aiModelSettingsRepository.countByTenantId(tenantId.getId()); diff --git a/dao/src/main/resources/sql/schema-entities.sql b/dao/src/main/resources/sql/schema-entities.sql index cf2b64175e..82d3aea66b 100644 --- a/dao/src/main/resources/sql/schema-entities.sql +++ b/dao/src/main/resources/sql/schema-entities.sql @@ -951,10 +951,12 @@ CREATE TABLE IF NOT EXISTS cf_debug_event ( CREATE TABLE IF NOT EXISTS ai_model_settings ( id UUID NOT NULL PRIMARY KEY, + external_id UUID, created_time BIGINT NOT NULL, tenant_id UUID NOT NULL, version BIGINT NOT NULL DEFAULT 1, name VARCHAR(255) NOT NULL, configuration JSONB NOT NULL, - CONSTRAINT ai_model_settings_name_unq_key UNIQUE (tenant_id, name) + CONSTRAINT ai_model_settings_name_unq_key UNIQUE (tenant_id, name), + CONSTRAINT ai_model_settings_external_id_unq_key UNIQUE (tenant_id, external_id) ); diff --git a/ui-ngx/src/app/shared/models/entity-type.models.ts b/ui-ngx/src/app/shared/models/entity-type.models.ts index 3f70ad4b7c..02bae1576f 100644 --- a/ui-ngx/src/app/shared/models/entity-type.models.ts +++ b/ui-ngx/src/app/shared/models/entity-type.models.ts @@ -51,7 +51,7 @@ export enum EntityType { MOBILE_APP_BUNDLE = 'MOBILE_APP_BUNDLE', MOBILE_APP = 'MOBILE_APP', CALCULATED_FIELD = 'CALCULATED_FIELD', - AI_SETTINGS = 'AI_SETTINGS', + AI_MODEL_SETTINGS = 'AI_MODEL_SETTINGS', } export enum AliasEntityType { @@ -494,7 +494,7 @@ export const entityTypeTranslations = new Map