Merge branch 'rc' of github.com:thingsboard/thingsboard into master-rc
This commit is contained in:
		
						commit
						e79eec56cb
					
				@ -114,9 +114,6 @@ public class AppActor extends ContextAwareActor {
 | 
				
			|||||||
                ctx.broadcastToChildrenByType(msg, EntityType.TENANT);
 | 
					                ctx.broadcastToChildrenByType(msg, EntityType.TENANT);
 | 
				
			||||||
                break;
 | 
					                break;
 | 
				
			||||||
            case CF_CACHE_INIT_MSG:
 | 
					            case CF_CACHE_INIT_MSG:
 | 
				
			||||||
            case CF_INIT_PROFILE_ENTITY_MSG:
 | 
					 | 
				
			||||||
            case CF_INIT_MSG:
 | 
					 | 
				
			||||||
            case CF_LINK_INIT_MSG:
 | 
					 | 
				
			||||||
            case CF_STATE_RESTORE_MSG:
 | 
					            case CF_STATE_RESTORE_MSG:
 | 
				
			||||||
                //TODO: use priority from the message body. For example, messages about CF lifecycle are important and Device lifecycle are not.
 | 
					                //TODO: use priority from the message body. For example, messages about CF lifecycle are important and Device lifecycle are not.
 | 
				
			||||||
                //      same for the Linked telemetry.
 | 
					                //      same for the Linked telemetry.
 | 
				
			||||||
 | 
				
			|||||||
@ -24,9 +24,6 @@ import org.thingsboard.server.common.msg.TbActorStopReason;
 | 
				
			|||||||
import org.thingsboard.server.common.msg.ToCalculatedFieldSystemMsg;
 | 
					import org.thingsboard.server.common.msg.ToCalculatedFieldSystemMsg;
 | 
				
			||||||
import org.thingsboard.server.common.msg.cf.CalculatedFieldCacheInitMsg;
 | 
					import org.thingsboard.server.common.msg.cf.CalculatedFieldCacheInitMsg;
 | 
				
			||||||
import org.thingsboard.server.common.msg.cf.CalculatedFieldEntityLifecycleMsg;
 | 
					import org.thingsboard.server.common.msg.cf.CalculatedFieldEntityLifecycleMsg;
 | 
				
			||||||
import org.thingsboard.server.common.msg.cf.CalculatedFieldInitMsg;
 | 
					 | 
				
			||||||
import org.thingsboard.server.common.msg.cf.CalculatedFieldInitProfileEntityMsg;
 | 
					 | 
				
			||||||
import org.thingsboard.server.common.msg.cf.CalculatedFieldLinkInitMsg;
 | 
					 | 
				
			||||||
import org.thingsboard.server.common.msg.cf.CalculatedFieldPartitionChangeMsg;
 | 
					import org.thingsboard.server.common.msg.cf.CalculatedFieldPartitionChangeMsg;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
@ -70,15 +67,6 @@ public class CalculatedFieldManagerActor extends AbstractCalculatedFieldActor {
 | 
				
			|||||||
            case CF_CACHE_INIT_MSG:
 | 
					            case CF_CACHE_INIT_MSG:
 | 
				
			||||||
                processor.onCacheInitMsg((CalculatedFieldCacheInitMsg) msg);
 | 
					                processor.onCacheInitMsg((CalculatedFieldCacheInitMsg) msg);
 | 
				
			||||||
                break;
 | 
					                break;
 | 
				
			||||||
            case CF_INIT_PROFILE_ENTITY_MSG:
 | 
					 | 
				
			||||||
                processor.onProfileEntityMsg((CalculatedFieldInitProfileEntityMsg) msg);
 | 
					 | 
				
			||||||
                break;
 | 
					 | 
				
			||||||
            case CF_INIT_MSG:
 | 
					 | 
				
			||||||
                processor.onFieldInitMsg((CalculatedFieldInitMsg) msg);
 | 
					 | 
				
			||||||
                break;
 | 
					 | 
				
			||||||
            case CF_LINK_INIT_MSG:
 | 
					 | 
				
			||||||
                processor.onLinkInitMsg((CalculatedFieldLinkInitMsg) msg);
 | 
					 | 
				
			||||||
                break;
 | 
					 | 
				
			||||||
            case CF_STATE_RESTORE_MSG:
 | 
					            case CF_STATE_RESTORE_MSG:
 | 
				
			||||||
                processor.onStateRestoreMsg((CalculatedFieldStateRestoreMsg) msg);
 | 
					                processor.onStateRestoreMsg((CalculatedFieldStateRestoreMsg) msg);
 | 
				
			||||||
                break;
 | 
					                break;
 | 
				
			||||||
 | 
				
			|||||||
@ -35,9 +35,6 @@ import org.thingsboard.server.common.data.id.TenantId;
 | 
				
			|||||||
import org.thingsboard.server.common.data.page.PageDataIterable;
 | 
					import org.thingsboard.server.common.data.page.PageDataIterable;
 | 
				
			||||||
import org.thingsboard.server.common.msg.cf.CalculatedFieldCacheInitMsg;
 | 
					import org.thingsboard.server.common.msg.cf.CalculatedFieldCacheInitMsg;
 | 
				
			||||||
import org.thingsboard.server.common.msg.cf.CalculatedFieldEntityLifecycleMsg;
 | 
					import org.thingsboard.server.common.msg.cf.CalculatedFieldEntityLifecycleMsg;
 | 
				
			||||||
import org.thingsboard.server.common.msg.cf.CalculatedFieldInitMsg;
 | 
					 | 
				
			||||||
import org.thingsboard.server.common.msg.cf.CalculatedFieldInitProfileEntityMsg;
 | 
					 | 
				
			||||||
import org.thingsboard.server.common.msg.cf.CalculatedFieldLinkInitMsg;
 | 
					 | 
				
			||||||
import org.thingsboard.server.common.msg.cf.CalculatedFieldPartitionChangeMsg;
 | 
					import org.thingsboard.server.common.msg.cf.CalculatedFieldPartitionChangeMsg;
 | 
				
			||||||
import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg;
 | 
					import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg;
 | 
				
			||||||
import org.thingsboard.server.common.msg.queue.ServiceType;
 | 
					import org.thingsboard.server.common.msg.queue.ServiceType;
 | 
				
			||||||
@ -120,37 +117,6 @@ public class CalculatedFieldManagerMessageProcessor extends AbstractContextAware
 | 
				
			|||||||
        msg.getCallback().onSuccess();
 | 
					        msg.getCallback().onSuccess();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public void onProfileEntityMsg(CalculatedFieldInitProfileEntityMsg msg) {
 | 
					 | 
				
			||||||
        log.debug("[{}] Processing profile entity message.", msg.getTenantId().getId());
 | 
					 | 
				
			||||||
        entityProfileCache.add(msg.getProfileEntityId(), msg.getEntityId());
 | 
					 | 
				
			||||||
        msg.getCallback().onSuccess();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public void onFieldInitMsg(CalculatedFieldInitMsg msg) throws CalculatedFieldException {
 | 
					 | 
				
			||||||
        log.debug("[{}] Processing CF init message.", msg.getCf().getId());
 | 
					 | 
				
			||||||
        var cf = msg.getCf();
 | 
					 | 
				
			||||||
        var cfCtx = new CalculatedFieldCtx(cf, systemContext.getTbelInvokeService(), systemContext.getApiLimitService());
 | 
					 | 
				
			||||||
        try {
 | 
					 | 
				
			||||||
            cfCtx.init();
 | 
					 | 
				
			||||||
        } catch (Exception e) {
 | 
					 | 
				
			||||||
            throw CalculatedFieldException.builder().ctx(cfCtx).eventEntity(cf.getEntityId()).cause(e).errorMessage("Failed to initialize CF context").build();
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        calculatedFields.put(cf.getId(), cfCtx);
 | 
					 | 
				
			||||||
        // We use copy on write lists to safely pass the reference to another actor for the iteration.
 | 
					 | 
				
			||||||
        // Alternative approach would be to use any list but avoid modifications to the list (change the complete map value instead)
 | 
					 | 
				
			||||||
        entityIdCalculatedFields.computeIfAbsent(cf.getEntityId(), id -> new CopyOnWriteArrayList<>()).add(cfCtx);
 | 
					 | 
				
			||||||
        msg.getCallback().onSuccess();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public void onLinkInitMsg(CalculatedFieldLinkInitMsg msg) {
 | 
					 | 
				
			||||||
        log.debug("[{}] Processing CF link init message for entity [{}].", msg.getLink().getCalculatedFieldId(), msg.getLink().getEntityId());
 | 
					 | 
				
			||||||
        var link = msg.getLink();
 | 
					 | 
				
			||||||
        // We use copy on write lists to safely pass the reference to another actor for the iteration.
 | 
					 | 
				
			||||||
        // Alternative approach would be to use any list but avoid modifications to the list (change the complete map value instead)
 | 
					 | 
				
			||||||
        entityIdCalculatedFieldLinks.computeIfAbsent(link.getEntityId(), id -> new CopyOnWriteArrayList<>()).add(link);
 | 
					 | 
				
			||||||
        msg.getCallback().onSuccess();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public void onStateRestoreMsg(CalculatedFieldStateRestoreMsg msg) {
 | 
					    public void onStateRestoreMsg(CalculatedFieldStateRestoreMsg msg) {
 | 
				
			||||||
        var cfId = msg.getId().cfId();
 | 
					        var cfId = msg.getId().cfId();
 | 
				
			||||||
        var calculatedField = calculatedFields.get(cfId);
 | 
					        var calculatedField = calculatedFields.get(cfId);
 | 
				
			||||||
@ -566,20 +532,37 @@ public class CalculatedFieldManagerMessageProcessor extends AbstractContextAware
 | 
				
			|||||||
        cfs.forEach(cf -> {
 | 
					        cfs.forEach(cf -> {
 | 
				
			||||||
            log.trace("Processing calculated field record: {}", cf);
 | 
					            log.trace("Processing calculated field record: {}", cf);
 | 
				
			||||||
            try {
 | 
					            try {
 | 
				
			||||||
                onFieldInitMsg(new CalculatedFieldInitMsg(cf.getTenantId(), cf));
 | 
					                initCalculatedField(cf);
 | 
				
			||||||
            } catch (CalculatedFieldException e) {
 | 
					            } catch (CalculatedFieldException e) {
 | 
				
			||||||
                log.error("Failed to process calculated field record: {}", cf, e);
 | 
					                log.error("Failed to process calculated field record: {}", cf, e);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
        calculatedFields.values().forEach(cf -> {
 | 
					 | 
				
			||||||
            entityIdCalculatedFields.computeIfAbsent(cf.getEntityId(), id -> new CopyOnWriteArrayList<>()).add(cf);
 | 
					 | 
				
			||||||
        });
 | 
					 | 
				
			||||||
        PageDataIterable<CalculatedFieldLink> cfls = new PageDataIterable<>(pageLink -> cfDaoService.findAllCalculatedFieldLinksByTenantId(tenantId, pageLink), cfSettings.getInitTenantFetchPackSize());
 | 
					        PageDataIterable<CalculatedFieldLink> cfls = new PageDataIterable<>(pageLink -> cfDaoService.findAllCalculatedFieldLinksByTenantId(tenantId, pageLink), cfSettings.getInitTenantFetchPackSize());
 | 
				
			||||||
        cfls.forEach(link -> {
 | 
					        cfls.forEach(link -> {
 | 
				
			||||||
            onLinkInitMsg(new CalculatedFieldLinkInitMsg(link.getTenantId(), link));
 | 
					            log.trace("Processing calculated field link record: {}", link);
 | 
				
			||||||
 | 
					            initCalculatedFieldLink(link);
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private void initCalculatedField(CalculatedField cf) throws CalculatedFieldException {
 | 
				
			||||||
 | 
					        var cfCtx = new CalculatedFieldCtx(cf, systemContext.getTbelInvokeService(), systemContext.getApiLimitService());
 | 
				
			||||||
 | 
					        try {
 | 
				
			||||||
 | 
					            cfCtx.init();
 | 
				
			||||||
 | 
					        } catch (Exception e) {
 | 
				
			||||||
 | 
					            throw CalculatedFieldException.builder().ctx(cfCtx).eventEntity(cf.getEntityId()).cause(e).errorMessage("Failed to initialize CF context").build();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        calculatedFields.put(cf.getId(), cfCtx);
 | 
				
			||||||
 | 
					        // We use copy on write lists to safely pass the reference to another actor for the iteration.
 | 
				
			||||||
 | 
					        // Alternative approach would be to use any list but avoid modifications to the list (change the complete map value instead)
 | 
				
			||||||
 | 
					        entityIdCalculatedFields.computeIfAbsent(cf.getEntityId(), id -> new CopyOnWriteArrayList<>()).add(cfCtx);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private void initCalculatedFieldLink(CalculatedFieldLink link) {
 | 
				
			||||||
 | 
					        // We use copy on write lists to safely pass the reference to another actor for the iteration.
 | 
				
			||||||
 | 
					        // Alternative approach would be to use any list but avoid modifications to the list (change the complete map value instead)
 | 
				
			||||||
 | 
					        entityIdCalculatedFieldLinks.computeIfAbsent(link.getEntityId(), id -> new CopyOnWriteArrayList<>()).add(link);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private void initEntityProfileCache() {
 | 
					    private void initEntityProfileCache() {
 | 
				
			||||||
        PageDataIterable<ProfileEntityIdInfo> deviceIdInfos = new PageDataIterable<>(pageLink -> deviceService.findProfileEntityIdInfosByTenantId(tenantId, pageLink), cfSettings.getInitTenantFetchPackSize());
 | 
					        PageDataIterable<ProfileEntityIdInfo> deviceIdInfos = new PageDataIterable<>(pageLink -> deviceService.findProfileEntityIdInfosByTenantId(tenantId, pageLink), cfSettings.getInitTenantFetchPackSize());
 | 
				
			||||||
        for (ProfileEntityIdInfo idInfo : deviceIdInfos) {
 | 
					        for (ProfileEntityIdInfo idInfo : deviceIdInfos) {
 | 
				
			||||||
 | 
				
			|||||||
@ -180,9 +180,6 @@ public class TenantActor extends RuleChainManagerActor {
 | 
				
			|||||||
                onRuleChainMsg((RuleChainAwareMsg) msg);
 | 
					                onRuleChainMsg((RuleChainAwareMsg) msg);
 | 
				
			||||||
                break;
 | 
					                break;
 | 
				
			||||||
            case CF_CACHE_INIT_MSG:
 | 
					            case CF_CACHE_INIT_MSG:
 | 
				
			||||||
            case CF_INIT_PROFILE_ENTITY_MSG:
 | 
					 | 
				
			||||||
            case CF_INIT_MSG:
 | 
					 | 
				
			||||||
            case CF_LINK_INIT_MSG:
 | 
					 | 
				
			||||||
            case CF_STATE_RESTORE_MSG:
 | 
					            case CF_STATE_RESTORE_MSG:
 | 
				
			||||||
            case CF_PARTITIONS_CHANGE_MSG:
 | 
					            case CF_PARTITIONS_CHANGE_MSG:
 | 
				
			||||||
                onToCalculatedFieldSystemActorMsg((ToCalculatedFieldSystemMsg) msg, true);
 | 
					                onToCalculatedFieldSystemActorMsg((ToCalculatedFieldSystemMsg) msg, true);
 | 
				
			||||||
 | 
				
			|||||||
@ -19,11 +19,9 @@ import lombok.Getter;
 | 
				
			|||||||
import lombok.RequiredArgsConstructor;
 | 
					import lombok.RequiredArgsConstructor;
 | 
				
			||||||
import lombok.extern.slf4j.Slf4j;
 | 
					import lombok.extern.slf4j.Slf4j;
 | 
				
			||||||
import org.springframework.beans.factory.annotation.Value;
 | 
					import org.springframework.beans.factory.annotation.Value;
 | 
				
			||||||
import org.springframework.context.annotation.Lazy;
 | 
					 | 
				
			||||||
import org.springframework.stereotype.Service;
 | 
					import org.springframework.stereotype.Service;
 | 
				
			||||||
import org.springframework.util.ConcurrentReferenceHashMap;
 | 
					import org.springframework.util.ConcurrentReferenceHashMap;
 | 
				
			||||||
import org.thingsboard.script.api.tbel.TbelInvokeService;
 | 
					import org.thingsboard.script.api.tbel.TbelInvokeService;
 | 
				
			||||||
import org.thingsboard.server.actors.ActorSystemContext;
 | 
					 | 
				
			||||||
import org.thingsboard.server.common.data.cf.CalculatedField;
 | 
					import org.thingsboard.server.common.data.cf.CalculatedField;
 | 
				
			||||||
import org.thingsboard.server.common.data.cf.CalculatedFieldLink;
 | 
					import org.thingsboard.server.common.data.cf.CalculatedFieldLink;
 | 
				
			||||||
import org.thingsboard.server.common.data.cf.configuration.CalculatedFieldConfiguration;
 | 
					import org.thingsboard.server.common.data.cf.configuration.CalculatedFieldConfiguration;
 | 
				
			||||||
@ -31,8 +29,6 @@ import org.thingsboard.server.common.data.id.CalculatedFieldId;
 | 
				
			|||||||
import org.thingsboard.server.common.data.id.EntityId;
 | 
					import org.thingsboard.server.common.data.id.EntityId;
 | 
				
			||||||
import org.thingsboard.server.common.data.id.TenantId;
 | 
					import org.thingsboard.server.common.data.id.TenantId;
 | 
				
			||||||
import org.thingsboard.server.common.data.page.PageDataIterable;
 | 
					import org.thingsboard.server.common.data.page.PageDataIterable;
 | 
				
			||||||
import org.thingsboard.server.common.msg.cf.CalculatedFieldInitMsg;
 | 
					 | 
				
			||||||
import org.thingsboard.server.common.msg.cf.CalculatedFieldLinkInitMsg;
 | 
					 | 
				
			||||||
import org.thingsboard.server.dao.cf.CalculatedFieldService;
 | 
					import org.thingsboard.server.dao.cf.CalculatedFieldService;
 | 
				
			||||||
import org.thingsboard.server.dao.usagerecord.ApiLimitService;
 | 
					import org.thingsboard.server.dao.usagerecord.ApiLimitService;
 | 
				
			||||||
import org.thingsboard.server.queue.util.AfterStartUp;
 | 
					import org.thingsboard.server.queue.util.AfterStartUp;
 | 
				
			||||||
@ -56,8 +52,6 @@ public class DefaultCalculatedFieldCache implements CalculatedFieldCache {
 | 
				
			|||||||
    private final CalculatedFieldService calculatedFieldService;
 | 
					    private final CalculatedFieldService calculatedFieldService;
 | 
				
			||||||
    private final TbelInvokeService tbelInvokeService;
 | 
					    private final TbelInvokeService tbelInvokeService;
 | 
				
			||||||
    private final ApiLimitService apiLimitService;
 | 
					    private final ApiLimitService apiLimitService;
 | 
				
			||||||
    @Lazy
 | 
					 | 
				
			||||||
    private final ActorSystemContext actorSystemContext;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private final ConcurrentMap<CalculatedFieldId, CalculatedField> calculatedFields = new ConcurrentHashMap<>();
 | 
					    private final ConcurrentMap<CalculatedFieldId, CalculatedField> calculatedFields = new ConcurrentHashMap<>();
 | 
				
			||||||
    private final ConcurrentMap<EntityId, List<CalculatedField>> entityIdCalculatedFields = new ConcurrentHashMap<>();
 | 
					    private final ConcurrentMap<EntityId, List<CalculatedField>> entityIdCalculatedFields = new ConcurrentHashMap<>();
 | 
				
			||||||
@ -75,7 +69,6 @@ public class DefaultCalculatedFieldCache implements CalculatedFieldCache {
 | 
				
			|||||||
        cfs.forEach(cf -> {
 | 
					        cfs.forEach(cf -> {
 | 
				
			||||||
            if (cf != null) {
 | 
					            if (cf != null) {
 | 
				
			||||||
                calculatedFields.putIfAbsent(cf.getId(), cf);
 | 
					                calculatedFields.putIfAbsent(cf.getId(), cf);
 | 
				
			||||||
                actorSystemContext.tell(new CalculatedFieldInitMsg(cf.getTenantId(), cf));
 | 
					 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
        calculatedFields.values().forEach(cf -> {
 | 
					        calculatedFields.values().forEach(cf -> {
 | 
				
			||||||
@ -84,7 +77,6 @@ public class DefaultCalculatedFieldCache implements CalculatedFieldCache {
 | 
				
			|||||||
        PageDataIterable<CalculatedFieldLink> cfls = new PageDataIterable<>(calculatedFieldService::findAllCalculatedFieldLinks, initFetchPackSize);
 | 
					        PageDataIterable<CalculatedFieldLink> cfls = new PageDataIterable<>(calculatedFieldService::findAllCalculatedFieldLinks, initFetchPackSize);
 | 
				
			||||||
        cfls.forEach(link -> {
 | 
					        cfls.forEach(link -> {
 | 
				
			||||||
            calculatedFieldLinks.computeIfAbsent(link.getCalculatedFieldId(), id -> new CopyOnWriteArrayList<>()).add(link);
 | 
					            calculatedFieldLinks.computeIfAbsent(link.getCalculatedFieldId(), id -> new CopyOnWriteArrayList<>()).add(link);
 | 
				
			||||||
            actorSystemContext.tell(new CalculatedFieldLinkInitMsg(link.getTenantId(), link));
 | 
					 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
        calculatedFieldLinks.values().stream()
 | 
					        calculatedFieldLinks.values().stream()
 | 
				
			||||||
                .flatMap(List::stream)
 | 
					                .flatMap(List::stream)
 | 
				
			||||||
 | 
				
			|||||||
@ -953,7 +953,7 @@ public class EntityQueryControllerTest extends AbstractControllerTest {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        EntityCountQuery countQuery = new EntityCountQuery(entityTypeFilter);
 | 
					        EntityCountQuery countQuery = new EntityCountQuery(entityTypeFilter, keyFilters);
 | 
				
			||||||
        countByQueryAndCheck(countQuery, 97);
 | 
					        countByQueryAndCheck(countQuery, 97);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -137,9 +137,6 @@ public enum MsgType {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    CF_CACHE_INIT_MSG, // Sent to init caches for CF actor;
 | 
					    CF_CACHE_INIT_MSG, // Sent to init caches for CF actor;
 | 
				
			||||||
    CF_INIT_PROFILE_ENTITY_MSG, // Sent to init profile entities cache;
 | 
					 | 
				
			||||||
    CF_INIT_MSG, // Sent to init particular calculated field;
 | 
					 | 
				
			||||||
    CF_LINK_INIT_MSG, // Sent to init particular calculated field;
 | 
					 | 
				
			||||||
    CF_STATE_RESTORE_MSG, // Sent to restore particular calculated field entity state;
 | 
					    CF_STATE_RESTORE_MSG, // Sent to restore particular calculated field entity state;
 | 
				
			||||||
    CF_PARTITIONS_CHANGE_MSG, // Sent when cluster event occures;
 | 
					    CF_PARTITIONS_CHANGE_MSG, // Sent when cluster event occures;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -1,34 +0,0 @@
 | 
				
			|||||||
/**
 | 
					 | 
				
			||||||
 * 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.common.msg.cf;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import lombok.Data;
 | 
					 | 
				
			||||||
import org.thingsboard.server.common.data.cf.CalculatedField;
 | 
					 | 
				
			||||||
import org.thingsboard.server.common.data.id.TenantId;
 | 
					 | 
				
			||||||
import org.thingsboard.server.common.msg.MsgType;
 | 
					 | 
				
			||||||
import org.thingsboard.server.common.msg.ToCalculatedFieldSystemMsg;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
@Data
 | 
					 | 
				
			||||||
public class CalculatedFieldInitMsg implements ToCalculatedFieldSystemMsg {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    private final TenantId tenantId;
 | 
					 | 
				
			||||||
    private final CalculatedField cf;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    @Override
 | 
					 | 
				
			||||||
    public MsgType getMsgType() {
 | 
					 | 
				
			||||||
        return MsgType.CF_INIT_MSG;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@ -1,36 +0,0 @@
 | 
				
			|||||||
/**
 | 
					 | 
				
			||||||
 * 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.common.msg.cf;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import lombok.Data;
 | 
					 | 
				
			||||||
import org.thingsboard.server.common.data.id.EntityId;
 | 
					 | 
				
			||||||
import org.thingsboard.server.common.data.id.TenantId;
 | 
					 | 
				
			||||||
import org.thingsboard.server.common.msg.MsgType;
 | 
					 | 
				
			||||||
import org.thingsboard.server.common.msg.ToCalculatedFieldSystemMsg;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
@Data
 | 
					 | 
				
			||||||
public class CalculatedFieldInitProfileEntityMsg implements ToCalculatedFieldSystemMsg {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    private final TenantId tenantId;
 | 
					 | 
				
			||||||
    private final EntityId profileEntityId;
 | 
					 | 
				
			||||||
    private final EntityId entityId;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    @Override
 | 
					 | 
				
			||||||
    public MsgType getMsgType() {
 | 
					 | 
				
			||||||
        return MsgType.CF_INIT_PROFILE_ENTITY_MSG;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@ -1,34 +0,0 @@
 | 
				
			|||||||
/**
 | 
					 | 
				
			||||||
 * 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.common.msg.cf;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import lombok.Data;
 | 
					 | 
				
			||||||
import org.thingsboard.server.common.data.cf.CalculatedFieldLink;
 | 
					 | 
				
			||||||
import org.thingsboard.server.common.data.id.TenantId;
 | 
					 | 
				
			||||||
import org.thingsboard.server.common.msg.MsgType;
 | 
					 | 
				
			||||||
import org.thingsboard.server.common.msg.ToCalculatedFieldSystemMsg;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
@Data
 | 
					 | 
				
			||||||
public class CalculatedFieldLinkInitMsg implements ToCalculatedFieldSystemMsg {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    private final TenantId tenantId;
 | 
					 | 
				
			||||||
    private final CalculatedFieldLink link;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    @Override
 | 
					 | 
				
			||||||
    public MsgType getMsgType() {
 | 
					 | 
				
			||||||
        return MsgType.CF_LINK_INIT_MSG;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@ -31,7 +31,7 @@ import java.util.concurrent.TimeUnit;
 | 
				
			|||||||
public class AbstractRedisClusterContainer {
 | 
					public class AbstractRedisClusterContainer {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    static final String NODES = "127.0.0.1:6371,127.0.0.1:6372,127.0.0.1:6373,127.0.0.1:6374,127.0.0.1:6375,127.0.0.1:6376";
 | 
					    static final String NODES = "127.0.0.1:6371,127.0.0.1:6372,127.0.0.1:6373,127.0.0.1:6374,127.0.0.1:6375,127.0.0.1:6376";
 | 
				
			||||||
    static final String IMAGE = "bitnami/valkey-cluster:8.0";
 | 
					    static final String IMAGE = "bitnamilegacy/valkey-cluster:8.0";
 | 
				
			||||||
    static final Map<String,String> ENVS = Map.of(
 | 
					    static final Map<String,String> ENVS = Map.of(
 | 
				
			||||||
            "VALKEY_CLUSTER_ANNOUNCE_IP", "127.0.0.1",
 | 
					            "VALKEY_CLUSTER_ANNOUNCE_IP", "127.0.0.1",
 | 
				
			||||||
            "VALKEY_CLUSTER_DYNAMIC_IPS", "no",
 | 
					            "VALKEY_CLUSTER_DYNAMIC_IPS", "no",
 | 
				
			||||||
 | 
				
			|||||||
@ -27,7 +27,7 @@ import java.util.List;
 | 
				
			|||||||
public class AbstractRedisContainer {
 | 
					public class AbstractRedisContainer {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @ClassRule(order = 0)
 | 
					    @ClassRule(order = 0)
 | 
				
			||||||
    public static GenericContainer redis = new GenericContainer("bitnami/valkey:8.0")
 | 
					    public static GenericContainer redis = new GenericContainer("bitnamilegacy/valkey:8.0")
 | 
				
			||||||
            .withEnv("ALLOW_EMPTY_PASSWORD","yes")
 | 
					            .withEnv("ALLOW_EMPTY_PASSWORD","yes")
 | 
				
			||||||
            .withLogConsumer(s -> log.warn(((OutputFrame) s).getUtf8String().trim()))
 | 
					            .withLogConsumer(s -> log.warn(((OutputFrame) s).getUtf8String().trim()))
 | 
				
			||||||
            .withExposedPorts(6379);
 | 
					            .withExposedPorts(6379);
 | 
				
			||||||
 | 
				
			|||||||
@ -33,7 +33,7 @@ import static org.assertj.core.api.Assertions.assertThat;
 | 
				
			|||||||
public class RedisJUnit5Test {
 | 
					public class RedisJUnit5Test {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @Container
 | 
					    @Container
 | 
				
			||||||
    private static final GenericContainer REDIS = new GenericContainer("bitnami/valkey:8.0")
 | 
					    private static final GenericContainer REDIS = new GenericContainer("bitnamilegacy/valkey:8.0")
 | 
				
			||||||
            .withEnv("ALLOW_EMPTY_PASSWORD","yes")
 | 
					            .withEnv("ALLOW_EMPTY_PASSWORD","yes")
 | 
				
			||||||
            .withLogConsumer(s -> log.error(((OutputFrame) s).getUtf8String().trim()))
 | 
					            .withLogConsumer(s -> log.error(((OutputFrame) s).getUtf8String().trim()))
 | 
				
			||||||
            .withExposedPorts(6379);
 | 
					            .withExposedPorts(6379);
 | 
				
			||||||
 | 
				
			|||||||
@ -17,7 +17,7 @@
 | 
				
			|||||||
services:
 | 
					services:
 | 
				
			||||||
  kafka:
 | 
					  kafka:
 | 
				
			||||||
    restart: always
 | 
					    restart: always
 | 
				
			||||||
    image: "bitnami/kafka:4.0"
 | 
					    image: "bitnamilegacy/kafka:4.0"
 | 
				
			||||||
    ports:
 | 
					    ports:
 | 
				
			||||||
      - "9092:9092"
 | 
					      - "9092:9092"
 | 
				
			||||||
    env_file:
 | 
					    env_file:
 | 
				
			||||||
 | 
				
			|||||||
@ -18,7 +18,7 @@ services:
 | 
				
			|||||||
# Valkey cluster
 | 
					# Valkey cluster
 | 
				
			||||||
# The latest version of Valkey compatible with ThingsBoard is 8.0
 | 
					# The latest version of Valkey compatible with ThingsBoard is 8.0
 | 
				
			||||||
  valkey-node-0:
 | 
					  valkey-node-0:
 | 
				
			||||||
    image: bitnami/valkey-cluster:8.0
 | 
					    image: bitnamilegacy/valkey-cluster:8.0
 | 
				
			||||||
    volumes:
 | 
					    volumes:
 | 
				
			||||||
      - ./tb-node/valkey-cluster-data-0:/bitnami/valkey/data
 | 
					      - ./tb-node/valkey-cluster-data-0:/bitnami/valkey/data
 | 
				
			||||||
    environment:
 | 
					    environment:
 | 
				
			||||||
@ -26,7 +26,7 @@ services:
 | 
				
			|||||||
      - 'VALKEY_NODES=valkey-node-0 valkey-node-1 valkey-node-2 valkey-node-3 valkey-node-4 valkey-node-5'
 | 
					      - 'VALKEY_NODES=valkey-node-0 valkey-node-1 valkey-node-2 valkey-node-3 valkey-node-4 valkey-node-5'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  valkey-node-1:
 | 
					  valkey-node-1:
 | 
				
			||||||
    image: bitnami/valkey-cluster:8.0
 | 
					    image: bitnamilegacy/valkey-cluster:8.0
 | 
				
			||||||
    volumes:
 | 
					    volumes:
 | 
				
			||||||
      - ./tb-node/valkey-cluster-data-1:/bitnami/valkey/data
 | 
					      - ./tb-node/valkey-cluster-data-1:/bitnami/valkey/data
 | 
				
			||||||
    depends_on:
 | 
					    depends_on:
 | 
				
			||||||
@ -36,7 +36,7 @@ services:
 | 
				
			|||||||
      - 'VALKEY_NODES=valkey-node-0 valkey-node-1 valkey-node-2 valkey-node-3 valkey-node-4 valkey-node-5'
 | 
					      - 'VALKEY_NODES=valkey-node-0 valkey-node-1 valkey-node-2 valkey-node-3 valkey-node-4 valkey-node-5'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  valkey-node-2:
 | 
					  valkey-node-2:
 | 
				
			||||||
    image: bitnami/valkey-cluster:8.0
 | 
					    image: bitnamilegacy/valkey-cluster:8.0
 | 
				
			||||||
    volumes:
 | 
					    volumes:
 | 
				
			||||||
      - ./tb-node/valkey-cluster-data-2:/bitnami/valkey/data
 | 
					      - ./tb-node/valkey-cluster-data-2:/bitnami/valkey/data
 | 
				
			||||||
    depends_on:
 | 
					    depends_on:
 | 
				
			||||||
@ -46,7 +46,7 @@ services:
 | 
				
			|||||||
      - 'VALKEY_NODES=valkey-node-0 valkey-node-1 valkey-node-2 valkey-node-3 valkey-node-4 valkey-node-5'
 | 
					      - 'VALKEY_NODES=valkey-node-0 valkey-node-1 valkey-node-2 valkey-node-3 valkey-node-4 valkey-node-5'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  valkey-node-3:
 | 
					  valkey-node-3:
 | 
				
			||||||
    image: bitnami/valkey-cluster:8.0
 | 
					    image: bitnamilegacy/valkey-cluster:8.0
 | 
				
			||||||
    volumes:
 | 
					    volumes:
 | 
				
			||||||
      - ./tb-node/valkey-cluster-data-3:/bitnami/valkey/data
 | 
					      - ./tb-node/valkey-cluster-data-3:/bitnami/valkey/data
 | 
				
			||||||
    depends_on:
 | 
					    depends_on:
 | 
				
			||||||
@ -56,7 +56,7 @@ services:
 | 
				
			|||||||
      - 'VALKEY_NODES=valkey-node-0 valkey-node-1 valkey-node-2 valkey-node-3 valkey-node-4 valkey-node-5'
 | 
					      - 'VALKEY_NODES=valkey-node-0 valkey-node-1 valkey-node-2 valkey-node-3 valkey-node-4 valkey-node-5'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  valkey-node-4:
 | 
					  valkey-node-4:
 | 
				
			||||||
    image: bitnami/valkey-cluster:8.0
 | 
					    image: bitnamilegacy/valkey-cluster:8.0
 | 
				
			||||||
    volumes:
 | 
					    volumes:
 | 
				
			||||||
      - ./tb-node/valkey-cluster-data-4:/bitnami/valkey/data
 | 
					      - ./tb-node/valkey-cluster-data-4:/bitnami/valkey/data
 | 
				
			||||||
    depends_on:
 | 
					    depends_on:
 | 
				
			||||||
@ -66,7 +66,7 @@ services:
 | 
				
			|||||||
      - 'VALKEY_NODES=valkey-node-0 valkey-node-1 valkey-node-2 valkey-node-3 valkey-node-4 valkey-node-5'
 | 
					      - 'VALKEY_NODES=valkey-node-0 valkey-node-1 valkey-node-2 valkey-node-3 valkey-node-4 valkey-node-5'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  valkey-node-5:
 | 
					  valkey-node-5:
 | 
				
			||||||
    image: bitnami/valkey-cluster:8.0
 | 
					    image: bitnamilegacy/valkey-cluster:8.0
 | 
				
			||||||
    volumes:
 | 
					    volumes:
 | 
				
			||||||
      - ./tb-node/valkey-cluster-data-5:/bitnami/valkey/data
 | 
					      - ./tb-node/valkey-cluster-data-5:/bitnami/valkey/data
 | 
				
			||||||
    depends_on:
 | 
					    depends_on:
 | 
				
			||||||
 | 
				
			|||||||
@ -18,7 +18,7 @@ services:
 | 
				
			|||||||
  # Valkey sentinel
 | 
					  # Valkey sentinel
 | 
				
			||||||
  # The latest version of Valkey compatible with ThingsBoard is 8.0
 | 
					  # The latest version of Valkey compatible with ThingsBoard is 8.0
 | 
				
			||||||
  valkey-primary:
 | 
					  valkey-primary:
 | 
				
			||||||
    image: 'bitnami/valkey:8.0'
 | 
					    image: 'bitnamilegacy/valkey:8.0'
 | 
				
			||||||
    volumes:
 | 
					    volumes:
 | 
				
			||||||
      - ./tb-node/valkey-sentinel-data-primary:/bitnami/valkey/data
 | 
					      - ./tb-node/valkey-sentinel-data-primary:/bitnami/valkey/data
 | 
				
			||||||
    environment:
 | 
					    environment:
 | 
				
			||||||
@ -26,7 +26,7 @@ services:
 | 
				
			|||||||
      - 'VALKEY_PASSWORD=thingsboard'
 | 
					      - 'VALKEY_PASSWORD=thingsboard'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  valkey-replica:
 | 
					  valkey-replica:
 | 
				
			||||||
    image: 'bitnami/valkey:8.0'
 | 
					    image: 'bitnamilegacy/valkey:8.0'
 | 
				
			||||||
    volumes:
 | 
					    volumes:
 | 
				
			||||||
      - ./tb-node/valkey-sentinel-data-replica:/bitnami/valkey/data
 | 
					      - ./tb-node/valkey-sentinel-data-replica:/bitnami/valkey/data
 | 
				
			||||||
    environment:
 | 
					    environment:
 | 
				
			||||||
@ -38,7 +38,7 @@ services:
 | 
				
			|||||||
      - valkey-primary
 | 
					      - valkey-primary
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  valkey-sentinel:
 | 
					  valkey-sentinel:
 | 
				
			||||||
    image: 'bitnami/valkey-sentinel:8.0'
 | 
					    image: 'bitnamilegacy/valkey-sentinel:8.0'
 | 
				
			||||||
    volumes:
 | 
					    volumes:
 | 
				
			||||||
      - ./tb-node/valkey-sentinel-data-sentinel:/bitnami/valkey/data
 | 
					      - ./tb-node/valkey-sentinel-data-sentinel:/bitnami/valkey/data
 | 
				
			||||||
    environment:
 | 
					    environment:
 | 
				
			||||||
 | 
				
			|||||||
@ -19,7 +19,7 @@ services:
 | 
				
			|||||||
# The latest version of Valkey compatible with ThingsBoard is 8.0
 | 
					# The latest version of Valkey compatible with ThingsBoard is 8.0
 | 
				
			||||||
  valkey:
 | 
					  valkey:
 | 
				
			||||||
    restart: always
 | 
					    restart: always
 | 
				
			||||||
    image: bitnami/valkey:8.0
 | 
					    image: bitnamilegacy/valkey:8.0
 | 
				
			||||||
    environment:
 | 
					    environment:
 | 
				
			||||||
      # ALLOW_EMPTY_PASSWORD is recommended only for development.
 | 
					      # ALLOW_EMPTY_PASSWORD is recommended only for development.
 | 
				
			||||||
      ALLOW_EMPTY_PASSWORD: "yes"
 | 
					      ALLOW_EMPTY_PASSWORD: "yes"
 | 
				
			||||||
 | 
				
			|||||||
@ -19,7 +19,7 @@ services:
 | 
				
			|||||||
# The latest version of Valkey compatible with ThingsBoard is 8.0
 | 
					# The latest version of Valkey compatible with ThingsBoard is 8.0
 | 
				
			||||||
  valkey:
 | 
					  valkey:
 | 
				
			||||||
    restart: always
 | 
					    restart: always
 | 
				
			||||||
    image: bitnami/valkey:8.0
 | 
					    image: bitnamilegacy/valkey:8.0
 | 
				
			||||||
    environment:
 | 
					    environment:
 | 
				
			||||||
      # ALLOW_EMPTY_PASSWORD is recommended only for development.
 | 
					      # ALLOW_EMPTY_PASSWORD is recommended only for development.
 | 
				
			||||||
      - 'ALLOW_EMPTY_PASSWORD=yes'
 | 
					      - 'ALLOW_EMPTY_PASSWORD=yes'
 | 
				
			||||||
 | 
				
			|||||||
@ -79,6 +79,9 @@ export class AiConfigComponent extends RuleNodeConfigurationComponent {
 | 
				
			|||||||
    if (!this.aiConfigForm.get('systemPrompt').value) {
 | 
					    if (!this.aiConfigForm.get('systemPrompt').value) {
 | 
				
			||||||
      delete config.systemPrompt;
 | 
					      delete config.systemPrompt;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    if (this.aiConfigForm.get('responseFormat.type').value !== ResponseFormat.JSON_SCHEMA) {
 | 
				
			||||||
 | 
					      delete config.responseFormat.schema;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    return deepTrim(config);
 | 
					    return deepTrim(config);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -88,10 +91,10 @@ export class AiConfigComponent extends RuleNodeConfigurationComponent {
 | 
				
			|||||||
        if (this.aiConfigForm.get('responseFormat.type').value !== ResponseFormat.TEXT) {
 | 
					        if (this.aiConfigForm.get('responseFormat.type').value !== ResponseFormat.TEXT) {
 | 
				
			||||||
          this.aiConfigForm.get('responseFormat.type').patchValue(ResponseFormat.TEXT, {emitEvent: true});
 | 
					          this.aiConfigForm.get('responseFormat.type').patchValue(ResponseFormat.TEXT, {emitEvent: true});
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        this.aiConfigForm.get('responseFormat.type').disable();
 | 
					        this.aiConfigForm.get('responseFormat.type').disable({emitEvent: false});
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
      this.aiConfigForm.get('responseFormat.type').enable();
 | 
					      this.aiConfigForm.get('responseFormat.type').enable({emitEvent: false});
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user