diff --git a/application/pom.xml b/application/pom.xml index 112cc82ff7..d97f6d92e3 100644 --- a/application/pom.xml +++ b/application/pom.xml @@ -390,6 +390,10 @@ + + io.github.git-commit-id + git-commit-id-maven-plugin + org.apache.maven.plugins maven-compiler-plugin diff --git a/application/src/main/data/upgrade/basic/schema_update.sql b/application/src/main/data/upgrade/basic/schema_update.sql index 9aec87af00..ebe63a6b3a 100644 --- a/application/src/main/data/upgrade/basic/schema_update.sql +++ b/application/src/main/data/upgrade/basic/schema_update.sql @@ -193,6 +193,17 @@ $$ END; $$; +-- update constraint name +DO +$$ + BEGIN + ALTER TABLE domain DROP CONSTRAINT IF EXISTS domain_unq_key; + IF NOT EXISTS(SELECT 1 FROM pg_constraint WHERE conname = 'domain_name_key') THEN + ALTER TABLE domain ADD CONSTRAINT domain_name_key UNIQUE (name); + END IF; + END; +$$; + -- UPDATE RESOURCE JS_MODULE SUB TYPE START UPDATE resource SET resource_sub_type = 'EXTENSION' WHERE resource_type = 'JS_MODULE' AND resource_sub_type IS NULL; diff --git a/application/src/main/java/org/thingsboard/server/controller/AssetProfileController.java b/application/src/main/java/org/thingsboard/server/controller/AssetProfileController.java index 4b40cf3854..dfcbc59ca6 100644 --- a/application/src/main/java/org/thingsboard/server/controller/AssetProfileController.java +++ b/application/src/main/java/org/thingsboard/server/controller/AssetProfileController.java @@ -88,7 +88,7 @@ public class AssetProfileController extends BaseController { AssetProfileId assetProfileId = new AssetProfileId(toUUID(strAssetProfileId)); var result = checkAssetProfileId(assetProfileId, Operation.READ); if (inlineImages) { - imageService.inlineImage(result); + result = imageService.inlineImage(result); } return result; } diff --git a/application/src/main/java/org/thingsboard/server/controller/BaseController.java b/application/src/main/java/org/thingsboard/server/controller/BaseController.java index 2d868a1135..dbe430ba18 100644 --- a/application/src/main/java/org/thingsboard/server/controller/BaseController.java +++ b/application/src/main/java/org/thingsboard/server/controller/BaseController.java @@ -923,6 +923,7 @@ public abstract class BaseController { UserCredentials userCredentials = userService.findUserCredentialsByUserId(user.getTenantId(), user.getId()); info.put("userCredentialsEnabled", userCredentials.isEnabled()); + info.put("userActivated", userCredentials.getActivateToken() == null); info.put("lastLoginTs", userCredentials.getLastLoginTs()); } diff --git a/application/src/main/java/org/thingsboard/server/controller/DeviceProfileController.java b/application/src/main/java/org/thingsboard/server/controller/DeviceProfileController.java index e7915fc22c..43916e56bf 100644 --- a/application/src/main/java/org/thingsboard/server/controller/DeviceProfileController.java +++ b/application/src/main/java/org/thingsboard/server/controller/DeviceProfileController.java @@ -96,7 +96,7 @@ public class DeviceProfileController extends BaseController { DeviceProfileId deviceProfileId = new DeviceProfileId(toUUID(strDeviceProfileId)); var result = checkDeviceProfileId(deviceProfileId, Operation.READ); if (inlineImages) { - imageService.inlineImage(result); + result = imageService.inlineImage(result); } return result; } diff --git a/application/src/main/java/org/thingsboard/server/controller/WidgetsBundleController.java b/application/src/main/java/org/thingsboard/server/controller/WidgetsBundleController.java index 8d39e6c83d..307343f6fb 100644 --- a/application/src/main/java/org/thingsboard/server/controller/WidgetsBundleController.java +++ b/application/src/main/java/org/thingsboard/server/controller/WidgetsBundleController.java @@ -90,7 +90,7 @@ public class WidgetsBundleController extends BaseController { WidgetsBundleId widgetsBundleId = new WidgetsBundleId(toUUID(strWidgetsBundleId)); var result = checkWidgetsBundleId(widgetsBundleId, Operation.READ); if (inlineImages) { - imageService.inlineImage(result); + result = imageService.inlineImage(result); } return result; } diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeGrpcSession.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeGrpcSession.java index 42a6a60c2d..7c37b0ac54 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeGrpcSession.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeGrpcSession.java @@ -135,7 +135,7 @@ public abstract class EdgeGrpcSession implements Closeable { private StreamObserver inputStream; private StreamObserver outputStream; - private boolean connected; + private volatile boolean connected; private volatile boolean syncCompleted; private EdgeVersion edgeVersion; @@ -536,13 +536,15 @@ public abstract class EdgeGrpcSession implements Closeable { public void processHighPriorityEvents() { try { - List highPriorityEvents = new ArrayList<>(); - EdgeEvent event; - while ((event = highPriorityQueue.poll()) != null) { - highPriorityEvents.add(event); + if (isConnected() && isSyncCompleted()) { + List highPriorityEvents = new ArrayList<>(); + EdgeEvent event; + while ((event = highPriorityQueue.poll()) != null) { + highPriorityEvents.add(event); + } + List downlinkMsgsPack = convertToDownlinkMsgsPack(highPriorityEvents); + sendDownlinkMsgsPack(downlinkMsgsPack).get(); } - List downlinkMsgsPack = convertToDownlinkMsgsPack(highPriorityEvents); - sendDownlinkMsgsPack(downlinkMsgsPack).get(); } catch (Exception e) { log.error("[{}] Failed to process high priority events", sessionId, e); } diff --git a/application/src/main/java/org/thingsboard/server/service/notification/rule/DefaultNotificationRuleProcessor.java b/application/src/main/java/org/thingsboard/server/service/notification/rule/DefaultNotificationRuleProcessor.java index dd31642aac..5bcc4f88d2 100644 --- a/application/src/main/java/org/thingsboard/server/service/notification/rule/DefaultNotificationRuleProcessor.java +++ b/application/src/main/java/org/thingsboard/server/service/notification/rule/DefaultNotificationRuleProcessor.java @@ -54,7 +54,6 @@ import java.util.EnumMap; import java.util.List; import java.util.Map; import java.util.UUID; -import java.util.stream.Collectors; @Service @RequiredArgsConstructor @@ -106,22 +105,11 @@ public class DefaultNotificationRuleProcessor implements NotificationRuleProcess log.debug("Processing notification rule '{}' for trigger type {}", rule.getName(), rule.getTriggerType()); if (matchesClearRule(trigger, triggerConfig)) { - List notificationRequests = findAlreadySentNotificationRequests(rule, trigger); - if (notificationRequests.isEmpty()) { - return; - } - - List targets = notificationRequests.stream() - .filter(NotificationRequest::isSent) - .flatMap(notificationRequest -> notificationRequest.getTargets().stream()) - .distinct().collect(Collectors.toList()); - NotificationInfo notificationInfo = constructNotificationInfo(trigger, triggerConfig); - submitNotificationRequest(targets, rule, trigger.getOriginatorEntityId(), notificationInfo, 0); - - notificationRequests.forEach(notificationRequest -> { - if (notificationRequest.isScheduled()) { - notificationCenter.deleteNotificationRequest(rule.getTenantId(), notificationRequest.getId()); - } + List scheduledRequests = notificationRequestService.findNotificationRequestsByRuleIdAndOriginatorEntityIdAndStatus( + rule.getTenantId(), rule.getId(), trigger.getOriginatorEntityId(), NotificationRequestStatus.SCHEDULED + ); + scheduledRequests.forEach(notificationRequest -> { + notificationCenter.deleteNotificationRequest(rule.getTenantId(), notificationRequest.getId()); }); return; } @@ -139,10 +127,6 @@ public class DefaultNotificationRuleProcessor implements NotificationRuleProcess } } - private List findAlreadySentNotificationRequests(NotificationRule rule, NotificationRuleTrigger trigger) { - return notificationRequestService.findNotificationRequestsByRuleIdAndOriginatorEntityId(rule.getTenantId(), rule.getId(), trigger.getOriginatorEntityId()); - } - private void submitNotificationRequest(List targets, NotificationRule rule, EntityId originatorEntityId, NotificationInfo notificationInfo, int delayInSec) { NotificationRequestConfig config = new NotificationRequestConfig(); diff --git a/application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/AlarmTriggerProcessor.java b/application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/AlarmTriggerProcessor.java index b9047cac6b..a51d6689a7 100644 --- a/application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/AlarmTriggerProcessor.java +++ b/application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/AlarmTriggerProcessor.java @@ -46,10 +46,10 @@ public class AlarmTriggerProcessor implements NotificationRuleTriggerProcessor ctx, I entityId) throws ThingsboardException { diff --git a/application/src/main/java/org/thingsboard/server/service/sync/ie/exporting/impl/DeviceProfileExportService.java b/application/src/main/java/org/thingsboard/server/service/sync/ie/exporting/impl/DeviceProfileExportService.java index 60aaf34a3a..69389e7d57 100644 --- a/application/src/main/java/org/thingsboard/server/service/sync/ie/exporting/impl/DeviceProfileExportService.java +++ b/application/src/main/java/org/thingsboard/server/service/sync/ie/exporting/impl/DeviceProfileExportService.java @@ -34,7 +34,6 @@ public class DeviceProfileExportService extends BaseEntityExportService fqns = widgetTypeService.findWidgetFqnsByWidgetsBundleId(ctx.getTenantId(), widgetsBundle.getId()); exportData.setFqns(fqns); diff --git a/application/src/main/resources/thingsboard.yml b/application/src/main/resources/thingsboard.yml index 1fa09cd9bb..32fd62670d 100644 --- a/application/src/main/resources/thingsboard.yml +++ b/application/src/main/resources/thingsboard.yml @@ -1446,11 +1446,11 @@ edges: # Max number of high priority edge events per edge session. No persistence - stored in memory max_high_priority_queue_size_per_session: "${EDGES_MAX_HIGH_PRIORITY_QUEUE_SIZE_PER_SESSION:10000}" # Number of threads that are used to check DB for edge events - scheduler_pool_size: "${EDGES_SCHEDULER_POOL_SIZE:1}" + scheduler_pool_size: "${EDGES_SCHEDULER_POOL_SIZE:4}" # Number of threads that are used to send downlink messages to edge over gRPC - send_scheduler_pool_size: "${EDGES_SEND_SCHEDULER_POOL_SIZE:1}" + send_scheduler_pool_size: "${EDGES_SEND_SCHEDULER_POOL_SIZE:4}" # Number of threads that are used to convert edge events from DB into downlink messages and send them for delivery - grpc_callback_thread_pool_size: "${EDGES_GRPC_CALLBACK_POOL_SIZE:1}" + grpc_callback_thread_pool_size: "${EDGES_GRPC_CALLBACK_POOL_SIZE:4}" state: # Persist state of edge (active, last connect, last disconnect) into timeseries or attributes tables. 'false' means to store edge state into attributes table persistToTelemetry: "${EDGES_PERSIST_STATE_TO_TELEMETRY:false}" diff --git a/application/src/test/java/org/thingsboard/server/controller/AuthControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/AuthControllerTest.java index 73182587fb..dac48a1c06 100644 --- a/application/src/test/java/org/thingsboard/server/controller/AuthControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/AuthControllerTest.java @@ -83,6 +83,7 @@ public class AuthControllerTest extends AbstractControllerTest { assertThat(user.getEmail()).isEqualTo(CUSTOMER_USER_EMAIL); user = getUser(customerUserId); assertThat(user.getAdditionalInfo().get("userCredentialsEnabled").asBoolean()).isTrue(); + assertThat(user.getAdditionalInfo().get("userActivated").asBoolean()).isTrue(); assertThat(user.getAdditionalInfo().get("lastLoginTs").asLong()).isCloseTo(System.currentTimeMillis(), within(10000L)); } @@ -243,6 +244,7 @@ public class AuthControllerTest extends AbstractControllerTest { user.setAuthority(Authority.TENANT_ADMIN); user.setEmail("tenant-admin-2@thingsboard.org"); user = doPost("/api/user", user, User.class); + assertThat(getUser(user.getId()).getAdditionalInfo().get("userActivated").asBoolean()).isFalse(); UserCredentials userCredentials = userCredentialsDao.findByUserId(tenantId, user.getUuidId()); assertThat(userCredentials.getActivateTokenExpTime()).isCloseTo(System.currentTimeMillis() + TimeUnit.HOURS.toMillis(ttl), Offset.offset(120000L)); @@ -289,6 +291,7 @@ public class AuthControllerTest extends AbstractControllerTest { doPost("/api/noauth/activate", JacksonUtil.newObjectNode() .put("activateToken", newActivationToken) .put("password", "wefewe")).andExpect(status().isOk()); + assertThat(getUser(user.getId()).getAdditionalInfo().get("userActivated").asBoolean()).isTrue(); } @Test diff --git a/application/src/test/java/org/thingsboard/server/controller/ImageControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/ImageControllerTest.java index f6cc64fda8..d54810a394 100644 --- a/application/src/test/java/org/thingsboard/server/controller/ImageControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/ImageControllerTest.java @@ -24,6 +24,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpMethod; import org.springframework.test.context.TestPropertySource; import org.thingsboard.common.util.JacksonUtil; +import org.thingsboard.server.common.data.DeviceProfile; import org.thingsboard.server.common.data.ImageDescriptor; import org.thingsboard.server.common.data.ResourceExportData; import org.thingsboard.server.common.data.ResourceSubType; @@ -321,6 +322,24 @@ public class ImageControllerTest extends AbstractControllerTest { assertThat(systemParams.getMaxResourceSize()).isEqualTo(0); } + @Test + public void testInlineImages() throws Exception { + TbResourceInfo imageInfo = uploadImage(HttpMethod.POST, "/api/image", "my_png_image.png", "image/png", PNG_IMAGE); + DeviceProfile deviceProfile = createDeviceProfile("Test"); + deviceProfile.setImage("tb-image;" + imageInfo.getLink()); + deviceProfile = doPost("/api/deviceProfile", deviceProfile, DeviceProfile.class); + + DeviceProfile deviceProfileInlined = doGet("/api/deviceProfile/" + deviceProfile.getUuidId() + "?inlineImages=true", DeviceProfile.class); + assertThat(deviceProfileInlined.getImage()).isEqualTo("tb-image:" + + Base64.getEncoder().encodeToString(imageInfo.getResourceKey().getBytes()) + ":" + + Base64.getEncoder().encodeToString(imageInfo.getName().getBytes()) + ":" + + Base64.getEncoder().encodeToString(imageInfo.getResourceSubType().name().getBytes()) + + ";data:image/png;base64," + Base64.getEncoder().encodeToString(PNG_IMAGE)); + + deviceProfile = doGet("/api/deviceProfile/" + deviceProfile.getUuidId(), DeviceProfile.class); + assertThat(deviceProfile.getImage()).isEqualTo("tb-image;" + imageInfo.getLink()); + } + private TbResourceInfo updateImagePublicStatus(String filename, boolean isPublic) throws Exception { return doPut("/api/images/tenant/" + filename + "/public/" + isPublic, "", TbResourceInfo.class); } 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 a5fb3b05bf..3cfb2dc42b 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 @@ -274,7 +274,6 @@ public class NotificationRuleApiTest extends AbstractNotificationApiTest { Device device = createDevice("Device with alarm", "233"); NotificationTarget target = createNotificationTarget(tenantAdminUserId); defaultNotifications.create(tenantId, DefaultNotifications.newAlarm, target.getId()); - defaultNotifications.create(tenantId, DefaultNotifications.entityAction, target.getId()); notificationRulesCache.evict(tenantId); Alarm alarm = new Alarm(); @@ -287,7 +286,7 @@ public class NotificationRuleApiTest extends AbstractNotificationApiTest { .pollDelay(2, TimeUnit.SECONDS) .untilAsserted(() -> { List notifications = getMyNotifications(false, 10); - assertThat(notifications).hasSize(1).first().matches(notification -> { + assertThat(notifications).singleElement().matches(notification -> { return notification.getType() == NotificationType.ALARM && notification.getSubject().equals("New alarm 'testAlarm'"); }); @@ -353,12 +352,7 @@ public class NotificationRuleApiTest extends AbstractNotificationApiTest { .findFirst().orElse(null); assertThat(scheduledNotificationRequest).extracting(NotificationRequest::getInfo).isEqualTo(notification.getInfo()); - getWsClient().registerWaitForUpdate(); alarmSubscriptionService.clearAlarm(tenantId, alarm.getId(), System.currentTimeMillis(), null); - getWsClient().waitForUpdate(true); - notification = getWsClient().getLastDataUpdate().getUpdate(); - assertThat(notification.getSubject()).isEqualTo("critical alarm '" + alarmType + "' is CLEARED_UNACK"); - await().atMost(5, TimeUnit.SECONDS).untilAsserted(() -> { assertThat(findNotificationRequests(EntityType.ALARM).getData()).filteredOn(NotificationRequest::isScheduled).isEmpty(); }); diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/notification/NotificationRequestService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/notification/NotificationRequestService.java index 4a80775390..e2a0a3e467 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/notification/NotificationRequestService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/notification/NotificationRequestService.java @@ -43,7 +43,7 @@ public interface NotificationRequestService { List findNotificationRequestsIdsByStatusAndRuleId(TenantId tenantId, NotificationRequestStatus requestStatus, NotificationRuleId ruleId); - List findNotificationRequestsByRuleIdAndOriginatorEntityId(TenantId tenantId, NotificationRuleId ruleId, EntityId originatorEntityId); + List findNotificationRequestsByRuleIdAndOriginatorEntityIdAndStatus(TenantId tenantId, NotificationRuleId ruleId, EntityId originatorEntityId, NotificationRequestStatus status); void deleteNotificationRequest(TenantId tenantId, NotificationRequest request); diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/resource/ImageService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/resource/ImageService.java index fc282f6b74..a83b95ae34 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/resource/ImageService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/resource/ImageService.java @@ -64,7 +64,7 @@ public interface ImageService { boolean updateImagesUsage(WidgetTypeDetails widgetType); - void inlineImage(HasImage entity); + T inlineImage(T entity); Collection getUsedImages(Dashboard dashboard); diff --git a/common/version-control/src/main/java/org/thingsboard/server/service/sync/vc/GitRepository.java b/common/version-control/src/main/java/org/thingsboard/server/service/sync/vc/GitRepository.java index 33e15baccf..8498b4a7e4 100644 --- a/common/version-control/src/main/java/org/thingsboard/server/service/sync/vc/GitRepository.java +++ b/common/version-control/src/main/java/org/thingsboard/server/service/sync/vc/GitRepository.java @@ -51,7 +51,9 @@ import org.eclipse.jgit.revwalk.RevWalk; import org.eclipse.jgit.revwalk.filter.RevFilter; import org.eclipse.jgit.transport.CredentialsProvider; import org.eclipse.jgit.transport.FetchResult; +import org.eclipse.jgit.transport.PushResult; import org.eclipse.jgit.transport.RefSpec; +import org.eclipse.jgit.transport.RemoteRefUpdate; import org.eclipse.jgit.transport.SshTransport; import org.eclipse.jgit.transport.URIish; import org.eclipse.jgit.transport.UsernamePasswordCredentialsProvider; @@ -85,6 +87,7 @@ import java.util.Collections; import java.util.Comparator; import java.util.HashSet; import java.util.List; +import java.util.Optional; import java.util.Set; import java.util.UUID; import java.util.function.Function; @@ -350,8 +353,16 @@ public class GitRepository { return; } log.debug("Executing push [{}][{}]", settings.getRepositoryUri(), remoteBranch); - execute(git.push() + Iterable result = execute(git.push() .setRefSpecs(new RefSpec(localBranch + ":" + remoteBranch))); + result.forEach(pushResult -> { + for (RemoteRefUpdate update : pushResult.getRemoteUpdates()) { + RemoteRefUpdate.Status status = update.getStatus(); + if (status != RemoteRefUpdate.Status.OK && status != RemoteRefUpdate.Status.UP_TO_DATE) { + throw new RuntimeException("Failed to push changes: " + Optional.ofNullable(update.getMessage()).orElseGet(status::name)); + } + } + }); } public String getContentsDiff(String content1, String content2) throws IOException { diff --git a/dao/src/main/java/org/thingsboard/server/dao/domain/DomainServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/domain/DomainServiceImpl.java index d349d2d59b..1582d634b2 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/domain/DomainServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/domain/DomainServiceImpl.java @@ -67,7 +67,7 @@ public class DomainServiceImpl extends AbstractEntityService implements DomainSe return savedDomain; } catch (Exception e) { checkConstraintViolation(e, - Map.of("domain_unq_key", "Domain with such name and scheme already exists!")); + Map.of("domain_name_key", "Domain with such name and scheme already exists!")); throw e; } } diff --git a/dao/src/main/java/org/thingsboard/server/dao/notification/DefaultNotificationRequestService.java b/dao/src/main/java/org/thingsboard/server/dao/notification/DefaultNotificationRequestService.java index ebeb39ed91..b845cee74d 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/notification/DefaultNotificationRequestService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/notification/DefaultNotificationRequestService.java @@ -82,8 +82,8 @@ public class DefaultNotificationRequestService implements NotificationRequestSer } @Override - public List findNotificationRequestsByRuleIdAndOriginatorEntityId(TenantId tenantId, NotificationRuleId ruleId, EntityId originatorEntityId) { - return notificationRequestDao.findByRuleIdAndOriginatorEntityId(tenantId, ruleId, originatorEntityId); + public List findNotificationRequestsByRuleIdAndOriginatorEntityIdAndStatus(TenantId tenantId, NotificationRuleId ruleId, EntityId originatorEntityId, NotificationRequestStatus status) { + return notificationRequestDao.findByRuleIdAndOriginatorEntityIdAndStatus(tenantId, ruleId, originatorEntityId, status); } @Override diff --git a/dao/src/main/java/org/thingsboard/server/dao/notification/NotificationRequestDao.java b/dao/src/main/java/org/thingsboard/server/dao/notification/NotificationRequestDao.java index fb362f235b..c51091300a 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/notification/NotificationRequestDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/notification/NotificationRequestDao.java @@ -40,7 +40,7 @@ public interface NotificationRequestDao extends Dao { List findIdsByRuleId(TenantId tenantId, NotificationRequestStatus requestStatus, NotificationRuleId ruleId); - List findByRuleIdAndOriginatorEntityId(TenantId tenantId, NotificationRuleId ruleId, EntityId originatorEntityId); + List findByRuleIdAndOriginatorEntityIdAndStatus(TenantId tenantId, NotificationRuleId ruleId, EntityId originatorEntityId, NotificationRequestStatus status); PageData findAllByStatus(NotificationRequestStatus status, PageLink pageLink); diff --git a/dao/src/main/java/org/thingsboard/server/dao/resource/BaseImageService.java b/dao/src/main/java/org/thingsboard/server/dao/resource/BaseImageService.java index 1cf719d2dc..172b91a32c 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/resource/BaseImageService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/resource/BaseImageService.java @@ -27,6 +27,7 @@ import org.apache.commons.lang3.tuple.Pair; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.thingsboard.common.util.JacksonUtil; +import org.thingsboard.server.cache.CaffeineTbTransactionalCache; import org.thingsboard.server.common.data.Dashboard; import org.thingsboard.server.common.data.DataConstants; import org.thingsboard.server.common.data.EntityType; @@ -526,9 +527,16 @@ public class BaseImageService extends BaseResourceService implements ImageServic } @Override - public void inlineImage(HasImage entity) { + public T inlineImage(T entity) { log.trace("Executing inlineImage [{}] [{}] [{}]", entity.getTenantId(), entity.getClass().getSimpleName(), entity.getName()); + if (StringUtils.isEmpty(entity.getImage())) { + return entity; + } + if (cache instanceof CaffeineTbTransactionalCache) { + entity = JacksonUtil.clone(entity); // cloning the entity to avoid updating the cached one + } entity.setImage(inlineImage(entity.getTenantId(), "image", entity.getImage(), true)); + return entity; } @Override diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/notification/JpaNotificationRequestDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/notification/JpaNotificationRequestDao.java index 3d2d80e15e..6e5ae702dc 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/notification/JpaNotificationRequestDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/notification/JpaNotificationRequestDao.java @@ -73,8 +73,8 @@ public class JpaNotificationRequestDao extends JpaAbstractDao findByRuleIdAndOriginatorEntityId(TenantId tenantId, NotificationRuleId ruleId, EntityId originatorEntityId) { - return DaoUtil.convertDataList(notificationRequestRepository.findAllByRuleIdAndOriginatorEntityIdAndOriginatorEntityType(ruleId.getId(), originatorEntityId.getId(), originatorEntityId.getEntityType())); + public List findByRuleIdAndOriginatorEntityIdAndStatus(TenantId tenantId, NotificationRuleId ruleId, EntityId originatorEntityId, NotificationRequestStatus status) { + return DaoUtil.convertDataList(notificationRequestRepository.findAllByRuleIdAndOriginatorEntityIdAndOriginatorEntityTypeAndStatus(ruleId.getId(), originatorEntityId.getId(), originatorEntityId.getEntityType(), status)); } @Override diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/notification/NotificationRequestRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/notification/NotificationRequestRepository.java index d6b346e3df..558bab94ff 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/notification/NotificationRequestRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/notification/NotificationRequestRepository.java @@ -54,7 +54,7 @@ public interface NotificationRequestRepository extends JpaRepository findAllIdsByStatusAndRuleId(@Param("status") NotificationRequestStatus status, @Param("ruleId") UUID ruleId); - List findAllByRuleIdAndOriginatorEntityIdAndOriginatorEntityType(UUID ruleId, UUID originatorEntityId, EntityType originatorEntityType); + List findAllByRuleIdAndOriginatorEntityIdAndOriginatorEntityTypeAndStatus(UUID ruleId, UUID originatorEntityId, EntityType originatorEntityType, NotificationRequestStatus status); Page findAllByStatus(NotificationRequestStatus status, Pageable pageable); diff --git a/pom.xml b/pom.xml index f18740b658..dec169a9b6 100755 --- a/pom.xml +++ b/pom.xml @@ -869,6 +869,29 @@ + + io.github.git-commit-id + git-commit-id-maven-plugin + 5.0.0 + + + get-the-git-infos + + revision + + initialize + + + + true + ${project.build.outputDirectory}/git.properties + + + + + full + + diff --git a/ui-ngx/src/app/modules/home/components/alarm/alarm-filter-config.component.ts b/ui-ngx/src/app/modules/home/components/alarm/alarm-filter-config.component.ts index 609dbb8e7a..887a2e2e0d 100644 --- a/ui-ngx/src/app/modules/home/components/alarm/alarm-filter-config.component.ts +++ b/ui-ngx/src/app/modules/home/components/alarm/alarm-filter-config.component.ts @@ -16,6 +16,7 @@ import { Component, + DestroyRef, ElementRef, forwardRef, Inject, @@ -46,6 +47,7 @@ import { EntityType } from '@shared/models/entity-type.models'; import { fromEvent, Subscription } from 'rxjs'; import { POSITION_MAP } from '@shared/models/overlay.models'; import { UtilsService } from '@core/services/utils.service'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; export const ALARM_FILTER_CONFIG_DATA = new InjectionToken('AlarmFilterConfigData'); @@ -129,7 +131,8 @@ export class AlarmFilterConfigComponent implements OnInit, OnDestroy, ControlVal private overlay: Overlay, private nativeElement: ElementRef, private viewContainerRef: ViewContainerRef, - private utils: UtilsService) { + private utils: UtilsService, + private destroyRef: DestroyRef) { } ngOnInit(): void { @@ -149,7 +152,9 @@ export class AlarmFilterConfigComponent implements OnInit, OnDestroy, ControlVal searchPropagatedAlarms: [false, []], assigneeId: [AlarmAssigneeOption.noAssignee, []] }); - this.alarmFilterConfigForm.valueChanges.subscribe( + this.alarmFilterConfigForm.valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe( () => { if (!this.buttonMode) { this.alarmConfigUpdated(this.alarmFilterConfigForm.value); diff --git a/ui-ngx/src/app/modules/home/components/alias/entity-aliases-dialog.component.ts b/ui-ngx/src/app/modules/home/components/alias/entity-aliases-dialog.component.ts index 15791f9588..5a311a3392 100644 --- a/ui-ngx/src/app/modules/home/components/alias/entity-aliases-dialog.component.ts +++ b/ui-ngx/src/app/modules/home/components/alias/entity-aliases-dialog.component.ts @@ -14,7 +14,7 @@ /// limitations under the License. /// -import { Component, Inject, OnInit, SkipSelf } from '@angular/core'; +import { Component, DestroyRef, Inject, OnInit, SkipSelf } from '@angular/core'; import { ErrorStateMatcher } from '@angular/material/core'; import { MAT_DIALOG_DATA, MatDialog, MatDialogRef } from '@angular/material/dialog'; import { Store } from '@ngrx/store'; @@ -40,6 +40,7 @@ import { DialogService } from '@core/services/dialog.service'; import { deepClone, isUndefined } from '@core/utils'; import { EntityAliasDialogComponent, EntityAliasDialogData } from './entity-alias-dialog.component'; import { DashboardUtilsService } from '@core/services/dashboard-utils.service'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; export interface EntityAliasesDialogData { entityAliases: EntityAliases; @@ -80,7 +81,8 @@ export class EntityAliasesDialogComponent extends DialogComponent { + aliasFormControl.get('resolveMultiple').valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe((resolveMultiple: boolean) => { (aliasFormControl.get('filter').value as EntityAliasFilter).resolveMultiple = resolveMultiple; }); return aliasFormControl; diff --git a/ui-ngx/src/app/modules/home/components/attribute/add-widget-to-dashboard-dialog.component.ts b/ui-ngx/src/app/modules/home/components/attribute/add-widget-to-dashboard-dialog.component.ts index 9935ea5bbf..b745b1347e 100644 --- a/ui-ngx/src/app/modules/home/components/attribute/add-widget-to-dashboard-dialog.component.ts +++ b/ui-ngx/src/app/modules/home/components/attribute/add-widget-to-dashboard-dialog.component.ts @@ -40,6 +40,7 @@ import { AliasesInfo } from '@shared/models/alias.models'; import { ItemBufferService } from '@core/services/item-buffer.service'; import { StateObject } from '@core/api/widget-api.models'; import { FiltersInfo } from '@shared/models/query/query.models'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; export interface AddWidgetToDashboardDialogData { entityId: EntityId; @@ -83,7 +84,9 @@ export class AddWidgetToDashboardDialogComponent extends } ); - this.addWidgetFormGroup.get('addToDashboardType').valueChanges.subscribe( + this.addWidgetFormGroup.get('addToDashboardType').valueChanges.pipe( + takeUntilDestroyed() + ).subscribe( (addToDashboardType: number) => { if (addToDashboardType === 0) { this.addWidgetFormGroup.get('dashboardId').setValidators([Validators.required]); diff --git a/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-image-dialog.component.ts b/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-image-dialog.component.ts index bff5839bcb..35249f9200 100644 --- a/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-image-dialog.component.ts +++ b/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-image-dialog.component.ts @@ -28,6 +28,7 @@ import html2canvas from 'html2canvas'; import { map, share } from 'rxjs/operators'; import { BehaviorSubject, from } from 'rxjs'; import { isNumber } from '@core/utils'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; export interface DashboardImageDialogData { dashboardId: DashboardId; @@ -84,7 +85,9 @@ export class DashboardImageDialogComponent extends DialogComponent { this.updateImage(newImage); } diff --git a/ui-ngx/src/app/modules/home/components/dashboard-page/states/dashboard-state-dialog.component.ts b/ui-ngx/src/app/modules/home/components/dashboard-page/states/dashboard-state-dialog.component.ts index 223dfdbb54..051f82445f 100644 --- a/ui-ngx/src/app/modules/home/components/dashboard-page/states/dashboard-state-dialog.component.ts +++ b/ui-ngx/src/app/modules/home/components/dashboard-page/states/dashboard-state-dialog.component.ts @@ -34,6 +34,7 @@ import { DashboardState } from '@app/shared/models/dashboard.models'; import { DashboardStateInfo } from '@home/components/dashboard-page/states/manage-dashboard-states-dialog.component.models'; import { TranslateService } from '@ngx-translate/core'; import { DashboardUtilsService } from '@core/services/dashboard-utils.service'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; export interface DashboardStateDialogData { states: {[id: string]: DashboardState }; @@ -89,11 +90,15 @@ export class DashboardStateDialogComponent extends root: [this.state.root, []], }); - this.stateFormGroup.get('name').valueChanges.subscribe((name: string) => { + this.stateFormGroup.get('name').valueChanges.pipe( + takeUntilDestroyed() + ).subscribe((name: string) => { this.checkStateName(name); }); - this.stateFormGroup.get('id').valueChanges.subscribe((id: string) => { + this.stateFormGroup.get('id').valueChanges.pipe( + takeUntilDestroyed() + ).subscribe((id: string) => { this.stateIdTouched = true; }); } diff --git a/ui-ngx/src/app/modules/home/components/device/device-info-filter.component.ts b/ui-ngx/src/app/modules/home/components/device/device-info-filter.component.ts index b43aaf6100..ec85e1bf40 100644 --- a/ui-ngx/src/app/modules/home/components/device/device-info-filter.component.ts +++ b/ui-ngx/src/app/modules/home/components/device/device-info-filter.component.ts @@ -17,6 +17,7 @@ import { ChangeDetectorRef, Component, + DestroyRef, ElementRef, forwardRef, Inject, @@ -38,6 +39,7 @@ import { DeviceInfoFilter } from '@shared/models/device.models'; import { isDefinedAndNotNull } from '@core/utils'; import { EntityInfoData } from '@shared/models/entity.models'; import { DeviceProfileService } from '@core/http/device-profile.service'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; export const DEVICE_FILTER_CONFIG_DATA = new InjectionToken('DeviceFilterConfigData'); @@ -96,7 +98,8 @@ export class DeviceInfoFilterComponent implements OnInit, OnDestroy, ControlValu private nativeElement: ElementRef, private viewContainerRef: ViewContainerRef, private deviceProfileService: DeviceProfileService, - private cd: ChangeDetectorRef) { + private cd: ChangeDetectorRef, + private destroyRef: DestroyRef) { } ngOnInit(): void { @@ -108,7 +111,9 @@ export class DeviceInfoFilterComponent implements OnInit, OnDestroy, ControlValu deviceProfileId: [null, []], active: ['', []] }); - this.deviceInfoFilterForm.valueChanges.subscribe( + this.deviceInfoFilterForm.valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe( () => { this.updateValidators(); if (!this.buttonMode) { diff --git a/ui-ngx/src/app/modules/home/components/entity/contact-based.component.ts b/ui-ngx/src/app/modules/home/components/entity/contact-based.component.ts index 2d08fd9f50..3e23cbf8b1 100644 --- a/ui-ngx/src/app/modules/home/components/entity/contact-based.component.ts +++ b/ui-ngx/src/app/modules/home/components/entity/contact-based.component.ts @@ -18,15 +18,18 @@ import { Store } from '@ngrx/store'; import { AppState } from '@core/core.state'; import { UntypedFormBuilder, UntypedFormGroup, ValidatorFn, Validators } from '@angular/forms'; import { ContactBased } from '@shared/models/contact-based.model'; -import { AfterViewInit, ChangeDetectorRef, Directive } from '@angular/core'; +import { AfterViewInit, ChangeDetectorRef, DestroyRef, Directive, inject } from '@angular/core'; import { HasId } from '@shared/models/base-data'; import { EntityComponent } from './entity.component'; import { EntityTableConfig } from '@home/models/entity/entities-table-config.models'; import { CountryData } from '@shared/models/country.models'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; @Directive() export abstract class ContactBasedComponent> extends EntityComponent implements AfterViewInit { + protected destroyRef = inject(DestroyRef); + protected constructor(protected store: Store, protected fb: UntypedFormBuilder, protected entityValue: T, @@ -65,7 +68,9 @@ export abstract class ContactBasedComponent> exten } ngAfterViewInit() { - this.entityForm.get('country').valueChanges.subscribe( + this.entityForm.get('country').valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe( (country) => { this.entityForm.get('zip').setValidators(this.zipValidators(country)); this.entityForm.get('zip').updateValueAndValidity({onlySelf: true}); diff --git a/ui-ngx/src/app/modules/home/components/filter/boolean-filter-predicate.component.ts b/ui-ngx/src/app/modules/home/components/filter/boolean-filter-predicate.component.ts index cb19815c5b..1361062f3a 100644 --- a/ui-ngx/src/app/modules/home/components/filter/boolean-filter-predicate.component.ts +++ b/ui-ngx/src/app/modules/home/components/filter/boolean-filter-predicate.component.ts @@ -14,7 +14,7 @@ /// limitations under the License. /// -import { Component, forwardRef, Input, OnInit } from '@angular/core'; +import { Component, DestroyRef, forwardRef, Input, OnInit } from '@angular/core'; import { ControlValueAccessor, UntypedFormBuilder, @@ -32,6 +32,7 @@ import { EntityKeyValueType, FilterPredicateType } from '@shared/models/query/query.models'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; @Component({ selector: 'tb-boolean-filter-predicate', @@ -68,7 +69,8 @@ export class BooleanFilterPredicateComponent implements ControlValueAccessor, Va private propagateChange = null; - constructor(private fb: UntypedFormBuilder) { + constructor(private fb: UntypedFormBuilder, + private destroyRef: DestroyRef) { } ngOnInit(): void { @@ -76,7 +78,9 @@ export class BooleanFilterPredicateComponent implements ControlValueAccessor, Va operation: [BooleanOperation.EQUAL, [Validators.required]], value: [null, [Validators.required]] }); - this.booleanFilterPredicateFormGroup.valueChanges.subscribe(() => { + this.booleanFilterPredicateFormGroup.valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateModel(); }); } diff --git a/ui-ngx/src/app/modules/home/components/filter/filter-predicate-value.component.ts b/ui-ngx/src/app/modules/home/components/filter/filter-predicate-value.component.ts index 2f3d29df91..2192b33583 100644 --- a/ui-ngx/src/app/modules/home/components/filter/filter-predicate-value.component.ts +++ b/ui-ngx/src/app/modules/home/components/filter/filter-predicate-value.component.ts @@ -14,7 +14,7 @@ /// limitations under the License. /// -import { Component, forwardRef, Input, OnInit } from '@angular/core'; +import { Component, DestroyRef, forwardRef, Input, OnInit } from '@angular/core'; import { ControlValueAccessor, UntypedFormBuilder, @@ -35,6 +35,7 @@ import { inheritModeForDynamicValueSourceType, StringOperation } from '@shared/models/query/query.models'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; @Component({ selector: 'tb-filter-predicate-value', @@ -113,7 +114,8 @@ export class FilterPredicateValueComponent implements ControlValueAccessor, Vali private propagateChange = null; private propagateChangePending = false; - constructor(private fb: UntypedFormBuilder) { + constructor(private fb: UntypedFormBuilder, + private destroyRef: DestroyRef) { } ngOnInit(): void { @@ -147,7 +149,9 @@ export class FilterPredicateValueComponent implements ControlValueAccessor, Vali } ) }); - this.filterPredicateValueFormGroup.get('dynamicValue').get('sourceType').valueChanges.subscribe( + this.filterPredicateValueFormGroup.get('dynamicValue').get('sourceType').valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe( (sourceType) => { if (!sourceType) { this.filterPredicateValueFormGroup.get('dynamicValue').get('sourceAttribute').patchValue(null, {emitEvent: false}); @@ -156,7 +160,9 @@ export class FilterPredicateValueComponent implements ControlValueAccessor, Vali } ); this.updateValidationDynamicMode(); - this.filterPredicateValueFormGroup.valueChanges.subscribe(() => { + this.filterPredicateValueFormGroup.valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateModel(); }); } diff --git a/ui-ngx/src/app/modules/home/components/filter/filter-predicate.component.ts b/ui-ngx/src/app/modules/home/components/filter/filter-predicate.component.ts index d7bc07af2c..80a8d0b9ee 100644 --- a/ui-ngx/src/app/modules/home/components/filter/filter-predicate.component.ts +++ b/ui-ngx/src/app/modules/home/components/filter/filter-predicate.component.ts @@ -14,7 +14,7 @@ /// limitations under the License. /// -import { Component, forwardRef, Input, OnInit } from '@angular/core'; +import { Component, DestroyRef, forwardRef, Input, OnInit } from '@angular/core'; import { ControlValueAccessor, UntypedFormBuilder, @@ -26,6 +26,7 @@ import { Validators } from '@angular/forms'; import { EntityKeyValueType, FilterPredicateType, KeyFilterPredicateInfo } from '@shared/models/query/query.models'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; @Component({ selector: 'tb-filter-predicate', @@ -66,7 +67,8 @@ export class FilterPredicateComponent implements ControlValueAccessor, Validator private propagateChange = null; - constructor(private fb: UntypedFormBuilder) { + constructor(private fb: UntypedFormBuilder, + private destroyRef: DestroyRef) { } ngOnInit(): void { @@ -74,7 +76,9 @@ export class FilterPredicateComponent implements ControlValueAccessor, Validator predicate: [null, [Validators.required]], userInfo: [null, []] }); - this.filterPredicateFormGroup.valueChanges.subscribe(() => { + this.filterPredicateFormGroup.valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateModel(); }); } diff --git a/ui-ngx/src/app/modules/home/components/filter/filter-user-info-dialog.component.ts b/ui-ngx/src/app/modules/home/components/filter/filter-user-info-dialog.component.ts index 7d2c4f7e7c..de582ba8c3 100644 --- a/ui-ngx/src/app/modules/home/components/filter/filter-user-info-dialog.component.ts +++ b/ui-ngx/src/app/modules/home/components/filter/filter-user-info-dialog.component.ts @@ -29,6 +29,7 @@ import { StringOperation } from '@shared/models/query/query.models'; import { TranslateService } from '@ngx-translate/core'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; export interface FilterUserInfoDialogData { key: string; @@ -73,7 +74,9 @@ export class FilterUserInfoDialogComponent extends ); this.onAutogeneratedLabelChange(); if (!this.data.readonly) { - this.filterUserInfoFormGroup.get('autogeneratedLabel').valueChanges.subscribe(() => { + this.filterUserInfoFormGroup.get('autogeneratedLabel').valueChanges.pipe( + takeUntilDestroyed() + ).subscribe(() => { this.onAutogeneratedLabelChange(); }); } else { diff --git a/ui-ngx/src/app/modules/home/components/filter/numeric-filter-predicate.component.ts b/ui-ngx/src/app/modules/home/components/filter/numeric-filter-predicate.component.ts index 8210e7b06c..c1d36a7ee4 100644 --- a/ui-ngx/src/app/modules/home/components/filter/numeric-filter-predicate.component.ts +++ b/ui-ngx/src/app/modules/home/components/filter/numeric-filter-predicate.component.ts @@ -14,7 +14,7 @@ /// limitations under the License. /// -import { Component, forwardRef, Input, OnInit } from '@angular/core'; +import { Component, DestroyRef, forwardRef, Input, OnInit } from '@angular/core'; import { ControlValueAccessor, UntypedFormBuilder, @@ -32,6 +32,7 @@ import { NumericOperation, numericOperationTranslationMap, } from '@shared/models/query/query.models'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; @Component({ selector: 'tb-numeric-filter-predicate', @@ -70,7 +71,8 @@ export class NumericFilterPredicateComponent implements ControlValueAccessor, Va private propagateChange = null; - constructor(private fb: UntypedFormBuilder) { + constructor(private fb: UntypedFormBuilder, + private destroyRef: DestroyRef) { } ngOnInit(): void { @@ -78,7 +80,9 @@ export class NumericFilterPredicateComponent implements ControlValueAccessor, Va operation: [NumericOperation.EQUAL, [Validators.required]], value: [null, [Validators.required]] }); - this.numericFilterPredicateFormGroup.valueChanges.subscribe(() => { + this.numericFilterPredicateFormGroup.valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateModel(); }); } diff --git a/ui-ngx/src/app/modules/home/components/filter/string-filter-predicate.component.ts b/ui-ngx/src/app/modules/home/components/filter/string-filter-predicate.component.ts index 2e6d80029a..7cd62c41e9 100644 --- a/ui-ngx/src/app/modules/home/components/filter/string-filter-predicate.component.ts +++ b/ui-ngx/src/app/modules/home/components/filter/string-filter-predicate.component.ts @@ -14,7 +14,7 @@ /// limitations under the License. /// -import { Component, forwardRef, Input, OnInit } from '@angular/core'; +import { Component, DestroyRef, forwardRef, Input, OnInit } from '@angular/core'; import { ControlValueAccessor, UntypedFormBuilder, @@ -32,6 +32,7 @@ import { StringOperation, stringOperationTranslationMap } from '@shared/models/query/query.models'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; @Component({ selector: 'tb-string-filter-predicate', @@ -68,7 +69,8 @@ export class StringFilterPredicateComponent implements ControlValueAccessor, Val private propagateChange = null; - constructor(private fb: UntypedFormBuilder) { + constructor(private fb: UntypedFormBuilder, + private destroyRef: DestroyRef) { } ngOnInit(): void { @@ -77,7 +79,9 @@ export class StringFilterPredicateComponent implements ControlValueAccessor, Val value: [null, [Validators.required]], ignoreCase: [false] }); - this.stringFilterPredicateFormGroup.valueChanges.subscribe(() => { + this.stringFilterPredicateFormGroup.valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateModel(); }); } diff --git a/ui-ngx/src/app/modules/home/components/filter/user-filter-dialog.component.ts b/ui-ngx/src/app/modules/home/components/filter/user-filter-dialog.component.ts index ee5a780eff..0072b68d08 100644 --- a/ui-ngx/src/app/modules/home/components/filter/user-filter-dialog.component.ts +++ b/ui-ngx/src/app/modules/home/components/filter/user-filter-dialog.component.ts @@ -14,7 +14,7 @@ /// limitations under the License. /// -import { Component, Inject, OnInit, SkipSelf } from '@angular/core'; +import { Component, DestroyRef, Inject, OnInit, SkipSelf } from '@angular/core'; import { ErrorStateMatcher } from '@angular/material/core'; import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; import { Store } from '@ngrx/store'; @@ -38,6 +38,7 @@ import { UserFilterInputInfo } from '@shared/models/query/query.models'; import { isDefinedAndNotNull } from '@core/utils'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; export interface UserFilterDialogData { filter: Filter; @@ -66,7 +67,8 @@ export class UserFilterDialogComponent extends DialogComponent, private fb: UntypedFormBuilder, - public translate: TranslateService) { + public translate: TranslateService, + private destroyRef: DestroyRef) { super(store, router, dialogRef); this.filter = data.filter; const userInputs = filterToUserFilterInfoList(this.filter, translate); @@ -91,7 +93,9 @@ export class UserFilterDialogComponent extends DialogComponent { + userInputControl.get('value').valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(userValue => { (userInput.info.keyFilterPredicate as any).value.userValue = userValue; }); return userInputControl; diff --git a/ui-ngx/src/app/modules/home/components/profile/add-device-profile-dialog.component.ts b/ui-ngx/src/app/modules/home/components/profile/add-device-profile-dialog.component.ts index cee7426e26..83bfdf77a6 100644 --- a/ui-ngx/src/app/modules/home/components/profile/add-device-profile-dialog.component.ts +++ b/ui-ngx/src/app/modules/home/components/profile/add-device-profile-dialog.component.ts @@ -46,6 +46,7 @@ import { Observable } from 'rxjs'; import { BreakpointObserver } from '@angular/cdk/layout'; import { MediaBreakpoints } from '@shared/models/constants'; import { map } from 'rxjs/operators'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; export interface AddDeviceProfileDialogData { deviceProfileName: string; @@ -125,7 +126,9 @@ export class AddDeviceProfileDialogComponent extends [Validators.required]] } ); - this.transportConfigFormGroup.get('transportType').valueChanges.subscribe(() => { + this.transportConfigFormGroup.get('transportType').valueChanges.pipe( + takeUntilDestroyed() + ).subscribe(() => { this.deviceProfileTransportTypeChanged(); }); diff --git a/ui-ngx/src/app/modules/home/components/profile/alarm/alarm-duration-predicate-value.component.ts b/ui-ngx/src/app/modules/home/components/profile/alarm/alarm-duration-predicate-value.component.ts index ad821389cd..2063ca1522 100644 --- a/ui-ngx/src/app/modules/home/components/profile/alarm/alarm-duration-predicate-value.component.ts +++ b/ui-ngx/src/app/modules/home/components/profile/alarm/alarm-duration-predicate-value.component.ts @@ -14,7 +14,7 @@ /// limitations under the License. /// -import { Component, forwardRef, Input, OnInit } from '@angular/core'; +import { Component, DestroyRef, forwardRef, Input, OnInit } from '@angular/core'; import { ControlValueAccessor, UntypedFormBuilder, UntypedFormGroup, NG_VALUE_ACCESSOR, Validators } from '@angular/forms'; import { DynamicValueSourceType, @@ -24,6 +24,7 @@ import { inheritModeForDynamicValueSourceType } from '@shared/models/query/query.models'; import { AlarmConditionType } from '@shared/models/device.models'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; @Component({ selector: 'tb-alarm-duration-predicate-value', @@ -76,7 +77,8 @@ export class AlarmDurationPredicateValueComponent implements ControlValueAccesso private propagateChange = null; - constructor(private fb: UntypedFormBuilder) { + constructor(private fb: UntypedFormBuilder, + private destroyRef: DestroyRef) { } ngOnInit(): void { @@ -90,7 +92,9 @@ export class AlarmDurationPredicateValueComponent implements ControlValueAccesso } ) }); - this.alarmDurationPredicateValueFormGroup.get('dynamicValue').get('sourceType').valueChanges.subscribe( + this.alarmDurationPredicateValueFormGroup.get('dynamicValue').get('sourceType').valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe( (sourceType) => { if (!sourceType) { this.alarmDurationPredicateValueFormGroup.get('dynamicValue').get('sourceAttribute').patchValue(null, {emitEvent: false}); @@ -98,7 +102,9 @@ export class AlarmDurationPredicateValueComponent implements ControlValueAccesso this.updateShowInheritMode(sourceType); } ); - this.alarmDurationPredicateValueFormGroup.valueChanges.subscribe(() => { + this.alarmDurationPredicateValueFormGroup.valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateModel(); }); } diff --git a/ui-ngx/src/app/modules/home/components/profile/alarm/alarm-dynamic-value.component.ts b/ui-ngx/src/app/modules/home/components/profile/alarm/alarm-dynamic-value.component.ts index bb6a9bdbc8..f8e07d8381 100644 --- a/ui-ngx/src/app/modules/home/components/profile/alarm/alarm-dynamic-value.component.ts +++ b/ui-ngx/src/app/modules/home/components/profile/alarm/alarm-dynamic-value.component.ts @@ -14,7 +14,7 @@ /// limitations under the License. /// -import { Component, forwardRef, Input, OnInit } from '@angular/core'; +import { Component, DestroyRef, forwardRef, Input, OnInit } from '@angular/core'; import { ControlValueAccessor, UntypedFormBuilder, @@ -26,6 +26,7 @@ import { dynamicValueSourceTypeTranslationMap, getDynamicSourcesForAllowUser } from '@shared/models/query/query.models'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; @Component({ selector: 'tb-alarm-dynamic-value', @@ -49,7 +50,8 @@ export class AlarmDynamicValue implements ControlValueAccessor, OnInit{ @Input() disabled: boolean; - constructor(private fb: UntypedFormBuilder) { + constructor(private fb: UntypedFormBuilder, + private destroyRef: DestroyRef) { } ngOnInit(): void { @@ -58,7 +60,9 @@ export class AlarmDynamicValue implements ControlValueAccessor, OnInit{ sourceAttribute: [null] }) - this.dynamicValue.get('sourceType').valueChanges.subscribe( + this.dynamicValue.get('sourceType').valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe( (sourceType) => { if (!sourceType) { this.dynamicValue.get('sourceAttribute').patchValue(null, {emitEvent: false}); @@ -66,7 +70,9 @@ export class AlarmDynamicValue implements ControlValueAccessor, OnInit{ } ); - this.dynamicValue.valueChanges.subscribe(() => { + this.dynamicValue.valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateModel(); }) } diff --git a/ui-ngx/src/app/modules/home/components/profile/alarm/alarm-rule-condition-dialog.component.ts b/ui-ngx/src/app/modules/home/components/profile/alarm/alarm-rule-condition-dialog.component.ts index 6e341b58b5..8eb0f196b7 100644 --- a/ui-ngx/src/app/modules/home/components/profile/alarm/alarm-rule-condition-dialog.component.ts +++ b/ui-ngx/src/app/modules/home/components/profile/alarm/alarm-rule-condition-dialog.component.ts @@ -27,6 +27,7 @@ import { keyFilterInfosToKeyFilters, keyFiltersToKeyFilterInfos } from '@shared/ import { AlarmCondition, AlarmConditionType, AlarmConditionTypeTranslationMap } from '@shared/models/device.models'; import { TimeUnit, timeUnitTranslationMap } from '@shared/models/time/time.models'; import { EntityId } from '@shared/models/id/entity-id'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; export interface AlarmRuleConditionDialogData { readonly: boolean; @@ -74,7 +75,9 @@ export class AlarmRuleConditionDialogComponent extends DialogComponent { + this.conditionFormGroup.get('spec.type').valueChanges.pipe( + takeUntilDestroyed() + ).subscribe((type) => { this.updateValidators(type, true, true); }); if (this.readonly) { diff --git a/ui-ngx/src/app/modules/home/components/profile/alarm/alarm-rule.component.ts b/ui-ngx/src/app/modules/home/components/profile/alarm/alarm-rule.component.ts index 96829a3f8c..bba8907da3 100644 --- a/ui-ngx/src/app/modules/home/components/profile/alarm/alarm-rule.component.ts +++ b/ui-ngx/src/app/modules/home/components/profile/alarm/alarm-rule.component.ts @@ -14,7 +14,7 @@ /// limitations under the License. /// -import { Component, forwardRef, Input, OnInit } from '@angular/core'; +import { Component, DestroyRef, forwardRef, Input, OnInit } from '@angular/core'; import { ControlValueAccessor, UntypedFormBuilder, @@ -36,6 +36,7 @@ import { import { EntityId } from '@shared/models/id/entity-id'; import { DashboardId } from '@shared/models/id/dashboard-id'; import { UtilsService } from '@core/services/utils.service'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; @Component({ selector: 'tb-alarm-rule', @@ -81,7 +82,8 @@ export class AlarmRuleComponent implements ControlValueAccessor, OnInit, Validat constructor(private dialog: MatDialog, private utils: UtilsService, - private fb: UntypedFormBuilder) { + private fb: UntypedFormBuilder, + private destroyRef: DestroyRef) { } registerOnChange(fn: any): void { @@ -98,7 +100,9 @@ export class AlarmRuleComponent implements ControlValueAccessor, OnInit, Validat alarmDetails: [null], dashboardId: [null] }); - this.alarmRuleFormGroup.valueChanges.subscribe(() => { + this.alarmRuleFormGroup.valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateModel(); }); } diff --git a/ui-ngx/src/app/modules/home/components/profile/alarm/alarm-schedule.component.ts b/ui-ngx/src/app/modules/home/components/profile/alarm/alarm-schedule.component.ts index cf9b2fcff6..bdbd3d989d 100644 --- a/ui-ngx/src/app/modules/home/components/profile/alarm/alarm-schedule.component.ts +++ b/ui-ngx/src/app/modules/home/components/profile/alarm/alarm-schedule.component.ts @@ -14,7 +14,7 @@ /// limitations under the License. /// -import { Component, forwardRef, Input, OnInit } from '@angular/core'; +import { Component, DestroyRef, forwardRef, Input, OnInit } from '@angular/core'; import { AbstractControl, ControlValueAccessor, @@ -40,6 +40,7 @@ import { import { isDefined, isDefinedAndNotNull } from '@core/utils'; import { MatCheckboxChange } from '@angular/material/checkbox'; import { getDefaultTimezone } from '@shared/models/time/time.models'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; @Component({ selector: 'tb-alarm-schedule', @@ -80,7 +81,8 @@ export class AlarmScheduleComponent implements ControlValueAccessor, Validator, private propagateChange = (v: any) => { }; - constructor(private fb: UntypedFormBuilder) { + constructor(private fb: UntypedFormBuilder, + private destroyRef: DestroyRef) { } ngOnInit(): void { @@ -94,13 +96,17 @@ export class AlarmScheduleComponent implements ControlValueAccessor, Validator, dynamicValue: [null] }); - this.alarmScheduleForm.get('type').valueChanges.subscribe((type) => { + this.alarmScheduleForm.get('type').valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe((type) => { const defaultTimezone = getDefaultTimezone(); this.alarmScheduleForm.reset({type, items: this.defaultItems, timezone: defaultTimezone}, {emitEvent: false}); this.updateValidators(type, true); this.alarmScheduleForm.updateValueAndValidity(); }); - this.alarmScheduleForm.valueChanges.subscribe(() => { + this.alarmScheduleForm.valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateModel(); }); } diff --git a/ui-ngx/src/app/modules/home/components/profile/alarm/device-profile-alarm.component.ts b/ui-ngx/src/app/modules/home/components/profile/alarm/device-profile-alarm.component.ts index 2754969fac..637c9a59f7 100644 --- a/ui-ngx/src/app/modules/home/components/profile/alarm/device-profile-alarm.component.ts +++ b/ui-ngx/src/app/modules/home/components/profile/alarm/device-profile-alarm.component.ts @@ -14,7 +14,7 @@ /// limitations under the License. /// -import { Component, EventEmitter, forwardRef, Input, OnInit, Output } from '@angular/core'; +import { Component, DestroyRef, EventEmitter, forwardRef, Input, OnInit, Output } from '@angular/core'; import { ControlValueAccessor, UntypedFormBuilder, @@ -31,6 +31,7 @@ import { COMMA, ENTER, SEMICOLON } from '@angular/cdk/keycodes'; import { MatChipInputEvent } from '@angular/material/chips'; import { EntityId } from '@shared/models/id/entity-id'; import { UtilsService } from '@core/services/utils.service'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; @Component({ selector: 'tb-device-profile-alarm', @@ -74,7 +75,8 @@ export class DeviceProfileAlarmComponent implements ControlValueAccessor, OnInit constructor(private dialog: MatDialog, private utils: UtilsService, - private fb: UntypedFormBuilder) { + private fb: UntypedFormBuilder, + private destroyRef: DestroyRef) { } registerOnChange(fn: any): void { @@ -101,7 +103,9 @@ export class DeviceProfileAlarmComponent implements ControlValueAccessor, OnInit propagateToOwner: [null], propagateToTenant: [null] }, { validators: deviceProfileAlarmValidator }); - this.alarmFormGroup.valueChanges.subscribe(() => { + this.alarmFormGroup.valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateModel(); }); } diff --git a/ui-ngx/src/app/modules/home/components/profile/device-profile-provision-configuration.component.ts b/ui-ngx/src/app/modules/home/components/profile/device-profile-provision-configuration.component.ts index df6cdd52e1..6713877480 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device-profile-provision-configuration.component.ts +++ b/ui-ngx/src/app/modules/home/components/profile/device-profile-provision-configuration.component.ts @@ -14,7 +14,7 @@ /// limitations under the License. /// -import { Component, forwardRef, Input, OnInit } from '@angular/core'; +import { Component, DestroyRef, forwardRef, Input, OnInit } from '@angular/core'; import { ControlValueAccessor, UntypedFormBuilder, @@ -37,6 +37,7 @@ import { ActionNotificationShow } from '@core/notification/notification.actions' import { Store } from '@ngrx/store'; import { AppState } from '@core/core.state'; import { TranslateService } from '@ngx-translate/core'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; @Component({ selector: 'tb-device-profile-provision-configuration', @@ -79,7 +80,8 @@ export class DeviceProfileProvisionConfigurationComponent implements ControlValu constructor(protected store: Store, private fb: UntypedFormBuilder, - private translate: TranslateService) { + private translate: TranslateService, + private destroyRef: DestroyRef) { } ngOnInit(): void { @@ -91,7 +93,9 @@ export class DeviceProfileProvisionConfigurationComponent implements ControlValu certificateRegExPattern: [{value: null, disabled: true}, Validators.required], allowCreateNewDevicesByX509Certificate: [{value: null, disabled: true}, Validators.required] }); - this.provisionConfigurationFormGroup.get('type').valueChanges.subscribe((type) => { + this.provisionConfigurationFormGroup.get('type').valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe((type) => { if (type === DeviceProvisionType.DISABLED) { for (const field in this.provisionConfigurationFormGroup.controls) { if (field !== 'type') { @@ -129,7 +133,9 @@ export class DeviceProfileProvisionConfigurationComponent implements ControlValu this.provisionConfigurationFormGroup.get('provisionDeviceKey').enable({emitEvent: false}); } }); - this.provisionConfigurationFormGroup.valueChanges.subscribe(() => { + this.provisionConfigurationFormGroup.valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateModel(); }); } diff --git a/ui-ngx/src/app/modules/home/components/profile/device-profile.component.ts b/ui-ngx/src/app/modules/home/components/profile/device-profile.component.ts index 930e44a5d9..ea2d6fb1ca 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device-profile.component.ts +++ b/ui-ngx/src/app/modules/home/components/profile/device-profile.component.ts @@ -14,7 +14,7 @@ /// limitations under the License. /// -import { ChangeDetectorRef, Component, Inject, Input, Optional } from '@angular/core'; +import { ChangeDetectorRef, Component, DestroyRef, Inject, Input, Optional } from '@angular/core'; import { Store } from '@ngrx/store'; import { AppState } from '@core/core.state'; import { UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms'; @@ -43,6 +43,7 @@ import { EntityId } from '@shared/models/id/entity-id'; import { OtaUpdateType } from '@shared/models/ota-package.models'; import { DashboardId } from '@shared/models/id/dashboard-id'; import { RuleChainType } from '@shared/models/rule-chain.models'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; @Component({ selector: 'tb-device-profile', @@ -83,7 +84,8 @@ export class DeviceProfileComponent extends EntityComponent { @Optional() @Inject('entity') protected entityValue: DeviceProfile, @Optional() @Inject('entitiesTableConfig') protected entitiesTableConfigValue: EntityTableConfig, protected fb: UntypedFormBuilder, - protected cd: ChangeDetectorRef) { + protected cd: ChangeDetectorRef, + private destroyRef: DestroyRef) { super(store, fb, entityValue, entitiesTableConfigValue, cd); } @@ -129,10 +131,14 @@ export class DeviceProfileComponent extends EntityComponent { description: [entity ? entity.description : '', []], } ); - form.get('type').valueChanges.subscribe(() => { + form.get('type').valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.deviceProfileTypeChanged(form); }); - form.get('transportType').valueChanges.subscribe(() => { + form.get('transportType').valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.deviceProfileTransportTypeChanged(form); }); this.checkIsNewDeviceProfile(entity, form); diff --git a/ui-ngx/src/app/modules/home/components/profile/device/default-device-profile-configuration.component.ts b/ui-ngx/src/app/modules/home/components/profile/device/default-device-profile-configuration.component.ts index ff8e947ba3..1b09268536 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device/default-device-profile-configuration.component.ts +++ b/ui-ngx/src/app/modules/home/components/profile/device/default-device-profile-configuration.component.ts @@ -14,7 +14,7 @@ /// limitations under the License. /// -import { Component, forwardRef, Input, OnInit } from '@angular/core'; +import { Component, DestroyRef, forwardRef, Input, OnInit } from '@angular/core'; import { ControlValueAccessor, UntypedFormBuilder, UntypedFormGroup, NG_VALUE_ACCESSOR, Validators } from '@angular/forms'; import { Store } from '@ngrx/store'; import { AppState } from '@app/core/core.state'; @@ -23,6 +23,7 @@ import { DeviceProfileConfiguration, DeviceProfileType } from '@shared/models/device.models'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; @Component({ selector: 'tb-default-device-profile-configuration', @@ -44,7 +45,8 @@ export class DefaultDeviceProfileConfigurationComponent implements ControlValueA private propagateChange = (v: any) => { }; constructor(private store: Store, - private fb: UntypedFormBuilder) { + private fb: UntypedFormBuilder, + private destroyRef: DestroyRef) { } registerOnChange(fn: any): void { @@ -58,7 +60,9 @@ export class DefaultDeviceProfileConfigurationComponent implements ControlValueA this.defaultDeviceProfileConfigurationFormGroup = this.fb.group({ configuration: [null, Validators.required] }); - this.defaultDeviceProfileConfigurationFormGroup.valueChanges.subscribe(() => { + this.defaultDeviceProfileConfigurationFormGroup.valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateModel(); }); } diff --git a/ui-ngx/src/app/modules/home/components/profile/device/default-device-profile-transport-configuration.component.ts b/ui-ngx/src/app/modules/home/components/profile/device/default-device-profile-transport-configuration.component.ts index 1289d83745..5bbf451cde 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device/default-device-profile-transport-configuration.component.ts +++ b/ui-ngx/src/app/modules/home/components/profile/device/default-device-profile-transport-configuration.component.ts @@ -14,7 +14,7 @@ /// limitations under the License. /// -import { Component, forwardRef, Input, OnInit } from '@angular/core'; +import { Component, DestroyRef, forwardRef, Input, OnInit } from '@angular/core'; import { ControlValueAccessor, NG_VALIDATORS, @@ -29,6 +29,7 @@ import { import { Store } from '@ngrx/store'; import { AppState } from '@app/core/core.state'; import { DefaultDeviceProfileTransportConfiguration, DeviceTransportType } from '@shared/models/device.models'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; @Component({ selector: 'tb-default-device-profile-transport-configuration', @@ -57,7 +58,8 @@ export class DefaultDeviceProfileTransportConfigurationComponent implements Cont private propagateChange = (v: any) => { }; constructor(private store: Store, - private fb: UntypedFormBuilder) { + private fb: UntypedFormBuilder, + private destroyRef: DestroyRef) { } registerOnChange(fn: any): void { @@ -71,7 +73,9 @@ export class DefaultDeviceProfileTransportConfigurationComponent implements Cont this.defaultDeviceProfileTransportConfigurationFormGroup = this.fb.group({ configuration: [null, Validators.required] }); - this.defaultDeviceProfileTransportConfigurationFormGroup.valueChanges.subscribe(() => { + this.defaultDeviceProfileTransportConfigurationFormGroup.valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateModel(); }); } diff --git a/ui-ngx/src/app/modules/home/components/profile/device/device-profile-transport-configuration.component.ts b/ui-ngx/src/app/modules/home/components/profile/device/device-profile-transport-configuration.component.ts index 998235aefd..47d782dbdb 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device/device-profile-transport-configuration.component.ts +++ b/ui-ngx/src/app/modules/home/components/profile/device/device-profile-transport-configuration.component.ts @@ -14,7 +14,7 @@ /// limitations under the License. /// -import { Component, forwardRef, Input, OnInit } from '@angular/core'; +import { Component, DestroyRef, forwardRef, Input, OnInit } from '@angular/core'; import { ControlValueAccessor, NG_VALIDATORS, @@ -29,6 +29,7 @@ import { Store } from '@ngrx/store'; import { AppState } from '@app/core/core.state'; import { DeviceProfileTransportConfiguration, DeviceTransportType } from '@shared/models/device.models'; import { deepClone } from '@core/utils'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; @Component({ selector: 'tb-device-profile-transport-configuration', @@ -64,7 +65,8 @@ export class DeviceProfileTransportConfigurationComponent implements ControlValu private propagateChange = (v: any) => { }; constructor(private store: Store, - private fb: UntypedFormBuilder) { + private fb: UntypedFormBuilder, + private destroyRef: DestroyRef) { } registerOnChange(fn: any): void { @@ -78,7 +80,9 @@ export class DeviceProfileTransportConfigurationComponent implements ControlValu this.deviceProfileTransportConfigurationFormGroup = this.fb.group({ configuration: [null] }); - this.deviceProfileTransportConfigurationFormGroup.valueChanges.subscribe(() => { + this.deviceProfileTransportConfigurationFormGroup.valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateModel(); }); } diff --git a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-object-list.component.ts b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-object-list.component.ts index 950ac38cdb..775a5c963e 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-object-list.component.ts +++ b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-object-list.component.ts @@ -34,6 +34,7 @@ import { Direction } from '@shared/models/page/sort-order'; import { isDefined, isDefinedAndNotNull, isObject, isString } from '@core/utils'; import { PageLink } from '@shared/models/page/page-link'; import { TruncatePipe } from '@shared/pipe/truncate.pipe'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; @Component({ selector: 'tb-profile-lwm2m-object-list', @@ -90,7 +91,9 @@ export class Lwm2mObjectListComponent implements ControlValueAccessor, OnInit, V objectsList: [this.objectsList], objectLwm2m: [''] }); - this.lwm2mListFormGroup.get('objectsList').valueChanges.subscribe((value) => { + this.lwm2mListFormGroup.get('objectsList').valueChanges.pipe( + takeUntilDestroyed() + ).subscribe((value) => { if (!value.length || (value.length && isObject(value[0]))) { let formValue = null; if (this.lwm2mListFormGroup.valid) { diff --git a/ui-ngx/src/app/modules/home/components/profile/tenant-profile.component.ts b/ui-ngx/src/app/modules/home/components/profile/tenant-profile.component.ts index 9035b3dbaa..98a31db155 100644 --- a/ui-ngx/src/app/modules/home/components/profile/tenant-profile.component.ts +++ b/ui-ngx/src/app/modules/home/components/profile/tenant-profile.component.ts @@ -14,7 +14,7 @@ /// limitations under the License. /// -import { ChangeDetectorRef, Component, Inject, Input, Optional } from '@angular/core'; +import { ChangeDetectorRef, Component, DestroyRef, Inject, Input, Optional } from '@angular/core'; import { Store } from '@ngrx/store'; import { AppState } from '@core/core.state'; import { UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms'; @@ -24,6 +24,7 @@ import { TranslateService } from '@ngx-translate/core'; import { EntityTableConfig } from '@home/models/entity/entities-table-config.models'; import { EntityComponent } from '../entity/entity.component'; import { guid } from '@core/utils'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; @Component({ selector: 'tb-tenant-profile', @@ -40,7 +41,8 @@ export class TenantProfileComponent extends EntityComponent { @Optional() @Inject('entity') protected entityValue: TenantProfile, @Optional() @Inject('entitiesTableConfig') protected entitiesTableConfigValue: EntityTableConfig, protected fb: UntypedFormBuilder, - protected cd: ChangeDetectorRef) { + protected cd: ChangeDetectorRef, + private destroyRef: DestroyRef) { super(store, fb, entityValue, entitiesTableConfigValue, cd); } @@ -142,7 +144,9 @@ export class TenantProfileComponent extends EntityComponent { description: [entity ? entity.description : '', []], } ); - formGroup.get('isolatedTbRuleEngine').valueChanges.subscribe((value) => { + formGroup.get('isolatedTbRuleEngine').valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe((value) => { if (value) { formGroup.get('profileData').patchValue({ queueConfiguration: mainQueue 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 36ac40ecf2..fdf48af08c 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 @@ -128,7 +128,9 @@ export class DefaultTenantProfileConfigurationComponent implements ControlValueA } ); - this.defaultTenantProfileConfigurationFormGroup.valueChanges.subscribe(() => { + this.defaultTenantProfileConfigurationFormGroup.valueChanges.pipe( + takeUntil(this.destroy$) + ).subscribe(() => { this.updateModel(); }); } diff --git a/ui-ngx/src/app/modules/home/components/profile/tenant/rate-limits/rate-limits-list.component.ts b/ui-ngx/src/app/modules/home/components/profile/tenant/rate-limits/rate-limits-list.component.ts index dbc8f3e5df..38508c81c6 100644 --- a/ui-ngx/src/app/modules/home/components/profile/tenant/rate-limits/rate-limits-list.component.ts +++ b/ui-ngx/src/app/modules/home/components/profile/tenant/rate-limits/rate-limits-list.component.ts @@ -56,7 +56,6 @@ export class RateLimitsListComponent implements ControlValueAccessor, Validator, rateLimitsArray: Array; - private valueChangeSubscription: Subscription = null; private destroy$ = new Subject(); private propagateChange = (v: any) => { }; @@ -66,7 +65,7 @@ export class RateLimitsListComponent implements ControlValueAccessor, Validator, this.rateLimitsListFormGroup = this.fb.group({ rateLimits: this.fb.array([]) }); - this.valueChangeSubscription = this.rateLimitsListFormGroup.valueChanges + this.rateLimitsListFormGroup.valueChanges .pipe(takeUntil(this.destroy$)) .subscribe((value) => { this.updateView(value?.rateLimits); diff --git a/ui-ngx/src/app/modules/home/components/profile/tenant/tenant-profile-configuration.component.ts b/ui-ngx/src/app/modules/home/components/profile/tenant/tenant-profile-configuration.component.ts index 9494957cf5..c90485bc0b 100644 --- a/ui-ngx/src/app/modules/home/components/profile/tenant/tenant-profile-configuration.component.ts +++ b/ui-ngx/src/app/modules/home/components/profile/tenant/tenant-profile-configuration.component.ts @@ -14,13 +14,14 @@ /// limitations under the License. /// -import { Component, forwardRef, Input, OnInit } from '@angular/core'; +import { Component, DestroyRef, forwardRef, Input, OnInit } from '@angular/core'; import { ControlValueAccessor, UntypedFormBuilder, UntypedFormGroup, NG_VALUE_ACCESSOR, Validators } from '@angular/forms'; import { Store } from '@ngrx/store'; import { AppState } from '@app/core/core.state'; import { coerceBooleanProperty } from '@angular/cdk/coercion'; import { deepClone } from '@core/utils'; import { TenantProfileConfiguration, TenantProfileType } from '@shared/models/tenant.model'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; @Component({ selector: 'tb-tenant-profile-configuration', @@ -55,7 +56,8 @@ export class TenantProfileConfigurationComponent implements ControlValueAccessor private propagateChange = (v: any) => { }; constructor(private store: Store, - private fb: UntypedFormBuilder) { + private fb: UntypedFormBuilder, + private destroyRef: DestroyRef) { } registerOnChange(fn: any): void { @@ -69,7 +71,9 @@ export class TenantProfileConfigurationComponent implements ControlValueAccessor this.tenantProfileConfigurationFormGroup = this.fb.group({ configuration: [null, Validators.required] }); - this.tenantProfileConfigurationFormGroup.valueChanges.subscribe(() => { + this.tenantProfileConfigurationFormGroup.valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateModel(); }); } diff --git a/ui-ngx/src/app/modules/home/components/queue/queue-form.component.ts b/ui-ngx/src/app/modules/home/components/queue/queue-form.component.ts index c9a09a262d..25ae1ae873 100644 --- a/ui-ngx/src/app/modules/home/components/queue/queue-form.component.ts +++ b/ui-ngx/src/app/modules/home/components/queue/queue-form.component.ts @@ -14,7 +14,7 @@ /// limitations under the License. /// -import { Component, forwardRef, Input, OnDestroy, OnInit } from '@angular/core'; +import { Component, DestroyRef, forwardRef, Input, OnDestroy, OnInit } from '@angular/core'; import { ControlValueAccessor, UntypedFormBuilder, @@ -35,6 +35,7 @@ import { } from '@shared/models/queue.models'; import { isDefinedAndNotNull } from '@core/utils'; import { Subscription } from 'rxjs'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; @Component({ selector: 'tb-queue-form', @@ -53,7 +54,7 @@ import { Subscription } from 'rxjs'; } ] }) -export class QueueFormComponent implements ControlValueAccessor, OnInit, OnDestroy, Validator { +export class QueueFormComponent implements ControlValueAccessor, OnInit, Validator { @Input() disabled: boolean; @@ -77,10 +78,10 @@ export class QueueFormComponent implements ControlValueAccessor, OnInit, OnDestr private modelValue: QueueInfo; private propagateChange = null; private propagateChangePending = false; - private valueChange$: Subscription = null; constructor(private utils: UtilsService, - private fb: UntypedFormBuilder) { + private fb: UntypedFormBuilder, + private destroyRef: DestroyRef) { } registerOnChange(fn: any): void { @@ -122,24 +123,23 @@ export class QueueFormComponent implements ControlValueAccessor, OnInit, OnDestr duplicateMsgToAllPartitions: [false] }) }); - this.valueChange$ = this.queueFormGroup.valueChanges.subscribe(() => { + this.queueFormGroup.valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateModel(); }); - this.queueFormGroup.get('name').valueChanges.subscribe((value) => { + this.queueFormGroup.get('name').valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe((value) => { this.queueFormGroup.patchValue({topic: `tb_rule_engine.${value}`}); }); - this.queueFormGroup.get('submitStrategy').get('type').valueChanges.subscribe(() => { + this.queueFormGroup.get('submitStrategy').get('type').valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.submitStrategyTypeChanged(); }); } - ngOnDestroy() { - if (this.valueChange$) { - this.valueChange$.unsubscribe(); - this.valueChange$ = null; - } - } - setDisabledState(isDisabled: boolean): void { this.disabled = isDisabled; if (this.disabled) { diff --git a/ui-ngx/src/app/modules/home/components/relation/relation-dialog.component.ts b/ui-ngx/src/app/modules/home/components/relation/relation-dialog.component.ts index a8553c1b7c..28d02c5ba2 100644 --- a/ui-ngx/src/app/modules/home/components/relation/relation-dialog.component.ts +++ b/ui-ngx/src/app/modules/home/components/relation/relation-dialog.component.ts @@ -14,7 +14,7 @@ /// limitations under the License. /// -import { Component, Inject, OnInit, SkipSelf, ViewChild } from '@angular/core'; +import { Component, DestroyRef, Inject, OnInit, SkipSelf, ViewChild } from '@angular/core'; import { ErrorStateMatcher } from '@angular/material/core'; import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; import { Store } from '@ngrx/store'; @@ -32,6 +32,7 @@ import { forkJoin, Observable } from 'rxjs'; import { JsonObjectEditComponent } from '@shared/components/json-object-edit.component'; import { Router } from '@angular/router'; import { DialogComponent } from '@shared/components/dialog.component'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; export interface RelationDialogData { isAdd: boolean; @@ -65,7 +66,8 @@ export class RelationDialogComponent extends DialogComponent, - public fb: UntypedFormBuilder) { + public fb: UntypedFormBuilder, + private destroyRef: DestroyRef) { super(store, router, dialogRef); this.isAdd = data.isAdd; this.direction = data.direction; @@ -83,7 +85,9 @@ export class RelationDialogComponent extends DialogComponent { this.submitted = false; } diff --git a/ui-ngx/src/app/modules/home/components/sms/aws-sns-provider-configuration.component.ts b/ui-ngx/src/app/modules/home/components/sms/aws-sns-provider-configuration.component.ts index add25cda9f..e6af9d8613 100644 --- a/ui-ngx/src/app/modules/home/components/sms/aws-sns-provider-configuration.component.ts +++ b/ui-ngx/src/app/modules/home/components/sms/aws-sns-provider-configuration.component.ts @@ -14,7 +14,7 @@ /// limitations under the License. /// -import { Component, forwardRef, Input, OnInit } from '@angular/core'; +import { Component, DestroyRef, forwardRef, Input, OnInit } from '@angular/core'; import { ControlValueAccessor, UntypedFormBuilder, UntypedFormGroup, NG_VALUE_ACCESSOR, Validators } from '@angular/forms'; import { Store } from '@ngrx/store'; import { AppState } from '@app/core/core.state'; @@ -25,6 +25,7 @@ import { SmsProviderConfiguration, SmsProviderType } from '@shared/models/settings.models'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; @Component({ selector: 'tb-aws-sns-provider-configuration', @@ -57,7 +58,8 @@ export class AwsSnsProviderConfigurationComponent implements ControlValueAccesso private propagateChange = (v: any) => { }; constructor(private store: Store, - private fb: UntypedFormBuilder) { + private fb: UntypedFormBuilder, + private destroyRef: DestroyRef) { } registerOnChange(fn: any): void { @@ -73,7 +75,9 @@ export class AwsSnsProviderConfigurationComponent implements ControlValueAccesso secretAccessKey: [null, [Validators.required]], region: [null, [Validators.required]] }); - this.awsSnsProviderConfigurationFormGroup.valueChanges.subscribe(() => { + this.awsSnsProviderConfigurationFormGroup.valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateModel(); }); } diff --git a/ui-ngx/src/app/modules/home/components/sms/smpp-sms-provider-configuration.component.ts b/ui-ngx/src/app/modules/home/components/sms/smpp-sms-provider-configuration.component.ts index 5fb4d2208b..7a4c1c0975 100644 --- a/ui-ngx/src/app/modules/home/components/sms/smpp-sms-provider-configuration.component.ts +++ b/ui-ngx/src/app/modules/home/components/sms/smpp-sms-provider-configuration.component.ts @@ -14,7 +14,7 @@ /// limitations under the License. /// -import { Component, forwardRef, Input, OnInit } from '@angular/core'; +import { Component, DestroyRef, forwardRef, Input, OnInit } from '@angular/core'; import { ControlValueAccessor, UntypedFormBuilder, UntypedFormGroup, NG_VALUE_ACCESSOR, Validators } from '@angular/forms'; import { AwsSnsSmsProviderConfiguration, @@ -33,6 +33,7 @@ import { } from '@shared/models/settings.models'; import { isDefinedAndNotNull } from '@core/utils'; import { coerceBooleanProperty } from '@angular/cdk/coercion'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; @Component({ selector: 'tb-smpp-sms-provider-configuration', @@ -46,7 +47,8 @@ import { coerceBooleanProperty } from '@angular/cdk/coercion'; }) export class SmppSmsProviderConfigurationComponent implements ControlValueAccessor, OnInit{ - constructor(private fb: UntypedFormBuilder) { + constructor(private fb: UntypedFormBuilder, + private destroyRef: DestroyRef) { } private requiredValue: boolean; @@ -98,7 +100,9 @@ export class SmppSmsProviderConfigurationComponent implements ControlValueAcces codingScheme: [null, []], }); - this.smppSmsProviderConfigurationFormGroup.valueChanges.subscribe(() => { + this.smppSmsProviderConfigurationFormGroup.valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateValue(); }); } diff --git a/ui-ngx/src/app/modules/home/components/sms/sms-provider-configuration.component.ts b/ui-ngx/src/app/modules/home/components/sms/sms-provider-configuration.component.ts index 0a10859d4b..b167121c38 100644 --- a/ui-ngx/src/app/modules/home/components/sms/sms-provider-configuration.component.ts +++ b/ui-ngx/src/app/modules/home/components/sms/sms-provider-configuration.component.ts @@ -14,7 +14,7 @@ /// limitations under the License. /// -import { Component, forwardRef, Input, OnInit } from '@angular/core'; +import { Component, DestroyRef, forwardRef, Input, OnInit } from '@angular/core'; import { ControlValueAccessor, UntypedFormBuilder, UntypedFormGroup, NG_VALUE_ACCESSOR, Validators } from '@angular/forms'; import { Store } from '@ngrx/store'; import { AppState } from '@app/core/core.state'; @@ -31,6 +31,7 @@ import { SmsProviderType, smsProviderTypeTranslationMap } from '@shared/models/settings.models'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; @Component({ selector: 'tb-sms-provider-configuration', @@ -65,7 +66,8 @@ export class SmsProviderConfigurationComponent implements ControlValueAccessor, private propagateChange = (v: any) => { }; constructor(private store: Store, - private fb: UntypedFormBuilder) { + private fb: UntypedFormBuilder, + private destroyRef: DestroyRef) { } registerOnChange(fn: any): void { @@ -80,10 +82,14 @@ export class SmsProviderConfigurationComponent implements ControlValueAccessor, type: [null, Validators.required], configuration: [null, smsProviderConfigurationValidator(true)] }); - this.smsProviderConfigurationFormGroup.valueChanges.subscribe(() => { + this.smsProviderConfigurationFormGroup.valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateModel(); }); - this.smsProviderConfigurationFormGroup.get('type').valueChanges.subscribe(() => { + this.smsProviderConfigurationFormGroup.get('type').valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.smsProviderTypeChanged(); }); } diff --git a/ui-ngx/src/app/modules/home/components/sms/twilio-sms-provider-configuration.component.ts b/ui-ngx/src/app/modules/home/components/sms/twilio-sms-provider-configuration.component.ts index f8a73e60ca..5fb010794a 100644 --- a/ui-ngx/src/app/modules/home/components/sms/twilio-sms-provider-configuration.component.ts +++ b/ui-ngx/src/app/modules/home/components/sms/twilio-sms-provider-configuration.component.ts @@ -14,7 +14,7 @@ /// limitations under the License. /// -import { Component, forwardRef, Input, OnInit } from '@angular/core'; +import { Component, DestroyRef, forwardRef, Input, OnInit } from '@angular/core'; import { ControlValueAccessor, UntypedFormBuilder, UntypedFormGroup, NG_VALUE_ACCESSOR, Validators } from '@angular/forms'; import { Store } from '@ngrx/store'; import { AppState } from '@app/core/core.state'; @@ -26,6 +26,7 @@ import { SmsProviderType, TwilioSmsProviderConfiguration } from '@shared/models/settings.models'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; @Component({ selector: 'tb-twilio-sms-provider-configuration', @@ -60,7 +61,8 @@ export class TwilioSmsProviderConfigurationComponent implements ControlValueAcce private propagateChange = (v: any) => { }; constructor(private store: Store, - private fb: UntypedFormBuilder) { + private fb: UntypedFormBuilder, + private destroyRef: DestroyRef) { } registerOnChange(fn: any): void { @@ -76,7 +78,9 @@ export class TwilioSmsProviderConfigurationComponent implements ControlValueAcce accountSid: [null, Validators.required], accountToken: [null, Validators.required] }); - this.twilioSmsProviderConfigurationFormGroup.valueChanges.subscribe(() => { + this.twilioSmsProviderConfigurationFormGroup.valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateModel(); }); } diff --git a/ui-ngx/src/app/modules/home/components/vc/entity-types-version-create.component.ts b/ui-ngx/src/app/modules/home/components/vc/entity-types-version-create.component.ts index 95a172ab1b..ebfea4462f 100644 --- a/ui-ngx/src/app/modules/home/components/vc/entity-types-version-create.component.ts +++ b/ui-ngx/src/app/modules/home/components/vc/entity-types-version-create.component.ts @@ -14,7 +14,7 @@ /// limitations under the License. /// -import { Component, forwardRef, Input, OnInit } from '@angular/core'; +import { Component, DestroyRef, forwardRef, Input, OnInit } from '@angular/core'; import { AbstractControl, ControlValueAccessor, @@ -40,6 +40,7 @@ import { AppState } from '@core/core.state'; import { TranslateService } from '@ngx-translate/core'; import { EntityType, entityTypeTranslations } from '@shared/models/entity-type.models'; import { isDefinedAndNotNull } from '@core/utils'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; @Component({ selector: 'tb-entity-types-version-create', @@ -80,7 +81,8 @@ export class EntityTypesVersionCreateComponent extends PageComponent implements constructor(protected store: Store, private translate: TranslateService, - private fb: UntypedFormBuilder) { + private fb: UntypedFormBuilder, + private destroyRef: DestroyRef) { super(store); } @@ -88,7 +90,9 @@ export class EntityTypesVersionCreateComponent extends PageComponent implements this.entityTypesVersionCreateFormGroup = this.fb.group({ entityTypes: this.fb.array([], []) }); - this.entityTypesVersionCreateFormGroup.valueChanges.subscribe(() => { + this.entityTypesVersionCreateFormGroup.valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateModel(); }); } @@ -152,7 +156,9 @@ export class EntityTypesVersionCreateComponent extends PageComponent implements } ); this.updateEntityTypeValidators(entityTypeControl); - entityTypeControl.get('config.allEntities').valueChanges.subscribe(() => { + entityTypeControl.get('config.allEntities').valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateEntityTypeValidators(entityTypeControl); }); return entityTypeControl; diff --git a/ui-ngx/src/app/modules/home/components/vc/entity-types-version-load.component.ts b/ui-ngx/src/app/modules/home/components/vc/entity-types-version-load.component.ts index c663745954..5275daecd5 100644 --- a/ui-ngx/src/app/modules/home/components/vc/entity-types-version-load.component.ts +++ b/ui-ngx/src/app/modules/home/components/vc/entity-types-version-load.component.ts @@ -14,7 +14,7 @@ /// limitations under the License. /// -import { Component, forwardRef, Input, OnInit, Renderer2, ViewContainerRef } from '@angular/core'; +import { Component, DestroyRef, forwardRef, Input, OnInit, Renderer2, ViewContainerRef } from '@angular/core'; import { AbstractControl, ControlValueAccessor, @@ -40,6 +40,7 @@ import { EntityType, entityTypeTranslations } from '@shared/models/entity-type.m import { MatCheckbox } from '@angular/material/checkbox'; import { TbPopoverService } from '@shared/components/popover.service'; import { RemoveOtherEntitiesConfirmComponent } from '@home/components/vc/remove-other-entities-confirm.component'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; @Component({ selector: 'tb-entity-types-version-load', @@ -79,7 +80,8 @@ export class EntityTypesVersionLoadComponent extends PageComponent implements On private popoverService: TbPopoverService, private renderer: Renderer2, private viewContainerRef: ViewContainerRef, - private fb: UntypedFormBuilder) { + private fb: UntypedFormBuilder, + private destroyRef: DestroyRef) { super(store); } @@ -87,7 +89,9 @@ export class EntityTypesVersionLoadComponent extends PageComponent implements On this.entityTypesVersionLoadFormGroup = this.fb.group({ entityTypes: this.fb.array([], []) }); - this.entityTypesVersionLoadFormGroup.valueChanges.subscribe(() => { + this.entityTypesVersionLoadFormGroup.valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateModel(); }); } diff --git a/ui-ngx/src/app/modules/home/components/vc/repository-settings.component.ts b/ui-ngx/src/app/modules/home/components/vc/repository-settings.component.ts index 2cdef0dea4..d6fc7f413c 100644 --- a/ui-ngx/src/app/modules/home/components/vc/repository-settings.component.ts +++ b/ui-ngx/src/app/modules/home/components/vc/repository-settings.component.ts @@ -14,7 +14,7 @@ /// limitations under the License. /// -import { ChangeDetectorRef, Component, Input, OnInit } from '@angular/core'; +import { ChangeDetectorRef, Component, DestroyRef, Input, OnInit } from '@angular/core'; import { PageComponent } from '@shared/components/page.component'; import { UntypedFormBuilder, UntypedFormGroup, FormGroupDirective, Validators } from '@angular/forms'; import { select, Store } from '@ngrx/store'; @@ -35,6 +35,7 @@ import { catchError, mergeMap, take } from 'rxjs/operators'; import { of } from 'rxjs'; import { TbPopoverComponent } from '@shared/components/popover.component'; import { coerceBoolean } from '@shared/decorators/coercion'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; @Component({ selector: 'tb-repository-settings', @@ -71,7 +72,8 @@ export class RepositorySettingsComponent extends PageComponent implements OnInit private dialogService: DialogService, private translate: TranslateService, private cd: ChangeDetectorRef, - public fb: UntypedFormBuilder) { + public fb: UntypedFormBuilder, + private destroyRef: DestroyRef) { super(store); } @@ -89,10 +91,14 @@ export class RepositorySettingsComponent extends PageComponent implements OnInit privateKeyPassword: [null, []] }); this.updateValidators(false); - this.repositorySettingsForm.get('authMethod').valueChanges.subscribe(() => { + this.repositorySettingsForm.get('authMethod').valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateValidators(true); }); - this.repositorySettingsForm.get('privateKeyFileName').valueChanges.subscribe(() => { + this.repositorySettingsForm.get('privateKeyFileName').valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateValidators(false); }); this.store.pipe( diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/aggregated-data-key-row.component.ts b/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/aggregated-data-key-row.component.ts index f5eec3cc1a..3fb9c42449 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/aggregated-data-key-row.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/aggregated-data-key-row.component.ts @@ -17,6 +17,7 @@ import { ChangeDetectorRef, Component, + DestroyRef, EventEmitter, forwardRef, Input, @@ -53,6 +54,7 @@ import { AggregatedValueCardKeySettings } from '@home/components/widget/lib/cards/aggregated-value-card.models'; import { WidgetConfigCallbacks } from '@home/components/widget/config/widget-config.component.models'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; @Component({ selector: 'tb-aggregated-data-key-row', @@ -128,7 +130,8 @@ export class AggregatedDataKeyRowComponent implements ControlValueAccessor, OnIn private cd: ChangeDetectorRef, public translate: TranslateService, public truncate: TruncatePipe, - private widgetConfigComponent: WidgetConfigComponent) { + private widgetConfigComponent: WidgetConfigComponent, + private destroyRef: DestroyRef) { } ngOnInit() { @@ -140,7 +143,9 @@ export class AggregatedDataKeyRowComponent implements ControlValueAccessor, OnIn color: [null, []], showArrow: [null, []] }); - this.keyRowFormGroup.valueChanges.subscribe( + this.keyRowFormGroup.valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe( () => this.updateModel() ); } diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/aggregated-data-keys-panel.component.ts b/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/aggregated-data-keys-panel.component.ts index cb93e516fb..39481874e3 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/aggregated-data-keys-panel.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/aggregated-data-keys-panel.component.ts @@ -17,6 +17,7 @@ import { ChangeDetectorRef, Component, + DestroyRef, forwardRef, Input, OnChanges, @@ -39,6 +40,7 @@ import { DataKeyType } from '@shared/models/telemetry/telemetry.models'; import { UtilsService } from '@core/services/utils.service'; import { DataKeysCallbacks } from '@home/components/widget/config/data-keys.component.models'; import { aggregatedValueCardDefaultKeySettings } from '@home/components/widget/lib/cards/aggregated-value-card.models'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; @Component({ selector: 'tb-aggregated-data-keys-panel', @@ -87,14 +89,17 @@ export class AggregatedDataKeysPanelComponent implements ControlValueAccessor, O private dialog: MatDialog, private cd: ChangeDetectorRef, private utils: UtilsService, - private widgetConfigComponent: WidgetConfigComponent) { + private widgetConfigComponent: WidgetConfigComponent, + private destroyRef: DestroyRef) { } ngOnInit() { this.keysListFormGroup = this.fb.group({ keys: [this.fb.array([]), []] }); - this.keysListFormGroup.valueChanges.subscribe( + this.keysListFormGroup.valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe( (val) => this.propagateChange(this.keysListFormGroup.get('keys').value) ); this.updateParams(); diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/chart/comparison-key-row.component.ts b/ui-ngx/src/app/modules/home/components/widget/config/basic/chart/comparison-key-row.component.ts index 8836a31f8b..48ffda9c7c 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/basic/chart/comparison-key-row.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/chart/comparison-key-row.component.ts @@ -14,7 +14,7 @@ /// limitations under the License. /// -import { ChangeDetectorRef, Component, forwardRef, Input, OnInit, ViewEncapsulation } from '@angular/core'; +import { ChangeDetectorRef, Component, DestroyRef, forwardRef, Input, OnInit, ViewEncapsulation } from '@angular/core'; import { ControlValueAccessor, NG_VALUE_ACCESSOR, @@ -29,6 +29,7 @@ import { DatasourceType } from '@shared/models/widget.models'; import { deepClone } from '@core/utils'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; @Component({ selector: 'tb-comparison-key-row', @@ -60,7 +61,8 @@ export class ComparisonKeyRowComponent implements ControlValueAccessor, OnInit { private propagateChange = (_val: any) => {}; constructor(private fb: UntypedFormBuilder, - private cd: ChangeDetectorRef) { + private cd: ChangeDetectorRef, + private destroyRef: DestroyRef) { } ngOnInit() { @@ -70,10 +72,14 @@ export class ComparisonKeyRowComponent implements ControlValueAccessor, OnInit { comparisonValuesLabel: [null, []], color: [null, []] }); - this.keyRowFormGroup.valueChanges.subscribe( + this.keyRowFormGroup.valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe( () => this.updateModel() ); - this.keyRowFormGroup.get('showValuesForComparison').valueChanges.subscribe(() => this.updateValidators()); + this.keyRowFormGroup.get('showValuesForComparison').valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => this.updateValidators()); } registerOnChange(fn: any): void { diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/chart/comparison-keys-table.component.ts b/ui-ngx/src/app/modules/home/components/widget/config/basic/chart/comparison-keys-table.component.ts index b8241531b3..b605ef88e7 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/basic/chart/comparison-keys-table.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/chart/comparison-keys-table.component.ts @@ -14,7 +14,7 @@ /// limitations under the License. /// -import { Component, forwardRef, Input, OnInit, ViewEncapsulation } from '@angular/core'; +import { Component, DestroyRef, forwardRef, Input, OnInit, ViewEncapsulation } from '@angular/core'; import { AbstractControl, ControlValueAccessor, @@ -24,6 +24,7 @@ import { UntypedFormGroup } from '@angular/forms'; import { DataKey, DatasourceType } from '@shared/models/widget.models'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; @Component({ selector: 'tb-comparison-keys-table', @@ -55,14 +56,17 @@ export class ComparisonKeysTableComponent implements ControlValueAccessor, OnIni private propagateChange = (_val: any) => {}; - constructor(private fb: UntypedFormBuilder) { + constructor(private fb: UntypedFormBuilder, + private destroyRef: DestroyRef) { } ngOnInit() { this.keysListFormGroup = this.fb.group({ keys: [this.fb.array([]), []] }); - this.keysListFormGroup.valueChanges.subscribe( + this.keysListFormGroup.valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe( () => { const keys: DataKey[] = this.keysListFormGroup.get('keys').value; this.propagateChange(keys); diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/chart/time-series-chart-basic-config.component.ts b/ui-ngx/src/app/modules/home/components/widget/config/basic/chart/time-series-chart-basic-config.component.ts index 18a2e833f6..29e60afa69 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/basic/chart/time-series-chart-basic-config.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/chart/time-series-chart-basic-config.component.ts @@ -52,6 +52,7 @@ import { TimeSeriesChartYAxisId } from '@home/components/widget/lib/chart/time-series-chart.models'; import { TimeSeriesChartTooltipTrigger } from '@home/components/widget/lib/chart/time-series-chart-tooltip.models'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; @Component({ selector: 'tb-time-series-chart-basic-config', @@ -204,7 +205,9 @@ export class TimeSeriesChartBasicConfigComponent extends BasicWidgetConfigCompon if (this.chartType === TimeSeriesChartType.state) { this.timeSeriesChartWidgetConfigForm.addControl('states', this.fb.control(settings.states, [])); } - this.timeSeriesChartWidgetConfigForm.get('comparisonEnabled').valueChanges.subscribe(() => this.updateSeriesState()); + this.timeSeriesChartWidgetConfigForm.get('comparisonEnabled').valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => this.updateSeriesState()); } protected prepareOutputConfig(config: any): WidgetConfigComponentData { diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/common/data-key-row.component.ts b/ui-ngx/src/app/modules/home/components/widget/config/basic/common/data-key-row.component.ts index fdd7b292fa..d64fe7af27 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/basic/common/data-key-row.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/common/data-key-row.component.ts @@ -17,6 +17,7 @@ import { ChangeDetectorRef, Component, + DestroyRef, EventEmitter, forwardRef, Input, @@ -66,6 +67,7 @@ import { TimeSeriesChartYAxisId } from '@home/components/widget/lib/chart/time-series-chart.models'; import { WidgetConfigCallbacks } from '@home/components/widget/config/widget-config.component.models'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; export const dataKeyValid = (key: DataKey): boolean => !!key && !!key.type && !!key.name; @@ -234,7 +236,8 @@ export class DataKeyRowComponent implements ControlValueAccessor, OnInit, OnChan constructor(private fb: UntypedFormBuilder, private dialog: MatDialog, private cd: ChangeDetectorRef, - private widgetConfigComponent: WidgetConfigComponent) { + private widgetConfigComponent: WidgetConfigComponent, + private destroyRef: DestroyRef) { } ngOnInit() { @@ -252,7 +255,9 @@ export class DataKeyRowComponent implements ControlValueAccessor, OnInit, OnChan this.keyRowFormGroup.addControl('yAxis', this.fb.control(null)); this.keyRowFormGroup.addControl('timeSeriesType', this.fb.control(null)); } - merge(this.keyFormControl.valueChanges, this.keyRowFormGroup.valueChanges).subscribe( + merge(this.keyFormControl.valueChanges, this.keyRowFormGroup.valueChanges).pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe( () => this.updateModel() ); } diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/common/data-keys-panel.component.ts b/ui-ngx/src/app/modules/home/components/widget/config/basic/common/data-keys-panel.component.ts index 67ed19b2d2..c23bcfed7b 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/basic/common/data-keys-panel.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/common/data-keys-panel.component.ts @@ -17,6 +17,7 @@ import { ChangeDetectorRef, Component, + DestroyRef, forwardRef, Input, OnChanges, @@ -45,6 +46,7 @@ import { UtilsService } from '@core/services/utils.service'; import { DataKeysCallbacks, DataKeySettingsFunction } from '@home/components/widget/config/data-keys.component.models'; import { coerceBoolean } from '@shared/decorators/coercion'; import { TimeSeriesChartYAxisId } from '@home/components/widget/lib/chart/time-series-chart.models'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; @Component({ selector: 'tb-data-keys-panel', @@ -180,14 +182,17 @@ export class DataKeysPanelComponent implements ControlValueAccessor, OnInit, OnC private dialog: MatDialog, private cd: ChangeDetectorRef, private utils: UtilsService, - private widgetConfigComponent: WidgetConfigComponent) { + private widgetConfigComponent: WidgetConfigComponent, + private destroyRef: DestroyRef) { } ngOnInit() { this.keysListFormGroup = this.fb.group({ keys: [this.fb.array([]), []] }); - this.keysListFormGroup.valueChanges.subscribe( + this.keysListFormGroup.valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe( () => { let keys: DataKey[] = this.keysListFormGroup.get('keys').value; if (keys) { diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/common/widget-actions-panel.component.ts b/ui-ngx/src/app/modules/home/components/widget/config/basic/common/widget-actions-panel.component.ts index 82d1fa4094..37c5ab7f01 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/basic/common/widget-actions-panel.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/common/widget-actions-panel.component.ts @@ -14,7 +14,7 @@ /// limitations under the License. /// -import { ChangeDetectorRef, Component, forwardRef, Input, OnInit } from '@angular/core'; +import { ChangeDetectorRef, Component, DestroyRef, forwardRef, Input, OnInit } from '@angular/core'; import { ControlValueAccessor, NG_VALUE_ACCESSOR, UntypedFormBuilder, UntypedFormGroup } from '@angular/forms'; import { WidgetConfigComponent } from '@home/components/widget/widget-config.component'; import { WidgetActionsData } from '@home/components/widget/action/manage-widget-actions.component.models'; @@ -25,6 +25,7 @@ import { } from '@home/components/widget/action/manage-widget-actions-dialog.component'; import { deepClone } from '@core/utils'; import { MatDialog } from '@angular/material/dialog'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; @Component({ selector: 'tb-widget-actions-panel', @@ -50,14 +51,17 @@ export class WidgetActionsPanelComponent implements ControlValueAccessor, OnInit constructor(private fb: UntypedFormBuilder, private dialog: MatDialog, private cd: ChangeDetectorRef, - private widgetConfigComponent: WidgetConfigComponent) { + private widgetConfigComponent: WidgetConfigComponent, + private destroyRef: DestroyRef) { } ngOnInit() { this.actionsFormGroup = this.fb.group({ actions: [null, []] }); - this.actionsFormGroup.get('actions').valueChanges.subscribe( + this.actionsFormGroup.get('actions').valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe( (val) => this.propagateChange(val) ); } diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/indicator/liquid-level-card-basic-config.component.ts b/ui-ngx/src/app/modules/home/components/widget/config/basic/indicator/liquid-level-card-basic-config.component.ts index 2a9994486c..3f7baa5d7c 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/basic/indicator/liquid-level-card-basic-config.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/indicator/liquid-level-card-basic-config.component.ts @@ -63,6 +63,7 @@ import { map, share, tap } from 'rxjs/operators'; import { Observable, of, ReplaySubject } from 'rxjs'; import { ResourcesService } from '@core/services/resources.service'; import { UtilsService } from '@core/services/utils.service'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; @Component({ selector: 'liquid-level-card-basic-config', @@ -228,7 +229,9 @@ export class LiquidLevelCardBasicConfigComponent extends BasicWidgetConfigCompon actions: [configData.config.actions || {}, []] }); - this.levelCardWidgetConfigForm.get('selectedShape').valueChanges.subscribe(() => { + this.levelCardWidgetConfigForm.get('selectedShape').valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.cd.detectChanges(); this.layoutsImageCardsSelect?.imageCardsSelectOptions.notifyOnChanges(); }); diff --git a/ui-ngx/src/app/modules/home/components/widget/config/data-key-config.component.ts b/ui-ngx/src/app/modules/home/components/widget/config/data-key-config.component.ts index 32e8727225..4c8fc5bc67 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/data-key-config.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/config/data-key-config.component.ts @@ -14,7 +14,7 @@ /// limitations under the License. /// -import { Component, ElementRef, forwardRef, Input, OnInit, ViewChild } from '@angular/core'; +import { Component, DestroyRef, ElementRef, forwardRef, Input, OnInit, ViewChild } from '@angular/core'; import { PageComponent } from '@shared/components/page.component'; import { Store } from '@ngrx/store'; import { AppState } from '@core/core.state'; @@ -58,6 +58,7 @@ import { WidgetConfigComponentData } from '@home/models/widget-component.models' import { WidgetComponentService } from '@home/components/widget/widget-component.service'; import { WidgetConfigCallbacks } from '@home/components/widget/config/widget-config.component.models'; import { isNotEmptyTbFunction, TbFunction } from '@shared/models/js-function.models'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; @Component({ selector: 'tb-data-key-config', @@ -188,7 +189,8 @@ export class DataKeyConfigComponent extends PageComponent implements OnInit, Con private translate: TranslateService, private widgetService: WidgetService, private widgetComponentService: WidgetComponentService, - private fb: UntypedFormBuilder) { + private fb: UntypedFormBuilder, + private destroyRef: DestroyRef) { super(store); this.functionScopeVariables = this.widgetService.getWidgetScopeVariables(); } @@ -240,7 +242,9 @@ export class DataKeyConfigComponent extends PageComponent implements OnInit, Con this.dataKeySettingsFormGroup = this.fb.group({ settings: [null, []] }); - this.dataKeySettingsFormGroup.valueChanges.subscribe(() => { + this.dataKeySettingsFormGroup.valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateModel(); }); } @@ -260,7 +264,9 @@ export class DataKeyConfigComponent extends PageComponent implements OnInit, Con postFuncBody: [null, []] }); - this.dataKeyFormGroup.get('aggregationType').valueChanges.subscribe( + this.dataKeyFormGroup.get('aggregationType').valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe( (aggType) => { if (!this.dataKeyFormGroup.get('label').dirty) { let newLabel = this.dataKeyFormGroup.get('name').value; @@ -274,23 +280,31 @@ export class DataKeyConfigComponent extends PageComponent implements OnInit, Con } ); - this.dataKeyFormGroup.get('comparisonEnabled').valueChanges.subscribe( + this.dataKeyFormGroup.get('comparisonEnabled').valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe( () => { this.updateComparisonValues(); } ); - this.dataKeyFormGroup.get('timeForComparison').valueChanges.subscribe( + this.dataKeyFormGroup.get('timeForComparison').valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe( () => { this.updateComparisonValues(); } ); - this.dataKeyFormGroup.valueChanges.subscribe(() => { + this.dataKeyFormGroup.valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateModel(); }); - this.dataKeyFormGroup.get('usePostProcessing').valueChanges.subscribe((usePostProcessing: boolean) => { + this.dataKeyFormGroup.get('usePostProcessing').valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe((usePostProcessing: boolean) => { const postFuncBody: TbFunction = this.dataKeyFormGroup.get('postFuncBody').value; if (usePostProcessing && !isNotEmptyTbFunction(postFuncBody)) { this.dataKeyFormGroup.get('postFuncBody').patchValue('return value;'); diff --git a/ui-ngx/src/app/modules/home/components/widget/config/datasource.component.ts b/ui-ngx/src/app/modules/home/components/widget/config/datasource.component.ts index 6038982d48..a138ed491d 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/datasource.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/config/datasource.component.ts @@ -14,7 +14,7 @@ /// limitations under the License. /// -import { Component, forwardRef, Input, OnInit, Optional } from '@angular/core'; +import { Component, DestroyRef, forwardRef, Input, OnInit, Optional } from '@angular/core'; import { ControlValueAccessor, NG_VALIDATORS, @@ -43,6 +43,7 @@ import { DataKeysCallbacks, DataKeySettingsFunction } from '@home/components/wid import { EntityType } from '@shared/models/entity-type.models'; import { DatasourcesComponent } from '@home/components/widget/config/datasources.component'; import { WidgetConfigCallbacks } from '@home/components/widget/config/widget-config.component.models'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; @Component({ selector: 'tb-datasource', @@ -188,7 +189,8 @@ export class DatasourceComponent implements ControlValueAccessor, OnInit, Valida constructor(private fb: UntypedFormBuilder, @Optional() private datasourcesComponent: DatasourcesComponent, - private widgetConfigComponent: WidgetConfigComponent) { + private widgetConfigComponent: WidgetConfigComponent, + private destroyRef: DestroyRef) { } registerOnChange(fn: any): void { @@ -238,10 +240,14 @@ export class DatasourceComponent implements ControlValueAccessor, OnInit, Valida if (this.hasAdditionalLatestDataKeys) { this.datasourceFormGroup.addControl('latestDataKeys', this.fb.control(null)); } - this.datasourceFormGroup.get('type').valueChanges.subscribe(() => { + this.datasourceFormGroup.get('type').valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateValidators(); }); - this.datasourceFormGroup.valueChanges.subscribe( + this.datasourceFormGroup.valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe( () => { this.datasourceUpdated(this.datasourceFormGroup.value); } diff --git a/ui-ngx/src/app/modules/home/components/widget/config/datasources.component.ts b/ui-ngx/src/app/modules/home/components/widget/config/datasources.component.ts index 6ad1972886..41198127af 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/datasources.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/config/datasources.component.ts @@ -14,7 +14,7 @@ /// limitations under the License. /// -import { Component, forwardRef, Input, OnChanges, OnInit, SimpleChanges } from '@angular/core'; +import { Component, DestroyRef, forwardRef, Input, OnChanges, OnInit, SimpleChanges } from '@angular/core'; import { AbstractControl, ControlValueAccessor, @@ -42,6 +42,7 @@ import { UtilsService } from '@core/services/utils.service'; import { DataKeysCallbacks, DataKeySettingsFunction } from '@home/components/widget/config/data-keys.component.models'; import { TranslateService } from '@ngx-translate/core'; import { coerceBoolean } from '@shared/decorators/coercion'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; @Component({ selector: 'tb-datasources', @@ -149,7 +150,8 @@ export class DatasourcesComponent implements ControlValueAccessor, OnInit, Valid constructor(private fb: UntypedFormBuilder, private utils: UtilsService, public translate: TranslateService, - private widgetConfigComponent: WidgetConfigComponent) { + private widgetConfigComponent: WidgetConfigComponent, + private destroyRef: DestroyRef) { } registerOnChange(fn: any): void { @@ -177,7 +179,9 @@ export class DatasourcesComponent implements ControlValueAccessor, OnInit, Valid this.datasourcesFormGroup = this.fb.group({ datasources: this.fb.array([]) }); - this.datasourcesFormGroup.valueChanges.subscribe( + this.datasourcesFormGroup.valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe( () => { this.datasourcesUpdated(this.datasourcesFormGroup.get('datasources').value); } diff --git a/ui-ngx/src/app/modules/home/components/widget/config/target-device.component.ts b/ui-ngx/src/app/modules/home/components/widget/config/target-device.component.ts index 58893cb2a7..14e3187f61 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/target-device.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/config/target-device.component.ts @@ -24,7 +24,7 @@ import { Validator, Validators } from '@angular/forms'; -import { Component, forwardRef, Input, OnInit } from '@angular/core'; +import { Component, DestroyRef, forwardRef, Input, OnInit } from '@angular/core'; import { UtilsService } from '@core/services/utils.service'; import { TranslateService } from '@ngx-translate/core'; import { WidgetConfigComponent } from '@home/components/widget/widget-config.component'; @@ -32,6 +32,7 @@ import { TargetDevice, TargetDeviceType } from '@shared/models/widget.models'; import { EntityType } from '@shared/models/entity-type.models'; import { IAliasController } from '@core/api/widget-api.models'; import { EntityAliasSelectCallbacks } from '@home/components/alias/entity-alias-select.component.models'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; @Component({ selector: 'tb-target-device', @@ -80,7 +81,8 @@ export class TargetDeviceComponent implements ControlValueAccessor, OnInit, Vali constructor(private fb: UntypedFormBuilder, private utils: UtilsService, public translate: TranslateService, - private widgetConfigComponent: WidgetConfigComponent) { + private widgetConfigComponent: WidgetConfigComponent, + private destroyRef: DestroyRef) { } registerOnChange(fn: any): void { @@ -111,10 +113,14 @@ export class TargetDeviceComponent implements ControlValueAccessor, OnInit, Vali deviceId: [null, (!this.widgetEditMode && !this.targetDeviceOptional) ? [Validators.required] : []], entityAliasId: [null, (!this.widgetEditMode && !this.targetDeviceOptional) ? [Validators.required] : []] }); - this.targetDeviceFormGroup.get('type').valueChanges.subscribe(() => { + this.targetDeviceFormGroup.get('type').valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateValidators(); }); - this.targetDeviceFormGroup.valueChanges.subscribe( + this.targetDeviceFormGroup.valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe( () => { this.targetDeviceUpdated(this.targetDeviceFormGroup.value); } diff --git a/ui-ngx/src/app/modules/home/components/widget/config/timewindow-config-panel.component.ts b/ui-ngx/src/app/modules/home/components/widget/config/timewindow-config-panel.component.ts index 4ab2de5aea..6e2a34d6d7 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/timewindow-config-panel.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/config/timewindow-config-panel.component.ts @@ -14,7 +14,7 @@ /// limitations under the License. /// -import { Component, forwardRef, Input, OnInit } from '@angular/core'; +import { Component, DestroyRef, forwardRef, Input, OnInit } from '@angular/core'; import { ControlValueAccessor, NG_VALUE_ACCESSOR, UntypedFormBuilder, UntypedFormGroup } from '@angular/forms'; import { WidgetConfigComponent } from '@home/components/widget/widget-config.component'; import { WidgetConfig, widgetType } from '@shared/models/widget.models'; @@ -23,6 +23,7 @@ import { TranslateService } from '@ngx-translate/core'; import { coerceBoolean } from '@shared/decorators/coercion'; import { isDefined } from '@core/utils'; import { TimewindowStyle } from '@shared/models/widget-settings.models'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; export interface TimewindowConfigData { useDashboardTimewindow: boolean; @@ -81,7 +82,8 @@ export class TimewindowConfigPanelComponent implements ControlValueAccessor, OnI constructor(private fb: UntypedFormBuilder, public translate: TranslateService, - private widgetConfigComponent: WidgetConfigComponent) { + private widgetConfigComponent: WidgetConfigComponent, + private destroyRef: DestroyRef) { } ngOnInit() { @@ -91,13 +93,19 @@ export class TimewindowConfigPanelComponent implements ControlValueAccessor, OnI timewindow: [null, []], timewindowStyle: [null, []] }); - this.timewindowConfig.valueChanges.subscribe( + this.timewindowConfig.valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe( () => this.propagateChange(this.timewindowConfig.getRawValue()) ); - this.timewindowConfig.get('useDashboardTimewindow').valueChanges.subscribe(() => { + this.timewindowConfig.get('useDashboardTimewindow').valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateTimewindowConfigEnabledState(); }); - this.timewindowConfig.get('displayTimewindow').valueChanges.subscribe(() => { + this.timewindowConfig.get('displayTimewindow').valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateTimewindowConfigEnabledState(); }); } diff --git a/ui-ngx/src/app/modules/home/components/widget/config/timewindow-style-panel.component.ts b/ui-ngx/src/app/modules/home/components/widget/config/timewindow-style-panel.component.ts index a70bcf196f..664108a783 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/timewindow-style-panel.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/config/timewindow-style-panel.component.ts @@ -14,7 +14,7 @@ /// limitations under the License. /// -import { Component, EventEmitter, Input, OnInit, Output, ViewEncapsulation } from '@angular/core'; +import { Component, DestroyRef, EventEmitter, Input, OnInit, Output, ViewEncapsulation } from '@angular/core'; import { PageComponent } from '@shared/components/page.component'; import { defaultTimewindowStyle, TimewindowStyle } from '@shared/models/widget-settings.models'; import { TbPopoverComponent } from '@shared/components/popover.component'; @@ -23,6 +23,7 @@ import { Store } from '@ngrx/store'; import { AppState } from '@core/core.state'; import { Timewindow } from '@shared/models/time/time.models'; import { deepClone } from '@core/utils'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; @Component({ selector: 'tb-timewindow-style-panel', @@ -50,7 +51,8 @@ export class TimewindowStylePanelComponent extends PageComponent implements OnIn previewTimewindowStyle: TimewindowStyle; constructor(private fb: UntypedFormBuilder, - protected store: Store) { + protected store: Store, + private destroyRef: DestroyRef) { super(store); } @@ -69,13 +71,17 @@ export class TimewindowStylePanelComponent extends PageComponent implements OnIn ); this.updatePreviewStyle(this.timewindowStyle); this.updateTimewindowStyleEnabledState(); - this.timewindowStyleFormGroup.valueChanges.subscribe((timewindowStyle: TimewindowStyle) => { + this.timewindowStyleFormGroup.valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe((timewindowStyle: TimewindowStyle) => { if (this.timewindowStyleFormGroup.valid) { this.updatePreviewStyle(timewindowStyle); setTimeout(() => {this.popover?.updatePosition();}, 0); } }); - this.timewindowStyleFormGroup.get('showIcon').valueChanges.subscribe(() => { + this.timewindowStyleFormGroup.get('showIcon').valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateTimewindowStyleEnabledState(); }); } diff --git a/ui-ngx/src/app/modules/home/components/widget/config/widget-config.component.models.ts b/ui-ngx/src/app/modules/home/components/widget/config/widget-config.component.models.ts index f3807d319d..cea4ca85c9 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/widget-config.component.models.ts +++ b/ui-ngx/src/app/modules/home/components/widget/config/widget-config.component.models.ts @@ -18,7 +18,7 @@ import { WidgetActionCallbacks } from '@home/components/widget/action/manage-wid import { DatasourceCallbacks } from '@home/components/widget/config/datasource.component.models'; import { WidgetConfigComponentData } from '@home/models/widget-component.models'; import { Observable } from 'rxjs'; -import { AfterViewInit, Directive, EventEmitter, Inject, OnInit } from '@angular/core'; +import { AfterViewInit, DestroyRef, Directive, EventEmitter, inject, Inject, OnInit } from '@angular/core'; import { PageComponent } from '@shared/components/page.component'; import { Store } from '@ngrx/store'; import { AppState } from '@core/core.state'; @@ -27,6 +27,7 @@ import { DataKey, DatasourceType, WidgetConfigMode, widgetType } from '@shared/m import { WidgetConfigComponent } from '@home/components/widget/widget-config.component'; import { isDefinedAndNotNull } from '@core/utils'; import { IAliasController } from '@core/api/widget-api.models'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; export type WidgetConfigCallbacks = DatasourceCallbacks & WidgetActionCallbacks; @@ -77,6 +78,8 @@ export abstract class BasicWidgetConfigComponent extends PageComponent implement widgetConfigChangedEmitter = new EventEmitter(); widgetConfigChanged = this.widgetConfigChangedEmitter.asObservable(); + protected destroyRef = inject(DestroyRef); + protected constructor(@Inject(Store) protected store: Store, protected widgetConfigComponent: WidgetConfigComponent) { super(store); @@ -104,11 +107,15 @@ export abstract class BasicWidgetConfigComponent extends PageComponent implement for (const part of path) { control = control.get(part); } - control.valueChanges.subscribe(() => { + control.valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateValidators(true, trigger); }); } - this.configForm().valueChanges.subscribe(() => { + this.configForm().valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.onConfigChanged(this.prepareOutputConfig(this.configForm().getRawValue())); }); } diff --git a/ui-ngx/src/app/modules/home/components/widget/config/widget-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/config/widget-settings.component.ts index d8060d7d0e..9e3f711ac3 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/widget-settings.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/config/widget-settings.component.ts @@ -154,6 +154,10 @@ export class WidgetSettingsComponent implements ControlValueAccessor, OnDestroy, if (this.definedSettingsComponentRef) { this.definedSettingsComponentRef.destroy(); } + if (this.changeSubscription) { + this.changeSubscription.unsubscribe(); + this.changeSubscription = null; + } } setDisabledState(isDisabled: boolean): void { diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/json-input-widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/json-input-widget.component.ts index f60db9763d..42050c2228 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/json-input-widget.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/json-input-widget.component.ts @@ -14,7 +14,7 @@ /// limitations under the License. /// -import { Component, Input, OnInit } from '@angular/core'; +import { Component, DestroyRef, Input, OnInit } from '@angular/core'; import { PageComponent } from '@shared/components/page.component'; import { WidgetContext } from '@home/models/widget-component.models'; import { Store } from '@ngrx/store'; @@ -31,6 +31,7 @@ import { EntityType } from '@shared/models/entity-type.models'; import { createLabelFromDatasource, isDefinedAndNotNull } from '@core/utils'; import { Observable } from 'rxjs'; import { jsonRequired } from '@shared/components/json-object-edit.component'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; enum JsonInputWidgetMode { ATTRIBUTE = 'ATTRIBUTE', @@ -77,7 +78,8 @@ export class JsonInputWidgetComponent extends PageComponent implements OnInit { private utils: UtilsService, private fb: UntypedFormBuilder, private attributeService: AttributeService, - private translate: TranslateService) { + private translate: TranslateService, + private destroyRef: DestroyRef) { super(store); } @@ -137,7 +139,9 @@ export class JsonInputWidgetComponent extends PageComponent implements OnInit { this.attributeUpdateFormGroup = this.fb.group({ currentValue: [{}, validators] }); - this.attributeUpdateFormGroup.valueChanges.subscribe(() => { + this.attributeUpdateFormGroup.valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.ctx.detectChanges(); }); } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/rpc/persistent-add-dialog.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/rpc/persistent-add-dialog.component.ts index de79261d2b..8742d88411 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/rpc/persistent-add-dialog.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/rpc/persistent-add-dialog.component.ts @@ -14,7 +14,7 @@ /// limitations under the License. /// -import { Component, OnInit } from '@angular/core'; +import { Component, DestroyRef, OnInit } from '@angular/core'; import { DialogComponent } from '@shared/components/dialog.component'; import { Store } from '@ngrx/store'; import { AppState } from '@core/core.state'; @@ -23,6 +23,7 @@ import { MatDialogRef } from '@angular/material/dialog'; import { UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms'; import { RequestData } from '@shared/models/rpc.models'; import { TranslateService } from '@ngx-translate/core'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; @Component({ selector: 'tb-persistent-add-dialog', @@ -41,7 +42,8 @@ export class PersistentAddDialogComponent extends DialogComponent, private fb: UntypedFormBuilder, - private translate: TranslateService) { + private translate: TranslateService, + private destroyRef: DestroyRef) { super(store, router, dialogRef); this.persistentFormGroup = this.fb.group( @@ -62,7 +64,9 @@ export class PersistentAddDialogComponent extends DialogComponent { this.rpcMessageTypeText = this.translate.instant(`widgets.persistent-table.message-types.${this.persistentFormGroup.get('oneWayElseTwoWay').value}`); } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/label-widget-label.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/label-widget-label.component.ts index 7e47cb6433..262df80d67 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/label-widget-label.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/label-widget-label.component.ts @@ -14,13 +14,14 @@ /// limitations under the License. /// -import { Component, EventEmitter, forwardRef, Input, OnInit, Output } from '@angular/core'; +import { Component, DestroyRef, EventEmitter, forwardRef, Input, OnInit, Output } from '@angular/core'; import { ControlValueAccessor, UntypedFormBuilder, UntypedFormGroup, NG_VALUE_ACCESSOR, Validators } from '@angular/forms'; import { PageComponent } from '@shared/components/page.component'; import { Store } from '@ngrx/store'; import { AppState } from '@core/core.state'; import { TranslateService } from '@ngx-translate/core'; import { WidgetFont } from '@home/components/widget/lib/settings/common/widget-font.component'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; export interface LabelWidgetLabel { pattern: string; @@ -61,7 +62,8 @@ export class LabelWidgetLabelComponent extends PageComponent implements OnInit, constructor(protected store: Store, private translate: TranslateService, - private fb: UntypedFormBuilder) { + private fb: UntypedFormBuilder, + private destroyRef: DestroyRef) { super(store); } @@ -73,7 +75,9 @@ export class LabelWidgetLabelComponent extends PageComponent implements OnInit, backgroundColor: [null, []], font: [null, []] }); - this.labelWidgetLabelFormGroup.valueChanges.subscribe(() => { + this.labelWidgetLabelFormGroup.valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateModel(); }); } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-key-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-key-settings.component.ts index 3f31a27a58..28363dff34 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-key-settings.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-key-settings.component.ts @@ -14,7 +14,7 @@ /// limitations under the License. /// -import { Component, forwardRef, Input, OnInit } from '@angular/core'; +import { Component, DestroyRef, forwardRef, Input, OnInit } from '@angular/core'; import { AbstractControl, ControlValueAccessor, @@ -35,6 +35,7 @@ import { TranslateService } from '@ngx-translate/core'; import { WidgetService } from '@core/http/widget.service'; import { CdkDragDrop } from '@angular/cdk/drag-drop'; import { IAliasController } from 'src/app/core/api/widget-api.models'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; export function flotDataKeyDefaultSettings(chartType: ChartType): TbFlotKeySettings { const settings: TbFlotKeySettings = { @@ -128,7 +129,8 @@ export class FlotKeySettingsComponent extends PageComponent implements OnInit, C constructor(protected store: Store, private translate: TranslateService, private widgetService: WidgetService, - private fb: UntypedFormBuilder) { + private fb: UntypedFormBuilder, + private destroyRef: DestroyRef) { super(store); } @@ -189,23 +191,33 @@ export class FlotKeySettingsComponent extends PageComponent implements OnInit, C }); - this.flotKeySettingsFormGroup.get('showLines').valueChanges.subscribe(() => { + this.flotKeySettingsFormGroup.get('showLines').valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateValidators(false); }); - this.flotKeySettingsFormGroup.get('fillLines').valueChanges.subscribe(() => { + this.flotKeySettingsFormGroup.get('fillLines').valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateValidators(false); }); - this.flotKeySettingsFormGroup.get('showPoints').valueChanges.subscribe(() => { + this.flotKeySettingsFormGroup.get('showPoints').valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateValidators(false); }); - this.flotKeySettingsFormGroup.get('comparisonSettings.showValuesForComparison').valueChanges.subscribe(() => { + this.flotKeySettingsFormGroup.get('comparisonSettings.showValuesForComparison').valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateValidators(false); }); - this.flotKeySettingsFormGroup.valueChanges.subscribe(() => { + this.flotKeySettingsFormGroup.valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateModel(); }); diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-threshold.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-threshold.component.ts index b6b4c88962..2c793abc82 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-threshold.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-threshold.component.ts @@ -15,7 +15,16 @@ /// import { ValueSourceProperty } from '@home/components/widget/lib/settings/common/value-source.component'; -import { Component, EventEmitter, forwardRef, Input, OnInit, Output, ViewEncapsulation } from '@angular/core'; +import { + Component, + DestroyRef, + EventEmitter, + forwardRef, + Input, + OnInit, + Output, + ViewEncapsulation +} from '@angular/core'; import { ControlValueAccessor, NG_VALUE_ACCESSOR, @@ -28,6 +37,7 @@ import { Store } from '@ngrx/store'; import { AppState } from '@core/core.state'; import { IAliasController } from '@core/api/widget-api.models'; import { TbFlotKeyThreshold } from '@home/components/widget/lib/flot-widget.models'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; @Component({ selector: 'tb-flot-threshold', @@ -60,7 +70,8 @@ export class FlotThresholdComponent extends PageComponent implements OnInit, Con public thresholdFormGroup: UntypedFormGroup; constructor(protected store: Store, - private fb: UntypedFormBuilder) { + private fb: UntypedFormBuilder, + private destroyRef: DestroyRef) { super(store); } @@ -70,7 +81,9 @@ export class FlotThresholdComponent extends PageComponent implements OnInit, Con lineWidth: [null, [Validators.min(0)]], color: [null, []] }); - this.thresholdFormGroup.valueChanges.subscribe(() => { + this.thresholdFormGroup.valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateModel(); }); } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-widget-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-widget-settings.component.ts index 1e5e88e7cf..44b04406e7 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-widget-settings.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-widget-settings.component.ts @@ -14,7 +14,7 @@ /// limitations under the License. /// -import { Component, forwardRef, Input, OnInit } from '@angular/core'; +import { Component, DestroyRef, forwardRef, Input, OnInit } from '@angular/core'; import { AbstractControl, ControlValueAccessor, @@ -41,6 +41,7 @@ import { } from '@home/components/widget/lib/settings/chart/label-data-key.component'; import { DataKeyType } from '@shared/models/telemetry/telemetry.models'; import { defaultLegendConfig, widgetType } from '@shared/models/widget.models'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; export const flotDefaultSettings = (chartType: ChartType): Partial => { const settings: Partial = { @@ -140,7 +141,8 @@ export class FlotWidgetSettingsComponent extends PageComponent implements OnInit constructor(protected store: Store, private translate: TranslateService, private widgetService: WidgetService, - private fb: UntypedFormBuilder) { + private fb: UntypedFormBuilder, + private destroyRef: DestroyRef) { super(store); } @@ -238,34 +240,50 @@ export class FlotWidgetSettingsComponent extends PageComponent implements OnInit this.flotSettingsFormGroup.addControl('dataKeysListForLabels', this.fb.control(this.fb.array([]), [])); } - this.flotSettingsFormGroup.get('showTooltip').valueChanges.subscribe(() => { + this.flotSettingsFormGroup.get('showTooltip').valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateValidators(true); }); - this.flotSettingsFormGroup.get('xaxis.showLabels').valueChanges.subscribe(() => { + this.flotSettingsFormGroup.get('xaxis.showLabels').valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateValidators(true); }); - this.flotSettingsFormGroup.get('yaxis.showLabels').valueChanges.subscribe(() => { + this.flotSettingsFormGroup.get('yaxis.showLabels').valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateValidators(true); }); if (this.chartType === 'graph' || this.chartType === 'bar') { - this.flotSettingsFormGroup.get('showLegend').valueChanges.subscribe(() => { + this.flotSettingsFormGroup.get('showLegend').valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateValidators(true); }); - this.flotSettingsFormGroup.get('comparisonEnabled').valueChanges.subscribe(() => { + this.flotSettingsFormGroup.get('comparisonEnabled').valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateValidators(true); }); - this.flotSettingsFormGroup.get('timeForComparison').valueChanges.subscribe(() => { + this.flotSettingsFormGroup.get('timeForComparison').valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateValidators(true); }); - this.flotSettingsFormGroup.get('customLegendEnabled').valueChanges.subscribe(() => { + this.flotSettingsFormGroup.get('customLegendEnabled').valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateValidators(true); }); } - this.flotSettingsFormGroup.valueChanges.subscribe(() => { + this.flotSettingsFormGroup.valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateModel(); }); diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/label-data-key.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/label-data-key.component.ts index 793f6ea6d1..30361117a7 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/label-data-key.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/label-data-key.component.ts @@ -14,7 +14,7 @@ /// limitations under the License. /// -import { Component, EventEmitter, forwardRef, Input, OnInit, Output } from '@angular/core'; +import { Component, DestroyRef, EventEmitter, forwardRef, Input, OnInit, Output } from '@angular/core'; import { AbstractControl, ControlValueAccessor, @@ -28,6 +28,7 @@ import { Store } from '@ngrx/store'; import { AppState } from '@core/core.state'; import { TranslateService } from '@ngx-translate/core'; import { DataKeyType } from '@shared/models/telemetry/telemetry.models'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; export interface LabelDataKey { name: string; @@ -75,7 +76,8 @@ export class LabelDataKeyComponent extends PageComponent implements OnInit, Cont constructor(protected store: Store, private translate: TranslateService, - private fb: UntypedFormBuilder) { + private fb: UntypedFormBuilder, + private destroyRef: DestroyRef) { super(store); } @@ -84,7 +86,9 @@ export class LabelDataKeyComponent extends PageComponent implements OnInit, Cont name: [null, [Validators.required]], type: [DataKeyType.attribute, [Validators.required]] }); - this.labelDataKeyFormGroup.valueChanges.subscribe(() => { + this.labelDataKeyFormGroup.valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateModel(); }); } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/time-series-chart-line-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/time-series-chart-line-settings.component.ts index 2f0ca0197a..60f841a69a 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/time-series-chart-line-settings.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/time-series-chart-line-settings.component.ts @@ -14,7 +14,7 @@ /// limitations under the License. /// -import { Component, forwardRef, Input, OnInit } from '@angular/core'; +import { Component, DestroyRef, forwardRef, Input, OnInit } from '@angular/core'; import { ControlValueAccessor, NG_VALUE_ACCESSOR, @@ -41,6 +41,7 @@ import { chartShapes, chartShapeTranslations } from '@home/components/widget/lib/chart/chart.models'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; @Component({ selector: 'tb-time-series-chart-line-settings', @@ -90,7 +91,8 @@ export class TimeSeriesChartLineSettingsComponent implements OnInit, ControlValu constructor(protected store: Store, private dataKeyConfigComponent: DataKeyConfigComponent, - private fb: UntypedFormBuilder) { + private fb: UntypedFormBuilder, + private destroyRef: DestroyRef) { } ngOnInit(): void { @@ -112,14 +114,18 @@ export class TimeSeriesChartLineSettingsComponent implements OnInit, ControlValu pointSize: [null, [Validators.min(0)]], fillAreaSettings: [null, []] }); - this.lineSettingsFormGroup.valueChanges.subscribe(() => { + this.lineSettingsFormGroup.valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateModel(); }); merge(this.lineSettingsFormGroup.get('showLine').valueChanges, this.lineSettingsFormGroup.get('step').valueChanges, this.lineSettingsFormGroup.get('showPointLabel').valueChanges, - this.lineSettingsFormGroup.get('enablePointLabelBackground').valueChanges) - .subscribe(() => { + this.lineSettingsFormGroup.get('enablePointLabelBackground').valueChanges + ).pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateValidators(); }); } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/action/get-value-action-settings-panel.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/action/get-value-action-settings-panel.component.ts index 6abc51b003..a4339b7e12 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/action/get-value-action-settings-panel.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/action/get-value-action-settings-panel.component.ts @@ -14,7 +14,7 @@ /// limitations under the License. /// -import { Component, EventEmitter, Input, OnInit, Output, ViewEncapsulation } from '@angular/core'; +import { Component, DestroyRef, EventEmitter, Input, OnInit, Output, ViewEncapsulation } from '@angular/core'; import { PageComponent } from '@shared/components/page.component'; import { TbPopoverComponent } from '@shared/components/popover.component'; import { UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms'; @@ -35,6 +35,7 @@ import { IAliasController } from '@core/api/widget-api.models'; import { WidgetService } from '@core/http/widget.service'; import { AlarmSeverity, alarmSeverityTranslations } from '@shared/models/alarm.models'; import { EntityType } from '@shared/models/entity-type.models'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; @Component({ selector: 'tb-get-value-action-settings-panel', @@ -103,7 +104,8 @@ export class GetValueActionSettingsPanelComponent extends PageComponent implemen constructor(private fb: UntypedFormBuilder, private widgetService: WidgetService, - protected store: Store) { + protected store: Store, + private destroyRef: DestroyRef) { super(store); } @@ -145,7 +147,10 @@ export class GetValueActionSettingsPanelComponent extends PageComponent implemen merge(this.getValueSettingsFormGroup.get('action').valueChanges, this.getValueSettingsFormGroup.get('dataToValue').get('type').valueChanges, - this.getValueSettingsFormGroup.get('executeRpc').get('requestPersistent').valueChanges).subscribe(() => { + this.getValueSettingsFormGroup.get('executeRpc').get('requestPersistent').valueChanges + ).pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateValidators(); }); this.updateValidators(); diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/action/mobile-action-editor.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/action/mobile-action-editor.component.ts index a573023152..e949f765c6 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/action/mobile-action-editor.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/action/mobile-action-editor.component.ts @@ -14,7 +14,7 @@ /// limitations under the License. /// -import { Component, forwardRef, Input, OnInit } from '@angular/core'; +import { Component, DestroyRef, forwardRef, Input, OnInit } from '@angular/core'; import { ControlValueAccessor, NG_VALUE_ACCESSOR, @@ -42,6 +42,7 @@ import { } from '@home/components/widget/lib/settings/common/action/mobile-action-editor.models'; import { WidgetService } from '@core/http/widget.service'; import { TbFunction } from '@shared/models/js-function.models'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; @Component({ selector: 'tb-mobile-action-editor', @@ -81,7 +82,8 @@ export class MobileActionEditorComponent implements ControlValueAccessor, OnInit private propagateChange = (_v: any) => { }; constructor(private fb: UntypedFormBuilder, - private widgetService: WidgetService) { + private widgetService: WidgetService, + private destroyRef: DestroyRef) { this.functionScopeVariables = this.widgetService.getWidgetScopeVariables(); } @@ -98,14 +100,18 @@ export class MobileActionEditorComponent implements ControlValueAccessor, OnInit handleEmptyResultFunction: [null], handleErrorFunction: [null] }); - this.mobileActionFormGroup.get('type').valueChanges.subscribe((type: WidgetMobileActionType) => { + this.mobileActionFormGroup.get('type').valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe((type: WidgetMobileActionType) => { let action: WidgetMobileActionDescriptor = this.mobileActionFormGroup.value; if (this.mobileActionTypeFormGroup) { action = {...action, ...this.mobileActionTypeFormGroup.value}; } this.updateMobileActionType(type, action); }); - this.mobileActionFormGroup.valueChanges.subscribe(() => { + this.mobileActionFormGroup.valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateModel(); }); } @@ -250,7 +256,9 @@ export class MobileActionEditorComponent implements ControlValueAccessor, OnInit break; } } - this.mobileActionTypeFormGroup.valueChanges.subscribe(() => { + this.mobileActionTypeFormGroup.valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateModel(); }); } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/action/set-value-action-settings-panel.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/action/set-value-action-settings-panel.component.ts index 819ed2a3fc..48120ade8e 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/action/set-value-action-settings-panel.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/action/set-value-action-settings-panel.component.ts @@ -14,7 +14,7 @@ /// limitations under the License. /// -import { Component, EventEmitter, Input, OnInit, Output, ViewEncapsulation } from '@angular/core'; +import { Component, DestroyRef, EventEmitter, Input, OnInit, Output, ViewEncapsulation } from '@angular/core'; import { PageComponent } from '@shared/components/page.component'; import { TbPopoverComponent } from '@shared/components/popover.component'; import { UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms'; @@ -33,6 +33,7 @@ import { AttributeScope, DataKeyType, telemetryTypeTranslationsShort } from '@sh import { IAliasController } from '@core/api/widget-api.models'; import { WidgetService } from '@core/http/widget.service'; import { ValueType } from '@shared/models/constants'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; @Component({ selector: 'tb-set-value-action-settings-panel', @@ -89,7 +90,8 @@ export class SetValueActionSettingsPanelComponent extends PageComponent implemen constructor(private fb: UntypedFormBuilder, private widgetService: WidgetService, - protected store: Store) { + protected store: Store, + private destroyRef: DestroyRef) { super(store); } @@ -122,7 +124,10 @@ export class SetValueActionSettingsPanelComponent extends PageComponent implemen merge(this.setValueSettingsFormGroup.get('action').valueChanges, this.setValueSettingsFormGroup.get('valueToData').get('type').valueChanges, - this.setValueSettingsFormGroup.get('executeRpc').get('requestPersistent').valueChanges).subscribe(() => { + this.setValueSettingsFormGroup.get('executeRpc').get('requestPersistent').valueChanges + ).pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateValidators(); }); this.updateValidators(); diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/advanced-range.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/advanced-range.component.ts index bfb6433a82..a9d547974d 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/advanced-range.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/advanced-range.component.ts @@ -14,7 +14,7 @@ /// limitations under the License. /// -import { Component, EventEmitter, forwardRef, Input, OnInit, Output } from '@angular/core'; +import { Component, DestroyRef, EventEmitter, forwardRef, Input, OnInit, Output } from '@angular/core'; import { ControlValueAccessor, NG_VALUE_ACCESSOR, @@ -29,6 +29,7 @@ import { IAliasController } from '@core/api/widget-api.models'; import { AdvancedColorRange } from '@shared/models/widget-settings.models'; import { DataKeysCallbacks } from '@home/components/widget/config/data-keys.component.models'; import { Datasource } from '@shared/models/widget.models'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; @Component({ selector: 'tb-advanced-range', @@ -66,7 +67,8 @@ export class AdvancedRangeComponent extends PageComponent implements OnInit, Con public advancedRangeLevelFormGroup: UntypedFormGroup; constructor(protected store: Store, - private fb: UntypedFormBuilder) { + private fb: UntypedFormBuilder, + private destroyRef: DestroyRef) { super(store); } @@ -76,7 +78,9 @@ export class AdvancedRangeComponent extends PageComponent implements OnInit, Con to: [null, []], color: [null, [Validators.required]] }); - this.advancedRangeLevelFormGroup.valueChanges.subscribe(() => { + this.advancedRangeLevelFormGroup.valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateModel(); }); } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/auto-date-format-settings-panel.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/auto-date-format-settings-panel.component.ts index dcfc942778..7c8685ed0c 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/auto-date-format-settings-panel.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/auto-date-format-settings-panel.component.ts @@ -14,7 +14,7 @@ /// limitations under the License. /// -import { Component, EventEmitter, Input, OnInit, Output, ViewEncapsulation } from '@angular/core'; +import { Component, DestroyRef, EventEmitter, Input, OnInit, Output, ViewEncapsulation } from '@angular/core'; import { PageComponent } from '@shared/components/page.component'; import { AutoDateFormatSettings, defaultAutoDateFormatSettings, @@ -27,6 +27,7 @@ import { UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms import { Store } from '@ngrx/store'; import { AppState } from '@core/core.state'; import { DatePipe } from '@angular/common'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; @Component({ selector: 'tb-auto-date-format-settings-panel', @@ -59,7 +60,8 @@ export class AutoDateFormatSettingsPanelComponent extends PageComponent implemen constructor(private date: DatePipe, private fb: UntypedFormBuilder, - protected store: Store) { + protected store: Store, + private destroyRef: DestroyRef) { super(store); } @@ -68,7 +70,9 @@ export class AutoDateFormatSettingsPanelComponent extends PageComponent implemen for (const unit of formatTimeUnits) { this.autoDateFormatFormGroup.addControl(unit, this.fb.control(this.autoDateFormatSettings[unit] || this.defaultValues[unit], [Validators.required])); - this.autoDateFormatFormGroup.get(unit).valueChanges.subscribe((value: string) => { + this.autoDateFormatFormGroup.get(unit).valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe((value: string) => { this.previewText[unit] = this.date.transform(Date.now(), value); }); this.previewText[unit] = this.date.transform(Date.now(), this.autoDateFormatSettings[unit] || this.defaultValues[unit]); diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/background-settings-panel.component.scss b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/background-settings-panel.component.scss index 6bc83fe967..d907e20f64 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/background-settings-panel.component.scss +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/background-settings-panel.component.scss @@ -17,6 +17,8 @@ .tb-background-settings-panel { width: 620px; + min-height: 300px; + max-height: 90vh; display: flex; flex-direction: column; gap: 16px; diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/background-settings-panel.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/background-settings-panel.component.ts index c1c85a05e1..6229b25ba8 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/background-settings-panel.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/background-settings-panel.component.ts @@ -14,7 +14,16 @@ /// limitations under the License. /// -import { ChangeDetectorRef, Component, EventEmitter, Input, OnInit, Output, ViewEncapsulation } from '@angular/core'; +import { + ChangeDetectorRef, + Component, + DestroyRef, + EventEmitter, + Input, + OnInit, + Output, + ViewEncapsulation +} from '@angular/core'; import { PageComponent } from '@shared/components/page.component'; import { backgroundStyle, @@ -30,6 +39,7 @@ import { AppState } from '@core/core.state'; import { Observable } from 'rxjs'; import { ImagePipe } from '@shared/pipe/image.pipe'; import { DomSanitizer } from '@angular/platform-browser'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; @Component({ selector: 'tb-background-settings-panel', @@ -64,7 +74,8 @@ export class BackgroundSettingsPanelComponent extends PageComponent implements O private imagePipe: ImagePipe, private sanitizer: DomSanitizer, protected store: Store, - private cd: ChangeDetectorRef) { + private cd: ChangeDetectorRef, + private destroyRef: DestroyRef) { super(store); } @@ -81,13 +92,19 @@ export class BackgroundSettingsPanelComponent extends PageComponent implements O }) } ); - this.backgroundSettingsFormGroup.get('type').valueChanges.subscribe(() => { + this.backgroundSettingsFormGroup.get('type').valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { setTimeout(() => {this.popover?.updatePosition();}, 0); }); - this.backgroundSettingsFormGroup.get('overlay').get('enabled').valueChanges.subscribe(() => { + this.backgroundSettingsFormGroup.get('overlay').get('enabled').valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateValidators(); }); - this.backgroundSettingsFormGroup.valueChanges.subscribe(() => { + this.backgroundSettingsFormGroup.valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateBackgroundStyle(); }); this.updateValidators(); diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/background-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/background-settings.component.ts index 66dd774a21..828f424b51 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/background-settings.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/background-settings.component.ts @@ -110,7 +110,7 @@ export class BackgroundSettingsComponent implements OnInit, ControlValueAccessor backgroundSettings: this.modelValue }; const backgroundSettingsPanelPopover = this.popoverService.displayPopover(trigger, this.renderer, - this.viewContainerRef, BackgroundSettingsPanelComponent, ['leftOnly', 'leftTopOnly', 'leftBottomOnly'], true, null, + this.viewContainerRef, BackgroundSettingsPanelComponent, ['left'], true, null, ctx, {}, {}, {}, true); diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/button/widget-button-appearance.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/button/widget-button-appearance.component.ts index f9afc0b5d1..552de96ab9 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/button/widget-button-appearance.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/button/widget-button-appearance.component.ts @@ -14,7 +14,7 @@ /// limitations under the License. /// -import { Component, forwardRef, Input, OnInit, ViewEncapsulation } from '@angular/core'; +import { Component, DestroyRef, forwardRef, Input, OnInit, ViewEncapsulation } from '@angular/core'; import { ControlValueAccessor, NG_VALUE_ACCESSOR, UntypedFormBuilder, UntypedFormGroup } from '@angular/forms'; import { WidgetButtonAppearance, @@ -25,6 +25,7 @@ import { } from '@shared/components/button/widget-button.models'; import { merge } from 'rxjs'; import { coerceBoolean } from '@shared/decorators/coercion'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; @Component({ selector: 'tb-widget-button-appearance', @@ -72,7 +73,8 @@ export class WidgetButtonAppearanceComponent implements OnInit, ControlValueAcce private propagateChange = (_val: any) => {}; - constructor(private fb: UntypedFormBuilder) {} + constructor(private fb: UntypedFormBuilder, + private destroyRef: DestroyRef) {} ngOnInit(): void { this.appearanceFormGroup = this.fb.group({ @@ -97,12 +99,16 @@ export class WidgetButtonAppearanceComponent implements OnInit, ControlValueAcce customStyle.addControl(state, this.fb.control(null, [])); } this.appearanceFormGroup.addControl('customStyle', customStyle); - this.appearanceFormGroup.valueChanges.subscribe(() => { + this.appearanceFormGroup.valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateModel(); }); merge(this.appearanceFormGroup.get('showLabel').valueChanges, - this.appearanceFormGroup.get('showIcon').valueChanges) - .subscribe(() => { + this.appearanceFormGroup.get('showIcon').valueChanges + ).pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateValidators(); }); } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/button/widget-button-custom-style-panel.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/button/widget-button-custom-style-panel.component.ts index 5bb043b9d8..2f27026f87 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/button/widget-button-custom-style-panel.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/button/widget-button-custom-style-panel.component.ts @@ -17,6 +17,7 @@ import { ChangeDetectorRef, Component, + DestroyRef, EventEmitter, Input, OnInit, @@ -42,6 +43,7 @@ import { import { merge } from 'rxjs'; import { deepClone } from '@core/utils'; import { WidgetButtonComponent } from '@shared/components/button/widget-button.component'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; @Component({ selector: 'tb-widget-button-custom-style-panel', @@ -99,7 +101,8 @@ export class WidgetButtonCustomStylePanelComponent extends PageComponent impleme constructor(private fb: UntypedFormBuilder, protected store: Store, - private cd: ChangeDetectorRef) { + private cd: ChangeDetectorRef, + private destroyRef: DestroyRef) { super(store); } @@ -118,11 +121,15 @@ export class WidgetButtonCustomStylePanelComponent extends PageComponent impleme ); merge(this.customStyleFormGroup.get('overrideMainColor').valueChanges, this.customStyleFormGroup.get('overrideBackgroundColor').valueChanges, - this.customStyleFormGroup.get('overrideDropShadow').valueChanges) - .subscribe(() => { + this.customStyleFormGroup.get('overrideDropShadow').valueChanges + ).pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateValidators(); }); - this.customStyleFormGroup.valueChanges.subscribe(() => { + this.customStyleFormGroup.valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updatePreviewAppearance(); }); this.setStyle(this.customStyle); diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/button/widget-button-toggle-custom-style-panel.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/button/widget-button-toggle-custom-style-panel.component.ts index 98ced2dc2e..321eaa31cf 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/button/widget-button-toggle-custom-style-panel.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/button/widget-button-toggle-custom-style-panel.component.ts @@ -17,6 +17,7 @@ import { ChangeDetectorRef, Component, + DestroyRef, EventEmitter, Input, OnInit, @@ -44,6 +45,7 @@ import { widgetButtonToggleStates, widgetButtonToggleStatesTranslations } from '@home/components/widget/lib/button/segmented-button-widget.models'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; @Component({ selector: 'tb-widget-button-toggle-custom-style-panel', @@ -106,7 +108,8 @@ export class WidgetButtonToggleCustomStylePanelComponent extends PageComponent i constructor(private fb: UntypedFormBuilder, protected store: Store, - private cd: ChangeDetectorRef) { + private cd: ChangeDetectorRef, + private destroyRef: DestroyRef) { super(store); } @@ -126,11 +129,15 @@ export class WidgetButtonToggleCustomStylePanelComponent extends PageComponent i ); merge(this.customStyleFormGroup.get('overrideMainColor').valueChanges, this.customStyleFormGroup.get('overrideBackgroundColor').valueChanges, - this.customStyleFormGroup.get('overrideBorderColor').valueChanges) - .subscribe(() => { - this.updateValidators(); - }); - this.customStyleFormGroup.valueChanges.subscribe(() => { + this.customStyleFormGroup.get('overrideBorderColor').valueChanges + ).pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { + this.updateValidators(); + }); + this.customStyleFormGroup.valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updatePreviewAppearance(); }); this.setStyle(this.customStyle); diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/chart-animation-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/chart-animation-settings.component.ts index 19ccfcd18b..b0e2d107c6 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/chart-animation-settings.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/chart-animation-settings.component.ts @@ -14,7 +14,7 @@ /// limitations under the License. /// -import { Component, forwardRef, Input, OnInit } from '@angular/core'; +import { Component, DestroyRef, forwardRef, Input, OnInit } from '@angular/core'; import { ControlValueAccessor, NG_VALUE_ACCESSOR, @@ -23,6 +23,7 @@ import { Validators } from '@angular/forms'; import { chartAnimationEasings, ChartAnimationSettings } from '@home/components/widget/lib/chart/chart.models'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; @Component({ selector: 'tb-chart-animation-settings', @@ -51,7 +52,8 @@ export class ChartAnimationSettingsComponent implements OnInit, ControlValueAcce public animationSettingsFormGroup: UntypedFormGroup; - constructor(private fb: UntypedFormBuilder) { + constructor(private fb: UntypedFormBuilder, + private destroyRef: DestroyRef) { } ngOnInit(): void { @@ -65,11 +67,14 @@ export class ChartAnimationSettingsComponent implements OnInit, ControlValueAcce animationEasingUpdate: [null, []], animationDelayUpdate: [null, [Validators.min(0)]] }); - this.animationSettingsFormGroup.valueChanges.subscribe(() => { + this.animationSettingsFormGroup.valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateModel(); }); - this.animationSettingsFormGroup.get('animation').valueChanges - .subscribe(() => { + this.animationSettingsFormGroup.get('animation').valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateValidators(); }); } @@ -97,7 +102,9 @@ export class ChartAnimationSettingsComponent implements OnInit, ControlValueAcce value, {emitEvent: false} ); this.updateValidators(); - this.animationSettingsFormGroup.get('animation').valueChanges.subscribe((animation) => { + this.animationSettingsFormGroup.get('animation').valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe((animation) => { this.settingsExpanded = animation; }); } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/chart-bar-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/chart-bar-settings.component.ts index 6fef380a40..88304e2b20 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/chart-bar-settings.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/chart-bar-settings.component.ts @@ -14,7 +14,7 @@ /// limitations under the License. /// -import { Component, forwardRef, Input, OnInit, Optional } from '@angular/core'; +import { Component, DestroyRef, forwardRef, Input, OnInit, Optional } from '@angular/core'; import { ControlValueAccessor, NG_VALUE_ACCESSOR, @@ -37,6 +37,7 @@ import { pieChartLabelPositionTranslations } from '@home/components/widget/lib/chart/chart.models'; import { coerceBoolean } from '@shared/decorators/coercion'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; @Component({ selector: 'tb-chart-bar-settings', @@ -77,7 +78,8 @@ export class ChartBarSettingsComponent implements OnInit, ControlValueAccessor { constructor(protected store: Store, @Optional() private dataKeyConfigComponent: DataKeyConfigComponent, - private fb: UntypedFormBuilder) { + private fb: UntypedFormBuilder, + private destroyRef: DestroyRef) { } ngOnInit(): void { @@ -104,13 +106,17 @@ export class ChartBarSettingsComponent implements OnInit, ControlValueAccessor { this.barSettingsFormGroup.addControl('barWidth', this.fb.control(null, [Validators.min(0), Validators.max(100)])); } - this.barSettingsFormGroup.valueChanges.subscribe(() => { + this.barSettingsFormGroup.valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateModel(); }); merge(this.barSettingsFormGroup.get('showBorder').valueChanges, this.barSettingsFormGroup.get('showLabel').valueChanges, - this.barSettingsFormGroup.get('enableLabelBackground').valueChanges) - .subscribe(() => { + this.barSettingsFormGroup.get('enableLabelBackground').valueChanges + ).pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateValidators(); }); } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/chart-fill-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/chart-fill-settings.component.ts index bf02937221..6f1093b9b7 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/chart-fill-settings.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/chart-fill-settings.component.ts @@ -14,7 +14,7 @@ /// limitations under the License. /// -import { Component, forwardRef, Input, OnInit } from '@angular/core'; +import { Component, DestroyRef, forwardRef, Input, OnInit } from '@angular/core'; import { ControlValueAccessor, NG_VALUE_ACCESSOR, @@ -30,6 +30,7 @@ import { chartFillTypes, chartFillTypeTranslations } from '@home/components/widget/lib/chart/chart.models'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; @Component({ selector: 'tb-chart-fill-settings', @@ -67,7 +68,8 @@ export class ChartFillSettingsComponent implements OnInit, ControlValueAccessor public fillSettingsFormGroup: UntypedFormGroup; constructor(protected store: Store, - private fb: UntypedFormBuilder) { + private fb: UntypedFormBuilder, + private destroyRef: DestroyRef) { } ngOnInit(): void { @@ -79,10 +81,14 @@ export class ChartFillSettingsComponent implements OnInit, ControlValueAccessor end: [null, [Validators.min(0), Validators.max(100)]] }) }); - this.fillSettingsFormGroup.valueChanges.subscribe(() => { + this.fillSettingsFormGroup.valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateModel(); }); - this.fillSettingsFormGroup.get('type').valueChanges.subscribe(() => { + this.fillSettingsFormGroup.get('type').valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateValidators(); }); for (const type of chartFillTypes) { diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/time-series-chart-axis-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/time-series-chart-axis-settings.component.ts index 91fe61caa3..590d691bec 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/time-series-chart-axis-settings.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/time-series-chart-axis-settings.component.ts @@ -14,7 +14,7 @@ /// limitations under the License. /// -import { Component, forwardRef, Input, OnInit } from '@angular/core'; +import { Component, DestroyRef, forwardRef, Input, OnInit } from '@angular/core'; import { ControlValueAccessor, NG_VALUE_ACCESSOR, @@ -31,6 +31,7 @@ import { import { merge } from 'rxjs'; import { coerceBoolean } from '@shared/decorators/coercion'; import { WidgetService } from '@core/http/widget.service'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; @Component({ selector: 'tb-time-series-chart-axis-settings', @@ -85,7 +86,8 @@ export class TimeSeriesChartAxisSettingsComponent implements OnInit, ControlValu public axisSettingsFormGroup: UntypedFormGroup; constructor(private fb: UntypedFormBuilder, - private widgetService: WidgetService) { + private widgetService: WidgetService, + private destroyRef: DestroyRef) { } ngOnInit(): void { @@ -121,15 +123,19 @@ export class TimeSeriesChartAxisSettingsComponent implements OnInit, ControlValu } else if (this.axisType === 'xAxis') { this.axisSettingsFormGroup.addControl('ticksFormat', this.fb.control(null, [])); } - this.axisSettingsFormGroup.valueChanges.subscribe(() => { + this.axisSettingsFormGroup.valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateModel(); }); merge(this.axisSettingsFormGroup.get('show').valueChanges, this.axisSettingsFormGroup.get('showTickLabels').valueChanges, this.axisSettingsFormGroup.get('showTicks').valueChanges, this.axisSettingsFormGroup.get('showLine').valueChanges, - this.axisSettingsFormGroup.get('showSplitLines').valueChanges) - .subscribe(() => { + this.axisSettingsFormGroup.get('showSplitLines').valueChanges + ).pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateValidators(); }); } @@ -157,7 +163,9 @@ export class TimeSeriesChartAxisSettingsComponent implements OnInit, ControlValu value, {emitEvent: false} ); this.updateValidators(); - this.axisSettingsFormGroup.get('show').valueChanges.subscribe((show) => { + this.axisSettingsFormGroup.get('show').valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe((show) => { this.settingsExpanded = show; }); } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/time-series-chart-grid-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/time-series-chart-grid-settings.component.ts index fd88ce2a8f..a939567b0d 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/time-series-chart-grid-settings.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/time-series-chart-grid-settings.component.ts @@ -14,7 +14,7 @@ /// limitations under the License. /// -import { Component, forwardRef, Input, OnInit } from '@angular/core'; +import { Component, DestroyRef, forwardRef, Input, OnInit } from '@angular/core'; import { ControlValueAccessor, NG_VALUE_ACCESSOR, @@ -24,6 +24,7 @@ import { } from '@angular/forms'; import { TimeSeriesChartGridSettings } from '@home/components/widget/lib/chart/time-series-chart.models'; import { WidgetService } from '@core/http/widget.service'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; @Component({ selector: 'tb-time-series-chart-grid-settings', @@ -51,7 +52,8 @@ export class TimeSeriesChartGridSettingsComponent implements OnInit, ControlValu public gridSettingsFormGroup: UntypedFormGroup; constructor(private fb: UntypedFormBuilder, - private widgetService: WidgetService,) { + private widgetService: WidgetService, + private destroyRef: DestroyRef) { } ngOnInit(): void { @@ -61,11 +63,14 @@ export class TimeSeriesChartGridSettingsComponent implements OnInit, ControlValu borderWidth: [null, [Validators.min(0)]], borderColor: [null, []], }); - this.gridSettingsFormGroup.valueChanges.subscribe(() => { + this.gridSettingsFormGroup.valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateModel(); }); - this.gridSettingsFormGroup.get('show').valueChanges - .subscribe(() => { + this.gridSettingsFormGroup.get('show').valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateValidators(); }); } @@ -93,7 +98,9 @@ export class TimeSeriesChartGridSettingsComponent implements OnInit, ControlValu value, {emitEvent: false} ); this.updateValidators(); - this.gridSettingsFormGroup.get('show').valueChanges.subscribe((show) => { + this.gridSettingsFormGroup.get('show').valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe((show) => { this.settingsExpanded = show; }); } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/time-series-chart-state-row.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/time-series-chart-state-row.component.ts index 97c87432c2..3879203939 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/time-series-chart-state-row.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/time-series-chart-state-row.component.ts @@ -17,6 +17,7 @@ import { ChangeDetectorRef, Component, + DestroyRef, EventEmitter, forwardRef, Input, @@ -37,6 +38,7 @@ import { timeSeriesStateSourceTypes, timeSeriesStateSourceTypeTranslations } from '@home/components/widget/lib/chart/time-series-chart.models'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; @Component({ selector: 'tb-time-series-chart-state-row', @@ -72,7 +74,8 @@ export class TimeSeriesChartStateRowComponent implements ControlValueAccessor, O private propagateChange = (_val: any) => {}; constructor(private fb: UntypedFormBuilder, - private cd: ChangeDetectorRef) { + private cd: ChangeDetectorRef, + private destroyRef: DestroyRef) { } ngOnInit() { @@ -84,10 +87,14 @@ export class TimeSeriesChartStateRowComponent implements ControlValueAccessor, O sourceRangeFrom: [null, []], sourceRangeTo: [null, []] }); - this.stateFormGroup.valueChanges.subscribe( + this.stateFormGroup.valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe( () => this.updateModel() ); - this.stateFormGroup.get('sourceType').valueChanges.subscribe(() => { + this.stateFormGroup.get('sourceType').valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateValidators(); }); } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/time-series-chart-states-panel.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/time-series-chart-states-panel.component.ts index 8c30582425..c7229c2a65 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/time-series-chart-states-panel.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/time-series-chart-states-panel.component.ts @@ -14,7 +14,7 @@ /// limitations under the License. /// -import { Component, forwardRef, Input, OnInit, ViewEncapsulation } from '@angular/core'; +import { Component, DestroyRef, forwardRef, Input, OnInit, ViewEncapsulation } from '@angular/core'; import { AbstractControl, ControlValueAccessor, @@ -32,6 +32,7 @@ import { timeSeriesChartStateValid, timeSeriesChartStateValidator } from '@home/components/widget/lib/chart/time-series-chart.models'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; @Component({ selector: 'tb-time-series-chart-states-panel', @@ -60,14 +61,17 @@ export class TimeSeriesChartStatesPanelComponent implements ControlValueAccessor private propagateChange = (_val: any) => {}; - constructor(private fb: UntypedFormBuilder) { + constructor(private fb: UntypedFormBuilder, + private destroyRef: DestroyRef) { } ngOnInit() { this.statesFormGroup = this.fb.group({ states: [this.fb.array([]), []] }); - this.statesFormGroup.valueChanges.subscribe( + this.statesFormGroup.valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe( () => { let states: TimeSeriesChartStateSettings[] = this.statesFormGroup.get('states').value; if (states) { diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/time-series-chart-threshold-row.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/time-series-chart-threshold-row.component.ts index f834066a13..58b5554483 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/time-series-chart-threshold-row.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/time-series-chart-threshold-row.component.ts @@ -17,6 +17,7 @@ import { ChangeDetectorRef, Component, + DestroyRef, EventEmitter, forwardRef, Input, @@ -52,6 +53,7 @@ import { ValueSourceType, ValueSourceTypeTranslation } from '@shared/models/widget-settings.models'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; @Component({ selector: 'tb-time-series-chart-threshold-row', @@ -121,7 +123,8 @@ export class TimeSeriesChartThresholdRowComponent implements ControlValueAccesso constructor(private fb: UntypedFormBuilder, private thresholdsPanel: TimeSeriesChartThresholdsPanelComponent, - private cd: ChangeDetectorRef) { + private cd: ChangeDetectorRef, + private destroyRef: DestroyRef) { } ngOnInit() { @@ -137,16 +140,24 @@ export class TimeSeriesChartThresholdRowComponent implements ControlValueAccesso this.latestKeyFormControl = this.fb.control(null, [Validators.required]); this.entityKeyFormControl = this.fb.control(null, [Validators.required]); this.thresholdSettingsFormControl = this.fb.control(null); - this.thresholdFormGroup.valueChanges.subscribe( + this.thresholdFormGroup.valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe( () => this.updateModel() ); - this.latestKeyFormControl.valueChanges.subscribe( + this.latestKeyFormControl.valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe( () => this.updateModel() ); - this.entityKeyFormControl.valueChanges.subscribe( + this.entityKeyFormControl.valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe( () => this.updateModel() ); - this.thresholdSettingsFormControl.valueChanges.subscribe((thresholdSettings: Partial) => { + this.thresholdSettingsFormControl.valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe((thresholdSettings: Partial) => { this.modelValue = {...this.modelValue, ...thresholdSettings}; this.thresholdFormGroup.patchValue( { @@ -158,7 +169,9 @@ export class TimeSeriesChartThresholdRowComponent implements ControlValueAccesso {emitEvent: false}); this.propagateChange(this.modelValue); }); - this.thresholdFormGroup.get('type').valueChanges.subscribe(() => { + this.thresholdFormGroup.get('type').valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateValidators(); }); } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/time-series-chart-threshold-settings-panel.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/time-series-chart-threshold-settings-panel.component.ts index eb0a2d79c8..07075bc8de 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/time-series-chart-threshold-settings-panel.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/time-series-chart-threshold-settings-panel.component.ts @@ -14,7 +14,7 @@ /// limitations under the License. /// -import { Component, EventEmitter, Input, OnInit, Output, ViewEncapsulation } from '@angular/core'; +import { Component, DestroyRef, EventEmitter, Input, OnInit, Output, ViewEncapsulation } from '@angular/core'; import { TbPopoverComponent } from '@shared/components/popover.component'; import { UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms'; import { @@ -33,6 +33,7 @@ import { chartShapes, chartShapeTranslations } from '@home/components/widget/lib/chart/chart.models'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; @Component({ selector: 'tb-time-series-chart-threshold-settings-panel', @@ -81,7 +82,8 @@ export class TimeSeriesChartThresholdSettingsPanelComponent implements OnInit { thresholdSettingsFormGroup: UntypedFormGroup; - constructor(private fb: UntypedFormBuilder) { + constructor(private fb: UntypedFormBuilder, + private destroyRef: DestroyRef) { } ngOnInit(): void { @@ -108,7 +110,10 @@ export class TimeSeriesChartThresholdSettingsPanelComponent implements OnInit { merge(this.thresholdSettingsFormGroup.get('showLabel').valueChanges, this.thresholdSettingsFormGroup.get('enableLabelBackground').valueChanges, this.thresholdSettingsFormGroup.get('startSymbol').valueChanges, - this.thresholdSettingsFormGroup.get('endSymbol').valueChanges).subscribe(() => { + this.thresholdSettingsFormGroup.get('endSymbol').valueChanges + ).pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateValidators(); }); this.updateValidators(); diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/time-series-chart-thresholds-panel.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/time-series-chart-thresholds-panel.component.ts index 62d2de8402..727783415a 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/time-series-chart-thresholds-panel.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/time-series-chart-thresholds-panel.component.ts @@ -14,7 +14,7 @@ /// limitations under the License. /// -import { Component, forwardRef, Input, OnInit, ViewEncapsulation } from '@angular/core'; +import { Component, DestroyRef, forwardRef, Input, OnInit, ViewEncapsulation } from '@angular/core'; import { AbstractControl, ControlValueAccessor, @@ -40,6 +40,7 @@ import { DataKey, Datasource, WidgetConfig } from '@shared/models/widget.models' import { DataKeyType } from '@shared/models/telemetry/telemetry.models'; import { coerceBoolean } from '@shared/decorators/coercion'; import { ValueSourceType } from '@shared/models/widget-settings.models'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; @Component({ selector: 'tb-time-series-chart-thresholds-panel', @@ -87,14 +88,17 @@ export class TimeSeriesChartThresholdsPanelComponent implements ControlValueAcce private propagateChange = (_val: any) => {}; - constructor(private fb: UntypedFormBuilder) { + constructor(private fb: UntypedFormBuilder, + private destroyRef: DestroyRef) { } ngOnInit() { this.thresholdsFormGroup = this.fb.group({ thresholds: [this.fb.array([]), []] }); - this.thresholdsFormGroup.valueChanges.subscribe( + this.thresholdsFormGroup.valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe( () => { let thresholds: TimeSeriesChartThreshold[] = this.thresholdsFormGroup.get('thresholds').value; if (thresholds) { diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/time-series-chart-y-axes-panel.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/time-series-chart-y-axes-panel.component.ts index 9879ffe877..4c2a0f7490 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/time-series-chart-y-axes-panel.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/time-series-chart-y-axes-panel.component.ts @@ -14,7 +14,16 @@ /// limitations under the License. /// -import { Component, EventEmitter, forwardRef, Input, OnInit, Output, ViewEncapsulation } from '@angular/core'; +import { + Component, + DestroyRef, + EventEmitter, + forwardRef, + Input, + OnInit, + Output, + ViewEncapsulation +} from '@angular/core'; import { AbstractControl, ControlValueAccessor, @@ -37,6 +46,7 @@ import { import { mergeDeep } from '@core/utils'; import { CdkDragDrop } from '@angular/cdk/drag-drop'; import { coerceBoolean } from '@shared/decorators/coercion'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; @Component({ selector: 'tb-time-series-chart-y-axes-panel', @@ -76,14 +86,17 @@ export class TimeSeriesChartYAxesPanelComponent implements ControlValueAccessor, private propagateChange = (_val: any) => {}; - constructor(private fb: UntypedFormBuilder) { + constructor(private fb: UntypedFormBuilder, + private destroyRef: DestroyRef) { } ngOnInit() { this.yAxesFormGroup = this.fb.group({ axes: [this.fb.array([]), []] }); - this.yAxesFormGroup.valueChanges.subscribe( + this.yAxesFormGroup.valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe( () => { let axes: TimeSeriesChartYAxisSettings[] = this.yAxesFormGroup.get('axes').value; for (let i = 0; i < axes.length; i++) { diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/time-series-chart-y-axis-row.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/time-series-chart-y-axis-row.component.ts index 3fcde90cef..7bb1ff1f07 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/time-series-chart-y-axis-row.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/time-series-chart-y-axis-row.component.ts @@ -17,6 +17,7 @@ import { ChangeDetectorRef, Component, + DestroyRef, EventEmitter, forwardRef, Input, @@ -40,6 +41,7 @@ import { } from '@home/components/widget/lib/settings/common/chart/time-series-chart-axis-settings-panel.component'; import { deepClone } from '@core/utils'; import { TranslateService } from '@ngx-translate/core'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; @Component({ selector: 'tb-time-series-chart-y-axis-row', @@ -81,7 +83,8 @@ export class TimeSeriesChartYAxisRowComponent implements ControlValueAccessor, O private popoverService: TbPopoverService, private renderer: Renderer2, private viewContainerRef: ViewContainerRef, - private cd: ChangeDetectorRef) { + private cd: ChangeDetectorRef, + private destroyRef: DestroyRef) { } ngOnInit() { @@ -94,10 +97,14 @@ export class TimeSeriesChartYAxisRowComponent implements ControlValueAccessor, O max: [null, []], show: [null, []] }); - this.axisFormGroup.valueChanges.subscribe( + this.axisFormGroup.valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe( () => this.updateModel() ); - this.axisFormGroup.get('show').valueChanges.subscribe(() => { + this.axisFormGroup.get('show').valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateValidators(); }); } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/time-series-no-aggregation-bar-width-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/time-series-no-aggregation-bar-width-settings.component.ts index 8601c48159..0107bbaec7 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/time-series-no-aggregation-bar-width-settings.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/time-series-no-aggregation-bar-width-settings.component.ts @@ -14,7 +14,7 @@ /// limitations under the License. /// -import { Component, forwardRef, Input, OnInit } from '@angular/core'; +import { Component, DestroyRef, forwardRef, Input, OnInit } from '@angular/core'; import { ControlValueAccessor, NG_VALUE_ACCESSOR, @@ -30,6 +30,7 @@ import { } from '@home/components/widget/lib/chart/time-series-chart.models'; import { merge } from 'rxjs'; import { coerceBoolean } from '@shared/decorators/coercion'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; @Component({ selector: 'tb-time-series-no-aggregation-bar-width-settings', @@ -64,7 +65,8 @@ export class TimeSeriesNoAggregationBarWidthSettingsComponent implements OnInit, public barWidthSettingsFormGroup: UntypedFormGroup; - constructor(private fb: UntypedFormBuilder) { + constructor(private fb: UntypedFormBuilder, + private destroyRef: DestroyRef) { } ngOnInit(): void { @@ -81,13 +83,17 @@ export class TimeSeriesNoAggregationBarWidthSettingsComponent implements OnInit, absoluteWidth: [null, [Validators.required, Validators.min(100)]] }) }); - this.barWidthSettingsFormGroup.valueChanges.subscribe(() => { + this.barWidthSettingsFormGroup.valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateModel(); }); merge(this.barWidthSettingsFormGroup.get('strategy').valueChanges, this.barWidthSettingsFormGroup.get('groupWidth.relative').valueChanges, - this.barWidthSettingsFormGroup.get('barWidth.relative').valueChanges) - .subscribe(() => { + this.barWidthSettingsFormGroup.get('barWidth.relative').valueChanges + ).pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateValidators(); }); } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/color-settings-panel.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/color-settings-panel.component.ts index 70111a1448..4ef6939e67 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/color-settings-panel.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/color-settings-panel.component.ts @@ -14,7 +14,7 @@ /// limitations under the License. /// -import { Component, EventEmitter, Input, OnInit, Output, ViewEncapsulation } from '@angular/core'; +import { Component, DestroyRef, EventEmitter, Input, OnInit, Output, ViewEncapsulation } from '@angular/core'; import { PageComponent } from '@shared/components/page.component'; import { ColorSettings, @@ -34,6 +34,7 @@ import { IAliasController } from '@core/api/widget-api.models'; import { coerceBoolean } from '@shared/decorators/coercion'; import { DataKeysCallbacks } from '@home/components/widget/config/data-keys.component.models'; import { Datasource } from '@shared/models/widget.models'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; @Component({ selector: 'tb-color-settings-panel', @@ -91,7 +92,8 @@ export class ColorSettingsPanelComponent extends PageComponent implements OnInit constructor(private fb: UntypedFormBuilder, private widgetService: WidgetService, - protected store: Store) { + protected store: Store, + private destroyRef: DestroyRef) { super(store); } @@ -105,7 +107,9 @@ export class ColorSettingsPanelComponent extends PageComponent implements OnInit colorFunction: [this.colorSettings?.colorFunction, []] } ); - this.colorSettingsFormGroup.get('type').valueChanges.subscribe(() => { + this.colorSettingsFormGroup.get('type').valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { setTimeout(() => {this.popover?.updatePosition();}, 0); }); } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/count-widget-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/count-widget-settings.component.ts index b700dce8f3..9613c4888a 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/count-widget-settings.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/count-widget-settings.component.ts @@ -32,12 +32,13 @@ import { CountWidgetSettings, entityCountCardLayoutImages } from '@home/components/widget/lib/count/count-widget.models'; import {PageComponent} from '@shared/components/page.component'; -import {Component, forwardRef, Input, OnInit} from '@angular/core'; +import { Component, DestroyRef, forwardRef, Input, OnInit } from '@angular/core'; import { coerceBoolean } from '@shared/decorators/coercion'; import { valueCardLayoutImages, valueCardLayoutTranslations } from '@home/components/widget/lib/cards/value-card-widget.models'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; @Component({ selector: 'tb-count-widget-settings', @@ -70,7 +71,8 @@ export class CountWidgetSettingsComponent extends PageComponent implements OnIni countWidgetConfigForm: UntypedFormGroup; constructor(protected store: Store, - private fb: UntypedFormBuilder) { + private fb: UntypedFormBuilder, + private destroyRef: DestroyRef) { super(store); } @@ -104,7 +106,9 @@ export class CountWidgetSettingsComponent extends PageComponent implements OnIni chevronSizeUnit: [null, []], chevronColor: [null, []], }); - this.countWidgetConfigForm.valueChanges.subscribe(() => { + this.countWidgetConfigForm.valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateModel(); }); for (const trigger of ['showLabel', 'showIcon', 'showIconBackground', 'showChevron']) { @@ -113,7 +117,9 @@ export class CountWidgetSettingsComponent extends PageComponent implements OnIni for (const part of path) { control = this.countWidgetConfigForm.get(part); } - control.valueChanges.subscribe(() => { + control.valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateValidators(); }); } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/css-size-input.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/css-size-input.component.ts index 099778e924..7a6d4b3c0c 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/css-size-input.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/css-size-input.component.ts @@ -14,7 +14,7 @@ /// limitations under the License. /// -import { Component, forwardRef, HostBinding, Input, OnInit } from '@angular/core'; +import { Component, DestroyRef, forwardRef, HostBinding, Input, OnInit } from '@angular/core'; import { ControlValueAccessor, NG_VALIDATORS, @@ -28,6 +28,7 @@ import { import { cssUnit, resolveCssSize } from '@shared/models/widget-settings.models'; import { coerceBoolean } from '@shared/decorators/coercion'; import { isDefinedAndNotNull } from '@core/utils'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; @Component({ selector: 'tb-css-size-input', @@ -82,14 +83,17 @@ export class CssSizeInputComponent implements OnInit, ControlValueAccessor, Vali private propagateChange = null; - constructor(private fb: UntypedFormBuilder) {} + constructor(private fb: UntypedFormBuilder, + private destroyRef: DestroyRef) {} ngOnInit(): void { this.cssSizeFormGroup = this.fb.group({ size: [null, this.required ? [Validators.required, Validators.min(0)] : [Validators.min(0)]], unit: [null, []] }); - this.cssSizeFormGroup.valueChanges.subscribe((value: {size: number; unit: cssUnit}) => { + this.cssSizeFormGroup.valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe((value: {size: number; unit: cssUnit}) => { this.updateModel(value); }); } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/css-unit-select.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/css-unit-select.component.ts index 588871b7b9..bdb5a60960 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/css-unit-select.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/css-unit-select.component.ts @@ -14,10 +14,11 @@ /// limitations under the License. /// -import { Component, forwardRef, Input, OnInit } from '@angular/core'; +import { Component, DestroyRef, forwardRef, Input, OnInit } from '@angular/core'; import { ControlValueAccessor, NG_VALUE_ACCESSOR, UntypedFormControl } from '@angular/forms'; import { cssUnit, cssUnits } from '@shared/models/widget-settings.models'; import { coerceBoolean } from '@shared/decorators/coercion'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; @Component({ selector: 'tb-css-unit-select', @@ -51,11 +52,13 @@ export class CssUnitSelectComponent implements OnInit, ControlValueAccessor { private propagateChange = null; - constructor() {} + constructor(private destroyRef: DestroyRef) {} ngOnInit(): void { this.cssUnitFormControl = new UntypedFormControl(); - this.cssUnitFormControl.valueChanges.subscribe((value: cssUnit) => { + this.cssUnitFormControl.valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe((value: cssUnit) => { this.updateModel(value); }); } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/date-format-select.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/date-format-select.component.ts index 144f02fe46..bf81fe8243 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/date-format-select.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/date-format-select.component.ts @@ -14,7 +14,16 @@ /// limitations under the License. /// -import { Component, forwardRef, Input, OnInit, Renderer2, ViewChild, ViewContainerRef } from '@angular/core'; +import { + Component, + DestroyRef, + forwardRef, + Input, + OnInit, + Renderer2, + ViewChild, + ViewContainerRef +} from '@angular/core'; import { ControlValueAccessor, NG_VALUE_ACCESSOR, UntypedFormControl } from '@angular/forms'; import { AutoDateFormatSettings, @@ -36,6 +45,7 @@ import { coerceBoolean } from '@shared/decorators/coercion'; import { AutoDateFormatSettingsPanelComponent } from '@home/components/widget/lib/settings/common/auto-date-format-settings-panel.component'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; @Component({ selector: 'tb-date-format-select', @@ -81,14 +91,17 @@ export class DateFormatSelectComponent implements OnInit, ControlValueAccessor { private date: DatePipe, private popoverService: TbPopoverService, private renderer: Renderer2, - private viewContainerRef: ViewContainerRef) {} + private viewContainerRef: ViewContainerRef, + private destroyRef: DestroyRef) {} ngOnInit(): void { const targetDateFormats = this.includeAuto ? dateFormatsWithAuto : dateFormats; this.dateFormatList = this.excludeLastUpdateAgo ? targetDateFormats.filter(format => !format.lastUpdateAgo) : dateFormats; this.dateFormatFormControl = new UntypedFormControl(); - this.dateFormatFormControl.valueChanges.subscribe((value: DateFormatSettings) => { + this.dateFormatFormControl.valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe((value: DateFormatSettings) => { this.updateModel(value); if (value?.custom) { setTimeout(() => { diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/date-format-settings-panel.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/date-format-settings-panel.component.ts index d187644370..5f707adb8c 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/date-format-settings-panel.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/date-format-settings-panel.component.ts @@ -14,7 +14,7 @@ /// limitations under the License. /// -import { Component, EventEmitter, Input, OnInit, Output, ViewEncapsulation } from '@angular/core'; +import { Component, DestroyRef, EventEmitter, Input, OnInit, Output, ViewEncapsulation } from '@angular/core'; import { PageComponent } from '@shared/components/page.component'; import { DateFormatSettings } from '@shared/models/widget-settings.models'; import { TbPopoverComponent } from '@shared/components/popover.component'; @@ -22,6 +22,7 @@ import { UntypedFormControl, Validators } from '@angular/forms'; import { Store } from '@ngrx/store'; import { AppState } from '@core/core.state'; import { DatePipe } from '@angular/common'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; @Component({ selector: 'tb-date-format-settings-panel', @@ -46,13 +47,16 @@ export class DateFormatSettingsPanelComponent extends PageComponent implements O previewText = ''; constructor(private date: DatePipe, - protected store: Store) { + protected store: Store, + private destroyRef: DestroyRef) { super(store); } ngOnInit(): void { this.dateFormatFormControl = new UntypedFormControl(this.dateFormat.format, [Validators.required]); - this.dateFormatFormControl.valueChanges.subscribe((value: string) => { + this.dateFormatFormControl.valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe((value: string) => { this.previewText = this.date.transform(Date.now(), value); }); this.previewText = this.date.transform(Date.now(), this.dateFormat.format); diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/entity-alias-input.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/entity-alias-input.component.ts index d36a4843a1..a5aa7cb99e 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/entity-alias-input.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/entity-alias-input.component.ts @@ -16,6 +16,7 @@ import { Component, + DestroyRef, ElementRef, forwardRef, HostBinding, @@ -35,6 +36,7 @@ import { coerceBoolean } from '@shared/decorators/coercion'; import { IAliasController } from '@core/api/widget-api.models'; import { map, mergeMap } from 'rxjs/operators'; import { Observable, of } from 'rxjs'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; @Component({ selector: 'tb-entity-alias-input', @@ -76,12 +78,15 @@ export class EntityAliasInputComponent implements ControlValueAccessor, OnInit { private propagateChange = (_val: any) => {}; - constructor(private fb: UntypedFormBuilder) { + constructor(private fb: UntypedFormBuilder, + private destroyRef: DestroyRef) { } ngOnInit() { this.entityAliasFormControl = this.fb.control(null, this.required ? [Validators.required] : []); - this.entityAliasFormControl.valueChanges.subscribe( + this.entityAliasFormControl.valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe( () => this.updateModel() ); diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/font-settings-panel.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/font-settings-panel.component.ts index 02266a34ee..13a4a93648 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/font-settings-panel.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/font-settings-panel.component.ts @@ -16,6 +16,7 @@ import { Component, + DestroyRef, ElementRef, EventEmitter, Input, @@ -42,6 +43,7 @@ import { AppState } from '@core/core.state'; import { Observable } from 'rxjs'; import { map, startWith, tap } from 'rxjs/operators'; import { coerceBoolean } from '@shared/decorators/coercion'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; @Component({ selector: 'tb-font-settings-panel', @@ -101,7 +103,8 @@ export class FontSettingsPanelComponent extends PageComponent implements OnInit previewStyle: ComponentStyle = {}; constructor(private fb: UntypedFormBuilder, - protected store: Store) { + protected store: Store, + private destroyRef: DestroyRef) { super(store); } @@ -118,7 +121,9 @@ export class FontSettingsPanelComponent extends PageComponent implements OnInit } ); this.updatePreviewStyle(this.font); - this.fontFormGroup.valueChanges.subscribe((font: Font) => { + this.fontFormGroup.valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe((font: Font) => { if (this.fontFormGroup.valid) { this.updatePreviewStyle(font); setTimeout(() => {this.popover?.updatePosition();}, 0); diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/indicator/status-widget-state-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/indicator/status-widget-state-settings.component.ts index 8425264d89..5776b6fe66 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/indicator/status-widget-state-settings.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/indicator/status-widget-state-settings.component.ts @@ -14,13 +14,14 @@ /// limitations under the License. /// -import { Component, forwardRef, Input, OnChanges, OnInit, SimpleChanges } from '@angular/core'; +import { Component, DestroyRef, forwardRef, Input, OnChanges, OnInit, SimpleChanges } from '@angular/core'; import { ControlValueAccessor, NG_VALUE_ACCESSOR, UntypedFormBuilder, UntypedFormGroup } from '@angular/forms'; import { merge } from 'rxjs'; import { StatusWidgetLayout, StatusWidgetStateSettings } from '@home/components/widget/lib/indicator/status-widget.models'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; @Component({ selector: 'tb-status-widget-state-settings', @@ -50,7 +51,8 @@ export class StatusWidgetStateSettingsComponent implements OnInit, OnChanges, Co public stateSettingsFormGroup: UntypedFormGroup; - constructor(private fb: UntypedFormBuilder) { + constructor(private fb: UntypedFormBuilder, + private destroyRef: DestroyRef) { } ngOnInit(): void { @@ -71,12 +73,16 @@ export class StatusWidgetStateSettingsComponent implements OnInit, OnChanges, Co secondaryColorDisabled: [null, []], backgroundDisabled: [null, []] }); - this.stateSettingsFormGroup.valueChanges.subscribe(() => { + this.stateSettingsFormGroup.valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateModel(); }); merge(this.stateSettingsFormGroup.get('showLabel').valueChanges, - this.stateSettingsFormGroup.get('showStatus').valueChanges) - .subscribe(() => { + this.stateSettingsFormGroup.get('showStatus').valueChanges + ).pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateValidators(); }); } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/scada/scada-symbol-object-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/scada/scada-symbol-object-settings.component.ts index e68788cc92..58afec4523 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/scada/scada-symbol-object-settings.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/scada/scada-symbol-object-settings.component.ts @@ -14,7 +14,17 @@ /// limitations under the License. /// -import { ChangeDetectorRef, Component, forwardRef, Input, OnChanges, OnInit, SimpleChanges } from '@angular/core'; +import { + ChangeDetectorRef, + Component, + DestroyRef, + forwardRef, + Input, + OnChanges, + OnDestroy, + OnInit, + SimpleChanges +} from '@angular/core'; import { ControlValueAccessor, NG_VALIDATORS, @@ -49,6 +59,7 @@ import { merge, Observable, of, Subscription } from 'rxjs'; import { WidgetActionCallbacks } from '@home/components/widget/action/manage-widget-actions.component.models'; import { ImageService } from '@core/http/image.service'; import { map } from 'rxjs/operators'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; @Component({ selector: 'tb-scada-symbol-object-settings', @@ -67,7 +78,7 @@ import { map } from 'rxjs/operators'; } ] }) -export class ScadaSymbolObjectSettingsComponent implements OnInit, OnChanges, ControlValueAccessor, Validator { +export class ScadaSymbolObjectSettingsComponent implements OnInit, OnChanges, ControlValueAccessor, Validator, OnDestroy { ScadaSymbolBehaviorType = ScadaSymbolBehaviorType; @@ -113,7 +124,8 @@ export class ScadaSymbolObjectSettingsComponent implements OnInit, OnChanges, Co constructor(protected store: Store, private fb: UntypedFormBuilder, private imageService: ImageService, - private cd: ChangeDetectorRef) { + private cd: ChangeDetectorRef, + private destroyRef: DestroyRef) { } ngOnInit(): void { @@ -121,7 +133,9 @@ export class ScadaSymbolObjectSettingsComponent implements OnInit, OnChanges, Co behavior: this.fb.group({}), properties: this.fb.group({}) }); - this.scadaSymbolObjectSettingsFormGroup.valueChanges.subscribe(() => { + this.scadaSymbolObjectSettingsFormGroup.valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateModel(); }); this.loadMetadata(); @@ -138,6 +152,13 @@ export class ScadaSymbolObjectSettingsComponent implements OnInit, OnChanges, Co } } + ngOnDestroy() { + if (this.validatorSubscription) { + this.validatorSubscription.unsubscribe(); + this.validatorSubscription = null; + } + } + registerOnChange(fn: any): void { this.propagateChange = fn; } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/value-source-data-key.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/value-source-data-key.component.ts index eb714597b2..a541291b08 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/value-source-data-key.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/value-source-data-key.component.ts @@ -14,7 +14,7 @@ /// limitations under the License. /// -import { ChangeDetectorRef, Component, forwardRef, Input, OnInit } from '@angular/core'; +import { ChangeDetectorRef, Component, DestroyRef, forwardRef, Input, OnInit } from '@angular/core'; import { ControlValueAccessor, NG_VALUE_ACCESSOR, @@ -36,6 +36,7 @@ import { ValueSourceTypes, ValueSourceTypeTranslation } from '@shared/models/widget-settings.models'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; @Component({ selector: 'tb-value-source-data-key', @@ -81,7 +82,8 @@ export class ValueSourceDataKeyComponent extends PageComponent implements OnInit constructor(protected store: Store, private fb: UntypedFormBuilder, - private cd: ChangeDetectorRef) { + private cd: ChangeDetectorRef, + private destroyRef: DestroyRef) { super(store); } @@ -93,16 +95,24 @@ export class ValueSourceDataKeyComponent extends PageComponent implements OnInit }); this.latestKeyFormControl = this.fb.control(null, [Validators.required]); this.entityKeyFormControl = this.fb.control(null, [Validators.required]); - this.valueSourceFormGroup.valueChanges.subscribe( + this.valueSourceFormGroup.valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe( () => this.updateModel() ); - this.latestKeyFormControl.valueChanges.subscribe( + this.latestKeyFormControl.valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe( () => this.updateModel() ); - this.entityKeyFormControl.valueChanges.subscribe( + this.entityKeyFormControl.valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe( () => this.updateModel() ); - this.valueSourceFormGroup.get('type').valueChanges.subscribe(() => { + this.valueSourceFormGroup.get('type').valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateValidators(); }); } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/value-source.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/value-source.component.ts index f290a05083..28bcb1dd4b 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/value-source.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/value-source.component.ts @@ -14,7 +14,7 @@ /// limitations under the License. /// -import { Component, ElementRef, forwardRef, Input, OnInit, ViewChild } from '@angular/core'; +import { Component, DestroyRef, ElementRef, forwardRef, Input, OnInit, ViewChild } from '@angular/core'; import { ControlValueAccessor, NG_VALUE_ACCESSOR, UntypedFormBuilder, UntypedFormGroup } from '@angular/forms'; import { PageComponent } from '@shared/components/page.component'; import { Store } from '@ngrx/store'; @@ -25,6 +25,7 @@ import { catchError, map, mergeMap, publishReplay, refCount, tap } from 'rxjs/op import { DataKey } from '@shared/models/widget.models'; import { DataKeyType } from '@shared/models/telemetry/telemetry.models'; import { EntityService } from '@core/http/entity.service'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; export declare type ValueSource = 'predefinedValue' | 'entityAttribute'; @@ -84,7 +85,8 @@ export class ValueSourceComponent extends PageComponent implements OnInit, Contr constructor(protected store: Store, private entityService: EntityService, - private fb: UntypedFormBuilder) { + private fb: UntypedFormBuilder, + private destroyRef: DestroyRef) { super(store); } @@ -95,10 +97,14 @@ export class ValueSourceComponent extends PageComponent implements OnInit, Contr attribute: [null, []], value: [null, []] }); - this.valueSourceFormGroup.valueChanges.subscribe(() => { + this.valueSourceFormGroup.valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateModel(); }); - this.valueSourceFormGroup.get('valueSource').valueChanges.subscribe(() => { + this.valueSourceFormGroup.get('valueSource').valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateValidators(true); }); this.updateValidators(false); diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/widget-font.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/widget-font.component.ts index f3c84926bd..ef3222cfbd 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/widget-font.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/widget-font.component.ts @@ -14,12 +14,13 @@ /// limitations under the License. /// -import { Component, forwardRef, HostBinding, Input, OnInit } from '@angular/core'; +import { Component, DestroyRef, forwardRef, HostBinding, Input, OnInit } from '@angular/core'; import { ControlValueAccessor, UntypedFormBuilder, UntypedFormGroup, NG_VALUE_ACCESSOR, Validators } from '@angular/forms'; import { PageComponent } from '@shared/components/page.component'; import { Store } from '@ngrx/store'; import { AppState } from '@core/core.state'; import { TranslateService } from '@ngx-translate/core'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; export interface WidgetFont { family: string; @@ -63,7 +64,8 @@ export class WidgetFontComponent extends PageComponent implements OnInit, Contro constructor(protected store: Store, private translate: TranslateService, - private fb: UntypedFormBuilder) { + private fb: UntypedFormBuilder, + private destroyRef: DestroyRef) { super(store); } @@ -78,7 +80,9 @@ export class WidgetFontComponent extends PageComponent implements OnInit, Contro if (this.hasShadowColor) { this.widgetFontFormGroup.addControl('shadowColor', this.fb.control(null, [])); } - this.widgetFontFormGroup.valueChanges.subscribe(() => { + this.widgetFontFormGroup.valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateModel(); }); } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/control/device-key-autocomplete.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/control/device-key-autocomplete.component.ts index 9c0691faed..470e7cd908 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/control/device-key-autocomplete.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/control/device-key-autocomplete.component.ts @@ -14,7 +14,17 @@ /// limitations under the License. /// -import { Component, ElementRef, forwardRef, Input, OnChanges, OnInit, SimpleChanges, ViewChild } from '@angular/core'; +import { + Component, + DestroyRef, + ElementRef, + forwardRef, + Input, + OnChanges, + OnInit, + SimpleChanges, + ViewChild +} from '@angular/core'; import { ControlValueAccessor, NG_VALUE_ACCESSOR, @@ -36,6 +46,7 @@ import { EntityType } from '@shared/models/entity-type.models'; import { EntityFilter, singleEntityFilterFromDeviceId } from '@shared/models/query/query.models'; import { AliasFilterType } from '@shared/models/alias.models'; import { coerceBoolean } from '@shared/decorators/coercion'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; @Component({ selector: 'tb-device-key-autocomplete', @@ -101,7 +112,8 @@ export class DeviceKeyAutocompleteComponent extends PageComponent implements OnI constructor(protected store: Store, private entityService: EntityService, - private fb: UntypedFormBuilder) { + private fb: UntypedFormBuilder, + private destroyRef: DestroyRef) { super(store); } @@ -109,7 +121,9 @@ export class DeviceKeyAutocompleteComponent extends PageComponent implements OnI this.deviceKeyFormGroup = this.fb.group({ key: [null, this.required ? [Validators.required] : []] }); - this.deviceKeyFormGroup.valueChanges.subscribe(() => { + this.deviceKeyFormGroup.valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateModel(); }); diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/control/rpc-button-style.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/control/rpc-button-style.component.ts index 5263aa8016..6cf3fe7bf8 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/control/rpc-button-style.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/control/rpc-button-style.component.ts @@ -14,11 +14,12 @@ /// limitations under the License. /// -import { Component, forwardRef, Input, OnInit } from '@angular/core'; +import { Component, DestroyRef, forwardRef, Input, OnInit } from '@angular/core'; import { ControlValueAccessor, UntypedFormBuilder, UntypedFormGroup, NG_VALUE_ACCESSOR } from '@angular/forms'; import { PageComponent } from '@shared/components/page.component'; import { Store } from '@ngrx/store'; import { AppState } from '@core/core.state'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; export interface RpcButtonStyle { isRaised: boolean; @@ -51,7 +52,8 @@ export class RpcButtonStyleComponent extends PageComponent implements OnInit, Co public rpcButtonStyleFormGroup: UntypedFormGroup; constructor(protected store: Store, - private fb: UntypedFormBuilder) { + private fb: UntypedFormBuilder, + private destroyRef: DestroyRef) { super(store); } @@ -62,7 +64,9 @@ export class RpcButtonStyleComponent extends PageComponent implements OnInit, Co bgColor: [null, []], textColor: [null, []] }); - this.rpcButtonStyleFormGroup.valueChanges.subscribe(() => { + this.rpcButtonStyleFormGroup.valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateModel(); }); } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/control/switch-rpc-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/control/switch-rpc-settings.component.ts index 764bfcfce9..7108eabbf6 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/control/switch-rpc-settings.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/control/switch-rpc-settings.component.ts @@ -14,7 +14,7 @@ /// limitations under the License. /// -import { Component, ElementRef, forwardRef, Input, OnInit, ViewChild } from '@angular/core'; +import { Component, DestroyRef, ElementRef, forwardRef, Input, OnInit, ViewChild } from '@angular/core'; import { ControlValueAccessor, NG_VALIDATORS, @@ -34,6 +34,7 @@ import { WidgetService } from '@core/http/widget.service'; import { IAliasController } from '@core/api/widget-api.models'; import { EntityService } from '@core/http/entity.service'; import { TargetDevice } from '@shared/models/widget.models'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; export declare type RpcRetrieveValueMethod = 'none' | 'rpc' | 'attribute' | 'timeseries'; @@ -107,7 +108,8 @@ export class SwitchRpcSettingsComponent extends PageComponent implements OnInit, private translate: TranslateService, private widgetService: WidgetService, private entityService: EntityService, - private fb: UntypedFormBuilder) { + private fb: UntypedFormBuilder, + private destroyRef: DestroyRef) { super(store); } @@ -139,13 +141,19 @@ export class SwitchRpcSettingsComponent extends PageComponent implements OnInit, requestPersistent: [false, []], persistentPollingInterval: [5000, [Validators.min(1000)]], }); - this.switchRpcSettingsFormGroup.get('retrieveValueMethod').valueChanges.subscribe(() => { + this.switchRpcSettingsFormGroup.get('retrieveValueMethod').valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateValidators(true); }); - this.switchRpcSettingsFormGroup.get('requestPersistent').valueChanges.subscribe(() => { + this.switchRpcSettingsFormGroup.get('requestPersistent').valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateValidators(true); }); - this.switchRpcSettingsFormGroup.valueChanges.subscribe(() => { + this.switchRpcSettingsFormGroup.valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateModel(); }); this.updateValidators(false); diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/gauge/tick-value.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/gauge/tick-value.component.ts index fcbeded87d..200c4d749a 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/gauge/tick-value.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/gauge/tick-value.component.ts @@ -15,7 +15,7 @@ /// import { ValueSourceProperty } from '@home/components/widget/lib/settings/common/value-source.component'; -import { Component, EventEmitter, forwardRef, Input, OnInit, Output } from '@angular/core'; +import { Component, DestroyRef, EventEmitter, forwardRef, Input, OnInit, Output } from '@angular/core'; import { ControlValueAccessor, NG_VALUE_ACCESSOR, UntypedFormBuilder, UntypedFormGroup } from '@angular/forms'; import { PageComponent } from '@shared/components/page.component'; import { Store } from '@ngrx/store'; @@ -24,6 +24,7 @@ import { TranslateService } from '@ngx-translate/core'; import { IAliasController } from '@core/api/widget-api.models'; import { DataKeysCallbacks } from '@home/components/widget/config/data-keys.component.models'; import { Datasource } from '@shared/models/widget.models'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; @Component({ selector: 'tb-tick-value', @@ -62,7 +63,8 @@ export class TickValueComponent extends PageComponent implements OnInit, Control constructor(protected store: Store, private translate: TranslateService, - private fb: UntypedFormBuilder) { + private fb: UntypedFormBuilder, + private destroyRef: DestroyRef) { super(store); } @@ -70,7 +72,9 @@ export class TickValueComponent extends PageComponent implements OnInit, Control this.tickValueFormGroup = this.fb.group({ tickValue: [null, []] }); - this.tickValueFormGroup.valueChanges.subscribe(() => { + this.tickValueFormGroup.valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateModel(); }); } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/gpio/gpio-item.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/gpio/gpio-item.component.ts index 22f7105b5d..fd46ccffc2 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/gpio/gpio-item.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/gpio/gpio-item.component.ts @@ -14,7 +14,7 @@ /// limitations under the License. /// -import { Component, EventEmitter, forwardRef, Input, OnInit, Output } from '@angular/core'; +import { Component, DestroyRef, EventEmitter, forwardRef, Input, OnInit, Output } from '@angular/core'; import { AbstractControl, ControlValueAccessor, @@ -28,6 +28,7 @@ import { Store } from '@ngrx/store'; import { AppState } from '@core/core.state'; import { TranslateService } from '@ngx-translate/core'; import { isNumber } from '@core/utils'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; export interface GpioItem { pin: number; @@ -87,7 +88,8 @@ export class GpioItemComponent extends PageComponent implements OnInit, ControlV constructor(protected store: Store, private translate: TranslateService, - private fb: UntypedFormBuilder) { + private fb: UntypedFormBuilder, + private destroyRef: DestroyRef) { super(store); } @@ -101,7 +103,9 @@ export class GpioItemComponent extends PageComponent implements OnInit, ControlV if (this.hasColor) { this.gpioItemFormGroup.addControl('color', this.fb.control(null, [Validators.required])); } - this.gpioItemFormGroup.valueChanges.subscribe(() => { + this.gpioItemFormGroup.valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateModel(); }); } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/indicator/liquid-level-card-widget-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/indicator/liquid-level-card-widget-settings.component.ts index ad424069a8..70a163ac1a 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/indicator/liquid-level-card-widget-settings.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/indicator/liquid-level-card-widget-settings.component.ts @@ -53,6 +53,7 @@ import { ResourcesService } from '@core/services/resources.service'; import { DataKeyType } from '@shared/models/telemetry/telemetry.models'; import { UtilsService } from '@core/services/utils.service'; import { EntityService } from '@core/http/entity.service'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; @Component({ selector: 'liquid-level-card-widget-settings', @@ -189,7 +190,9 @@ export class LiquidLevelCardWidgetSettingsComponent extends WidgetSettingsCompon tooltipBackgroundBlur: [settings.tooltipBackgroundBlur, []], }); - this.levelCardWidgetSettingsForm.get('selectedShape').valueChanges.subscribe(() => { + this.levelCardWidgetSettingsForm.get('selectedShape').valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.cd.detectChanges(); this.layoutsImageCardsSelect?.imageCardsSelectOptions.notifyOnChanges(); }); diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/input/datakey-select-option.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/input/datakey-select-option.component.ts index c620fa9e28..5c4e9bbdc3 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/input/datakey-select-option.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/input/datakey-select-option.component.ts @@ -14,7 +14,7 @@ /// limitations under the License. /// -import { Component, EventEmitter, forwardRef, Input, OnInit, Output } from '@angular/core'; +import { Component, DestroyRef, EventEmitter, forwardRef, Input, OnInit, Output } from '@angular/core'; import { AbstractControl, ControlValueAccessor, @@ -27,6 +27,7 @@ import { PageComponent } from '@shared/components/page.component'; import { Store } from '@ngrx/store'; import { AppState } from '@core/core.state'; import { TranslateService } from '@ngx-translate/core'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; export interface DataKeySelectOption { value: string; @@ -74,7 +75,8 @@ export class DataKeySelectOptionComponent extends PageComponent implements OnIni constructor(protected store: Store, private translate: TranslateService, - private fb: UntypedFormBuilder) { + private fb: UntypedFormBuilder, + private destroyRef: DestroyRef) { super(store); } @@ -83,7 +85,9 @@ export class DataKeySelectOptionComponent extends PageComponent implements OnIni value: [null, [Validators.required]], label: [null, []] }); - this.selectOptionFormGroup.valueChanges.subscribe(() => { + this.selectOptionFormGroup.valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateModel(); }); } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/input/update-attribute-general-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/input/update-attribute-general-settings.component.ts index 21ea72be69..1171864b3c 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/input/update-attribute-general-settings.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/input/update-attribute-general-settings.component.ts @@ -14,7 +14,7 @@ /// limitations under the License. /// -import { Component, forwardRef, Input, OnInit } from '@angular/core'; +import { Component, DestroyRef, forwardRef, Input, OnInit } from '@angular/core'; import { ControlValueAccessor, UntypedFormBuilder, @@ -28,6 +28,7 @@ import { PageComponent } from '@shared/components/page.component'; import { Store } from '@ngrx/store'; import { AppState } from '@core/core.state'; import { TranslateService } from '@ngx-translate/core'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; export interface UpdateAttributeGeneralSettings { widgetTitle: string; @@ -85,7 +86,8 @@ export class UpdateAttributeGeneralSettingsComponent extends PageComponent imple constructor(protected store: Store, private translate: TranslateService, - private fb: UntypedFormBuilder) { + private fb: UntypedFormBuilder, + private destroyRef: DestroyRef) { super(store); } @@ -99,14 +101,20 @@ export class UpdateAttributeGeneralSettingsComponent extends PageComponent imple }); if (this.hasLabelValue) { this.updateAttributeGeneralSettingsFormGroup.addControl('labelValue', this.fb.control('', [])); - this.updateAttributeGeneralSettingsFormGroup.get('showLabel').valueChanges.subscribe(() => { + this.updateAttributeGeneralSettingsFormGroup.get('showLabel').valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateValidators(true); }); } - this.updateAttributeGeneralSettingsFormGroup.get('isRequired').valueChanges.subscribe(() => { + this.updateAttributeGeneralSettingsFormGroup.get('isRequired').valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateValidators(true); }); - this.updateAttributeGeneralSettingsFormGroup.valueChanges.subscribe(() => { + this.updateAttributeGeneralSettingsFormGroup.valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateModel(); }); this.updateValidators(false); diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/map/circle-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/map/circle-settings.component.ts index f8e9b23b20..704f2b3b5b 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/map/circle-settings.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/map/circle-settings.component.ts @@ -14,7 +14,7 @@ /// limitations under the License. /// -import { Component, forwardRef, Input, OnInit } from '@angular/core'; +import { Component, DestroyRef, forwardRef, Input, OnInit } from '@angular/core'; import { ControlValueAccessor, UntypedFormBuilder, @@ -36,6 +36,7 @@ import { } from '@home/components/widget/lib/maps/map-models'; import { WidgetService } from '@core/http/widget.service'; import { Widget } from '@shared/models/widget.models'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; @Component({ selector: 'tb-circle-settings', @@ -77,7 +78,8 @@ export class CircleSettingsComponent extends PageComponent implements OnInit, Co constructor(protected store: Store, private translate: TranslateService, private widgetService: WidgetService, - private fb: UntypedFormBuilder) { + private fb: UntypedFormBuilder, + private destroyRef: DestroyRef) { super(store); } @@ -106,28 +108,44 @@ export class CircleSettingsComponent extends PageComponent implements OnInit, Co useCircleStrokeColorFunction: [null, []], circleStrokeColorFunction: [null, []] }); - this.circleSettingsFormGroup.valueChanges.subscribe(() => { + this.circleSettingsFormGroup.valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateModel(); }); - this.circleSettingsFormGroup.get('showCircle').valueChanges.subscribe(() => { + this.circleSettingsFormGroup.get('showCircle').valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateValidators(true); }); - this.circleSettingsFormGroup.get('showCircleLabel').valueChanges.subscribe(() => { + this.circleSettingsFormGroup.get('showCircleLabel').valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateValidators(true); }); - this.circleSettingsFormGroup.get('useCircleLabelFunction').valueChanges.subscribe(() => { + this.circleSettingsFormGroup.get('useCircleLabelFunction').valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateValidators(true); }); - this.circleSettingsFormGroup.get('showCircleTooltip').valueChanges.subscribe(() => { + this.circleSettingsFormGroup.get('showCircleTooltip').valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateValidators(true); }); - this.circleSettingsFormGroup.get('useCircleTooltipFunction').valueChanges.subscribe(() => { + this.circleSettingsFormGroup.get('useCircleTooltipFunction').valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateValidators(true); }); - this.circleSettingsFormGroup.get('useCircleFillColorFunction').valueChanges.subscribe(() => { + this.circleSettingsFormGroup.get('useCircleFillColorFunction').valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateValidators(true); }); - this.circleSettingsFormGroup.get('useCircleStrokeColorFunction').valueChanges.subscribe(() => { + this.circleSettingsFormGroup.get('useCircleStrokeColorFunction').valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateValidators(true); }); this.updateValidators(false); diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/map/common-map-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/map/common-map-settings.component.ts index 6e5c2bc255..09df84593d 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/map/common-map-settings.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/map/common-map-settings.component.ts @@ -14,7 +14,7 @@ /// limitations under the License. /// -import { Component, forwardRef, Input, OnChanges, OnInit, SimpleChanges } from '@angular/core'; +import { Component, DestroyRef, forwardRef, Input, OnChanges, OnInit, SimpleChanges } from '@angular/core'; import { ControlValueAccessor, UntypedFormBuilder, @@ -31,6 +31,7 @@ import { AppState } from '@core/core.state'; import { TranslateService } from '@ngx-translate/core'; import { CommonMapSettings, MapProviders } from '@home/components/widget/lib/maps/map-models'; import { Widget } from '@shared/models/widget.models'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; @Component({ selector: 'tb-common-map-settings', @@ -70,7 +71,8 @@ export class CommonMapSettingsComponent extends PageComponent implements OnInit, constructor(protected store: Store, private translate: TranslateService, - private fb: UntypedFormBuilder) { + private fb: UntypedFormBuilder, + private destroyRef: DestroyRef) { super(store); } @@ -89,7 +91,9 @@ export class CommonMapSettingsComponent extends PageComponent implements OnInit, useDefaultCenterPosition: [null, []], mapPageSize: [null, [Validators.min(1), Validators.required]] }); - this.commonMapSettingsFormGroup.valueChanges.subscribe(() => { + this.commonMapSettingsFormGroup.valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateModel(); }); this.updateValidators(false); diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/map/datasources-key-autocomplete.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/map/datasources-key-autocomplete.component.ts index b0b605c951..aca62b6f1e 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/map/datasources-key-autocomplete.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/map/datasources-key-autocomplete.component.ts @@ -14,7 +14,7 @@ /// limitations under the License. /// -import { Component, ElementRef, forwardRef, Input, OnInit, ViewChild } from '@angular/core'; +import { Component, DestroyRef, ElementRef, forwardRef, Input, OnInit, ViewChild } from '@angular/core'; import { ControlValueAccessor, UntypedFormBuilder, UntypedFormGroup, NG_VALUE_ACCESSOR, Validators } from '@angular/forms'; import { PageComponent } from '@shared/components/page.component'; import { Store } from '@ngrx/store'; @@ -25,6 +25,7 @@ import { map, mergeMap } from 'rxjs/operators'; import { Datasource } from '@shared/models/widget.models'; import { EntityService } from '@core/http/entity.service'; import { coerceBooleanProperty } from '@angular/cdk/coercion'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; @Component({ selector: 'tb-datasources-key-autocomplete', @@ -72,7 +73,8 @@ export class DatasourcesKeyAutocompleteComponent extends PageComponent implement constructor(protected store: Store, private translate: TranslateService, private entityService: EntityService, - private fb: UntypedFormBuilder) { + private fb: UntypedFormBuilder, + private destroyRef: DestroyRef) { super(store); } @@ -80,7 +82,9 @@ export class DatasourcesKeyAutocompleteComponent extends PageComponent implement this.keyFormGroup = this.fb.group({ key: [null, this.required ? [Validators.required] : []] }); - this.keyFormGroup.valueChanges.subscribe(() => { + this.keyFormGroup.valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateModel(); }); diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/map/google-map-provider-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/map/google-map-provider-settings.component.ts index bc175a4bbf..dde7175b1e 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/map/google-map-provider-settings.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/map/google-map-provider-settings.component.ts @@ -14,7 +14,7 @@ /// limitations under the License. /// -import { Component, forwardRef, Input, OnInit } from '@angular/core'; +import { Component, DestroyRef, forwardRef, Input, OnInit } from '@angular/core'; import { ControlValueAccessor, UntypedFormBuilder, @@ -34,6 +34,7 @@ import { GoogleMapType, googleMapTypeProviderTranslationMap } from '@home/components/widget/lib/maps/map-models'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; @Component({ selector: 'tb-google-map-provider-settings', @@ -69,7 +70,8 @@ export class GoogleMapProviderSettingsComponent extends PageComponent implements constructor(protected store: Store, private translate: TranslateService, - private fb: UntypedFormBuilder) { + private fb: UntypedFormBuilder, + private destroyRef: DestroyRef) { super(store); } @@ -78,7 +80,9 @@ export class GoogleMapProviderSettingsComponent extends PageComponent implements gmApiKey: [null, [Validators.required]], gmDefaultMapType: [null, [Validators.required]] }); - this.providerSettingsFormGroup.valueChanges.subscribe(() => { + this.providerSettingsFormGroup.valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateModel(); }); } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/map/here-map-provider-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/map/here-map-provider-settings.component.ts index b3b627de32..a5b63b26ee 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/map/here-map-provider-settings.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/map/here-map-provider-settings.component.ts @@ -14,7 +14,7 @@ /// limitations under the License. /// -import { Component, forwardRef, Input, OnInit } from '@angular/core'; +import { Component, DestroyRef, forwardRef, Input, OnInit } from '@angular/core'; import { ControlValueAccessor, FormBuilder, @@ -35,6 +35,7 @@ import { hereMapProviderTranslationMap } from '@home/components/widget/lib/maps/map-models'; import { isDefinedAndNotNull } from '@core/utils'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; @Component({ selector: 'tb-here-map-provider-settings', @@ -70,7 +71,8 @@ export class HereMapProviderSettingsComponent extends PageComponent implements O constructor(protected store: Store, private translate: TranslateService, - private fb: FormBuilder) { + private fb: FormBuilder, + private destroyRef: DestroyRef) { super(store); } @@ -84,7 +86,9 @@ export class HereMapProviderSettingsComponent extends PageComponent implements O apiKey: [null, [Validators.required]] }) }); - this.providerSettingsFormGroup.get('credentials.useV3').valueChanges.subscribe(value => { + this.providerSettingsFormGroup.get('credentials.useV3').valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(value => { if (value) { this.providerSettingsFormGroup.get('credentials.apiKey').enable({emitEvent: false}); this.providerSettingsFormGroup.get('credentials.app_id').disable({emitEvent: false}); @@ -95,7 +99,9 @@ export class HereMapProviderSettingsComponent extends PageComponent implements O this.providerSettingsFormGroup.get('credentials.app_code').enable({emitEvent: false}); } }); - this.providerSettingsFormGroup.valueChanges.subscribe(() => { + this.providerSettingsFormGroup.valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateModel(); }); } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/map/image-map-provider-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/map/image-map-provider-settings.component.ts index 51cc5ae6d7..9c655137a0 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/map/image-map-provider-settings.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/map/image-map-provider-settings.component.ts @@ -14,7 +14,7 @@ /// limitations under the License. /// -import { Component, ElementRef, forwardRef, Input, OnInit, ViewChild } from '@angular/core'; +import { Component, DestroyRef, ElementRef, forwardRef, Input, OnInit, ViewChild } from '@angular/core'; import { ControlValueAccessor, UntypedFormBuilder, @@ -35,6 +35,7 @@ import { catchError, map, mergeMap, publishReplay, refCount, startWith, tap } fr import { DataKey } from '@shared/models/widget.models'; import { DataKeyType } from '@shared/models/telemetry/telemetry.models'; import { EntityService } from '@core/http/entity.service'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; @Component({ selector: 'tb-image-map-provider-settings', @@ -85,7 +86,8 @@ export class ImageMapProviderSettingsComponent extends PageComponent implements constructor(protected store: Store, private translate: TranslateService, private entityService: EntityService, - private fb: UntypedFormBuilder) { + private fb: UntypedFormBuilder, + private destroyRef: DestroyRef) { super(store); } @@ -95,7 +97,9 @@ export class ImageMapProviderSettingsComponent extends PageComponent implements imageEntityAlias: [null, []], imageUrlAttribute: [null, []] }); - this.providerSettingsFormGroup.valueChanges.subscribe(() => { + this.providerSettingsFormGroup.valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateModel(); }); diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/map/map-editor-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/map/map-editor-settings.component.ts index b37e2d1447..7fed20ba9e 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/map/map-editor-settings.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/map/map-editor-settings.component.ts @@ -14,7 +14,7 @@ /// limitations under the License. /// -import { Component, forwardRef, Input, OnInit } from '@angular/core'; +import { Component, DestroyRef, forwardRef, Input, OnInit } from '@angular/core'; import { ControlValueAccessor, UntypedFormBuilder, @@ -30,6 +30,7 @@ import { AppState } from '@core/core.state'; import { TranslateService } from '@ngx-translate/core'; import { MapEditorSettings } from '@home/components/widget/lib/maps/map-models'; import { WidgetService } from '@core/http/widget.service'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; @Component({ selector: 'tb-map-editor-settings', @@ -62,7 +63,8 @@ export class MapEditorSettingsComponent extends PageComponent implements OnInit, constructor(protected store: Store, private translate: TranslateService, private widgetService: WidgetService, - private fb: UntypedFormBuilder) { + private fb: UntypedFormBuilder, + private destroyRef: DestroyRef) { super(store); } @@ -75,10 +77,14 @@ export class MapEditorSettingsComponent extends PageComponent implements OnInit, hideEditControlButton: [null, []], hideRemoveControlButton: [null, []], }); - this.mapEditorSettingsFormGroup.valueChanges.subscribe(() => { + this.mapEditorSettingsFormGroup.valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateModel(); }); - this.mapEditorSettingsFormGroup.get('hideAllControlButton').valueChanges.subscribe(() => { + this.mapEditorSettingsFormGroup.get('hideAllControlButton').valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateValidators(true); }); this.updateValidators(false); diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/map/map-provider-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/map/map-provider-settings.component.ts index 0f0fe7cc76..2bc7b93f76 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/map/map-provider-settings.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/map/map-provider-settings.component.ts @@ -14,7 +14,7 @@ /// limitations under the License. /// -import { Component, forwardRef, Input, OnInit } from '@angular/core'; +import { Component, DestroyRef, forwardRef, Input, OnInit } from '@angular/core'; import { ControlValueAccessor, UntypedFormBuilder, @@ -44,6 +44,7 @@ import { } from '@home/components/widget/lib/maps/map-models'; import { extractType } from '@core/utils'; import { IAliasController } from '@core/api/widget-api.models'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; @Component({ selector: 'tb-map-provider-settings', @@ -87,7 +88,8 @@ export class MapProviderSettingsComponent extends PageComponent implements OnIni constructor(protected store: Store, private translate: TranslateService, - private fb: UntypedFormBuilder) { + private fb: UntypedFormBuilder, + private destroyRef: DestroyRef) { super(store); } @@ -103,10 +105,14 @@ export class MapProviderSettingsComponent extends PageComponent implements OnIni imageMapProviderSettings: [null, []], tencentMapProviderSettings: [null, []] }); - this.providerSettingsFormGroup.valueChanges.subscribe(() => { + this.providerSettingsFormGroup.valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateModel(); }); - this.providerSettingsFormGroup.get('provider').valueChanges.subscribe(() => { + this.providerSettingsFormGroup.get('provider').valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateValidators(true); }); this.updateValidators(false); diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/map/map-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/map/map-settings.component.ts index 2bd3a78560..ad4ead491a 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/map/map-settings.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/map/map-settings.component.ts @@ -14,7 +14,7 @@ /// limitations under the License. /// -import { Component, forwardRef, Input, OnInit } from '@angular/core'; +import { Component, DestroyRef, forwardRef, Input, OnInit } from '@angular/core'; import { ControlValueAccessor, NG_VALIDATORS, @@ -50,6 +50,7 @@ import { import { extractType } from '@core/utils'; import { IAliasController } from '@core/api/widget-api.models'; import { Widget } from '@shared/models/widget.models'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; @Component({ selector: 'tb-map-settings', @@ -92,7 +93,8 @@ export class MapSettingsComponent extends PageComponent implements OnInit, Contr constructor(protected store: Store, private translate: TranslateService, - private fb: UntypedFormBuilder) { + private fb: UntypedFormBuilder, + private destroyRef: DestroyRef) { super(store); } @@ -110,19 +112,29 @@ export class MapSettingsComponent extends PageComponent implements OnInit, Contr this.mapSettingsFormGroup.addControl('markerClusteringSettings', this.fb.control(null, [])); } this.mapSettingsFormGroup.addControl('mapEditorSettings', this.fb.control(null, [])); - this.mapSettingsFormGroup.get('mapProviderSettings').valueChanges.subscribe(() => { + this.mapSettingsFormGroup.get('mapProviderSettings').valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateValidators(true); }); - this.mapSettingsFormGroup.get('markersSettings').valueChanges.subscribe(() => { + this.mapSettingsFormGroup.get('markersSettings').valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateValidators(true); }); - this.mapSettingsFormGroup.get('polygonSettings').valueChanges.subscribe(() => { + this.mapSettingsFormGroup.get('polygonSettings').valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateValidators(true); }); - this.mapSettingsFormGroup.get('circleSettings').valueChanges.subscribe(() => { + this.mapSettingsFormGroup.get('circleSettings').valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateValidators(true); }); - this.mapSettingsFormGroup.valueChanges.subscribe(() => { + this.mapSettingsFormGroup.valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateModel(); }); this.updateValidators(false); diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/map/marker-clustering-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/map/marker-clustering-settings.component.ts index bf622b6aa2..d648f951d9 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/map/marker-clustering-settings.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/map/marker-clustering-settings.component.ts @@ -14,7 +14,7 @@ /// limitations under the License. /// -import { Component, forwardRef, Input, OnInit } from '@angular/core'; +import { Component, DestroyRef, forwardRef, Input, OnInit } from '@angular/core'; import { ControlValueAccessor, UntypedFormBuilder, @@ -31,6 +31,7 @@ import { AppState } from '@core/core.state'; import { TranslateService } from '@ngx-translate/core'; import { MarkerClusteringSettings } from '@home/components/widget/lib/maps/map-models'; import { WidgetService } from '@core/http/widget.service'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; @Component({ selector: 'tb-marker-clustering-settings', @@ -65,7 +66,8 @@ export class MarkerClusteringSettingsComponent extends PageComponent implements constructor(protected store: Store, private translate: TranslateService, private widgetService: WidgetService, - private fb: UntypedFormBuilder) { + private fb: UntypedFormBuilder, + private destroyRef: DestroyRef) { super(store); } @@ -83,10 +85,14 @@ export class MarkerClusteringSettingsComponent extends PageComponent implements useIconCreateFunction: [null, []], clusterMarkerFunction: [null, []] }); - this.markerClusteringSettingsFormGroup.valueChanges.subscribe(() => { + this.markerClusteringSettingsFormGroup.valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateModel(); }); - this.markerClusteringSettingsFormGroup.get('useClusterMarkers').valueChanges.subscribe(() => { + this.markerClusteringSettingsFormGroup.get('useClusterMarkers').valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateValidators(true); }); this.updateValidators(false); diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/map/markers-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/map/markers-settings.component.ts index cf7be034eb..33ef1526ed 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/map/markers-settings.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/map/markers-settings.component.ts @@ -14,7 +14,7 @@ /// limitations under the License. /// -import { Component, forwardRef, Input, OnChanges, OnInit, SimpleChanges } from '@angular/core'; +import { Component, DestroyRef, forwardRef, Input, OnChanges, OnInit, SimpleChanges } from '@angular/core'; import { ControlValueAccessor, UntypedFormBuilder, @@ -33,6 +33,7 @@ import { MarkersSettings, ShowTooltipAction, showTooltipActionTranslationMap } from '@home/components/widget/lib/maps/map-models'; import { WidgetService } from '@core/http/widget.service'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; @Component({ selector: 'tb-markers-settings', @@ -76,7 +77,8 @@ export class MarkersSettingsComponent extends PageComponent implements OnInit, C constructor(protected store: Store, private translate: TranslateService, private widgetService: WidgetService, - private fb: UntypedFormBuilder) { + private fb: UntypedFormBuilder, + private destroyRef: DestroyRef) { super(store); } @@ -107,25 +109,39 @@ export class MarkersSettingsComponent extends PageComponent implements OnInit, C markerImageFunction: [null, []], markerImages: [null, []] }); - this.markersSettingsFormGroup.valueChanges.subscribe(() => { + this.markersSettingsFormGroup.valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateModel(); }); - this.markersSettingsFormGroup.get('showLabel').valueChanges.subscribe(() => { + this.markersSettingsFormGroup.get('showLabel').valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateValidators(true); }); - this.markersSettingsFormGroup.get('useLabelFunction').valueChanges.subscribe(() => { + this.markersSettingsFormGroup.get('useLabelFunction').valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateValidators(true); }); - this.markersSettingsFormGroup.get('showTooltip').valueChanges.subscribe(() => { + this.markersSettingsFormGroup.get('showTooltip').valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateValidators(true); }); - this.markersSettingsFormGroup.get('useTooltipFunction').valueChanges.subscribe(() => { + this.markersSettingsFormGroup.get('useTooltipFunction').valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateValidators(true); }); - this.markersSettingsFormGroup.get('useColorFunction').valueChanges.subscribe(() => { + this.markersSettingsFormGroup.get('useColorFunction').valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateValidators(true); }); - this.markersSettingsFormGroup.get('useMarkerImageFunction').valueChanges.subscribe(() => { + this.markersSettingsFormGroup.get('useMarkerImageFunction').valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateValidators(true); }); this.updateValidators(false); diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/map/openstreet-map-provider-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/map/openstreet-map-provider-settings.component.ts index b564f31dbe..14675fb5ef 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/map/openstreet-map-provider-settings.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/map/openstreet-map-provider-settings.component.ts @@ -14,7 +14,7 @@ /// limitations under the License. /// -import { Component, forwardRef, Input, OnInit } from '@angular/core'; +import { Component, DestroyRef, forwardRef, Input, OnInit } from '@angular/core'; import { ControlValueAccessor, UntypedFormBuilder, @@ -34,6 +34,7 @@ import { OpenStreetMapProviderSettings, openStreetMapProviderTranslationMap } from '@home/components/widget/lib/maps/map-models'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; @Component({ selector: 'tb-openstreet-map-provider-settings', @@ -69,7 +70,8 @@ export class OpenStreetMapProviderSettingsComponent extends PageComponent implem constructor(protected store: Store, private translate: TranslateService, - private fb: UntypedFormBuilder) { + private fb: UntypedFormBuilder, + private destroyRef: DestroyRef) { super(store); } @@ -79,10 +81,14 @@ export class OpenStreetMapProviderSettingsComponent extends PageComponent implem useCustomProvider: [null, []], customProviderTileUrl: [null, [Validators.required]] }); - this.providerSettingsFormGroup.valueChanges.subscribe(() => { + this.providerSettingsFormGroup.valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateModel(); }); - this.providerSettingsFormGroup.get('useCustomProvider').valueChanges.subscribe(() => { + this.providerSettingsFormGroup.get('useCustomProvider').valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateValidators(true); }); this.updateValidators(false); diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/map/polygon-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/map/polygon-settings.component.ts index e87ce981ad..ae0fd0c1f1 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/map/polygon-settings.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/map/polygon-settings.component.ts @@ -14,7 +14,7 @@ /// limitations under the License. /// -import { Component, forwardRef, Input, OnInit } from '@angular/core'; +import { Component, DestroyRef, forwardRef, Input, OnInit } from '@angular/core'; import { ControlValueAccessor, UntypedFormBuilder, @@ -36,6 +36,7 @@ import { } from '@home/components/widget/lib/maps/map-models'; import { WidgetService } from '@core/http/widget.service'; import { Widget } from '@shared/models/widget.models'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; @Component({ selector: 'tb-polygon-settings', @@ -77,7 +78,8 @@ export class PolygonSettingsComponent extends PageComponent implements OnInit, C constructor(protected store: Store, private translate: TranslateService, private widgetService: WidgetService, - private fb: UntypedFormBuilder) { + private fb: UntypedFormBuilder, + private destroyRef: DestroyRef) { super(store); } @@ -106,28 +108,44 @@ export class PolygonSettingsComponent extends PageComponent implements OnInit, C usePolygonStrokeColorFunction: [null, []], polygonStrokeColorFunction: [null, []] }); - this.polygonSettingsFormGroup.valueChanges.subscribe(() => { + this.polygonSettingsFormGroup.valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateModel(); }); - this.polygonSettingsFormGroup.get('showPolygon').valueChanges.subscribe(() => { + this.polygonSettingsFormGroup.get('showPolygon').valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateValidators(true); }); - this.polygonSettingsFormGroup.get('showPolygonLabel').valueChanges.subscribe(() => { + this.polygonSettingsFormGroup.get('showPolygonLabel').valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateValidators(true); }); - this.polygonSettingsFormGroup.get('usePolygonLabelFunction').valueChanges.subscribe(() => { + this.polygonSettingsFormGroup.get('usePolygonLabelFunction').valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateValidators(true); }); - this.polygonSettingsFormGroup.get('showPolygonTooltip').valueChanges.subscribe(() => { + this.polygonSettingsFormGroup.get('showPolygonTooltip').valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateValidators(true); }); - this.polygonSettingsFormGroup.get('usePolygonTooltipFunction').valueChanges.subscribe(() => { + this.polygonSettingsFormGroup.get('usePolygonTooltipFunction').valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateValidators(true); }); - this.polygonSettingsFormGroup.get('usePolygonColorFunction').valueChanges.subscribe(() => { + this.polygonSettingsFormGroup.get('usePolygonColorFunction').valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateValidators(true); }); - this.polygonSettingsFormGroup.get('usePolygonStrokeColorFunction').valueChanges.subscribe(() => { + this.polygonSettingsFormGroup.get('usePolygonStrokeColorFunction').valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateValidators(true); }); this.updateValidators(false); diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/map/route-map-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/map/route-map-settings.component.ts index a34d9b55a6..3ccbf9211c 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/map/route-map-settings.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/map/route-map-settings.component.ts @@ -14,7 +14,7 @@ /// limitations under the License. /// -import { Component, forwardRef, Input, OnInit } from '@angular/core'; +import { Component, DestroyRef, forwardRef, Input, OnInit } from '@angular/core'; import { ControlValueAccessor, UntypedFormBuilder, @@ -30,6 +30,7 @@ import { AppState } from '@core/core.state'; import { TranslateService } from '@ngx-translate/core'; import { PolylineSettings } from '@home/components/widget/lib/maps/map-models'; import { WidgetService } from '@core/http/widget.service'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; @Component({ selector: 'tb-route-map-settings', @@ -62,7 +63,8 @@ export class RouteMapSettingsComponent extends PageComponent implements OnInit, constructor(protected store: Store, private translate: TranslateService, private widgetService: WidgetService, - private fb: UntypedFormBuilder) { + private fb: UntypedFormBuilder, + private destroyRef: DestroyRef) { super(store); } @@ -71,7 +73,9 @@ export class RouteMapSettingsComponent extends PageComponent implements OnInit, strokeWeight: [null, [Validators.min(0)]], strokeOpacity: [null, [Validators.min(0), Validators.max(1)]] }); - this.routeMapSettingsFormGroup.valueChanges.subscribe(() => { + this.routeMapSettingsFormGroup.valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateModel(); }); } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/map/tencent-map-provider-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/map/tencent-map-provider-settings.component.ts index c2412866b3..868af4968c 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/map/tencent-map-provider-settings.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/map/tencent-map-provider-settings.component.ts @@ -14,7 +14,7 @@ /// limitations under the License. /// -import { Component, forwardRef, Input, OnInit } from '@angular/core'; +import { Component, DestroyRef, forwardRef, Input, OnInit } from '@angular/core'; import { ControlValueAccessor, UntypedFormBuilder, @@ -34,6 +34,7 @@ import { TencentMapType, tencentMapTypeProviderTranslationMap } from '@home/components/widget/lib/maps/map-models'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; @Component({ selector: 'tb-tencent-map-provider-settings', @@ -69,7 +70,8 @@ export class TencentMapProviderSettingsComponent extends PageComponent implement constructor(protected store: Store, private translate: TranslateService, - private fb: UntypedFormBuilder) { + private fb: UntypedFormBuilder, + private destroyRef: DestroyRef) { super(store); } @@ -78,7 +80,9 @@ export class TencentMapProviderSettingsComponent extends PageComponent implement tmApiKey: [null, [Validators.required]], tmDefaultMapType: [null, [Validators.required]] }); - this.providerSettingsFormGroup.valueChanges.subscribe(() => { + this.providerSettingsFormGroup.valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateModel(); }); } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/map/trip-animation-common-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/map/trip-animation-common-settings.component.ts index de05df2baa..1e7c484bdb 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/map/trip-animation-common-settings.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/map/trip-animation-common-settings.component.ts @@ -14,7 +14,7 @@ /// limitations under the License. /// -import { Component, forwardRef, Input, OnInit } from '@angular/core'; +import { Component, DestroyRef, forwardRef, Input, OnInit } from '@angular/core'; import { ControlValueAccessor, UntypedFormBuilder, @@ -32,6 +32,7 @@ import { TranslateService } from '@ngx-translate/core'; import { TripAnimationCommonSettings } from '@home/components/widget/lib/maps/map-models'; import { Widget } from '@shared/models/widget.models'; import { WidgetService } from '@core/http/widget.service'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; @Component({ selector: 'tb-trip-animation-common-settings', @@ -69,7 +70,8 @@ export class TripAnimationCommonSettingsComponent extends PageComponent implemen constructor(protected store: Store, private translate: TranslateService, private widgetService: WidgetService, - private fb: UntypedFormBuilder) { + private fb: UntypedFormBuilder, + private destroyRef: DestroyRef) { super(store); } @@ -87,13 +89,19 @@ export class TripAnimationCommonSettingsComponent extends PageComponent implemen tooltipPattern: [null, []], tooltipFunction: [null, []], }); - this.tripAnimationCommonSettingsFormGroup.valueChanges.subscribe(() => { + this.tripAnimationCommonSettingsFormGroup.valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateModel(); }); - this.tripAnimationCommonSettingsFormGroup.get('showTooltip').valueChanges.subscribe(() => { + this.tripAnimationCommonSettingsFormGroup.get('showTooltip').valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateValidators(true); }); - this.tripAnimationCommonSettingsFormGroup.get('useTooltipFunction').valueChanges.subscribe(() => { + this.tripAnimationCommonSettingsFormGroup.get('useTooltipFunction').valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateValidators(true); }); this.updateValidators(false); diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/map/trip-animation-marker-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/map/trip-animation-marker-settings.component.ts index 1a839126e6..422bcd3a2c 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/map/trip-animation-marker-settings.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/map/trip-animation-marker-settings.component.ts @@ -14,7 +14,7 @@ /// limitations under the License. /// -import { Component, forwardRef, Input, OnInit } from '@angular/core'; +import { Component, DestroyRef, forwardRef, Input, OnInit } from '@angular/core'; import { ControlValueAccessor, UntypedFormBuilder, @@ -31,6 +31,7 @@ import { AppState } from '@core/core.state'; import { TranslateService } from '@ngx-translate/core'; import { TripAnimationMarkerSettings } from '@home/components/widget/lib/maps/map-models'; import { WidgetService } from '@core/http/widget.service'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; @Component({ selector: 'tb-trip-animation-marker-settings', @@ -65,7 +66,8 @@ export class TripAnimationMarkerSettingsComponent extends PageComponent implemen constructor(protected store: Store, private translate: TranslateService, private widgetService: WidgetService, - private fb: UntypedFormBuilder) { + private fb: UntypedFormBuilder, + private destroyRef: DestroyRef) { super(store); } @@ -82,16 +84,24 @@ export class TripAnimationMarkerSettingsComponent extends PageComponent implemen markerImageFunction: [null, []], markerImages: [null, []] }); - this.tripAnimationMarkerSettingsFormGroup.valueChanges.subscribe(() => { + this.tripAnimationMarkerSettingsFormGroup.valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateModel(); }); - this.tripAnimationMarkerSettingsFormGroup.get('showLabel').valueChanges.subscribe(() => { + this.tripAnimationMarkerSettingsFormGroup.get('showLabel').valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateValidators(true); }); - this.tripAnimationMarkerSettingsFormGroup.get('useLabelFunction').valueChanges.subscribe(() => { + this.tripAnimationMarkerSettingsFormGroup.get('useLabelFunction').valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateValidators(true); }); - this.tripAnimationMarkerSettingsFormGroup.get('useMarkerImageFunction').valueChanges.subscribe(() => { + this.tripAnimationMarkerSettingsFormGroup.get('useMarkerImageFunction').valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateValidators(true); }); this.updateValidators(false); diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/map/trip-animation-path-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/map/trip-animation-path-settings.component.ts index 13cb5ea8f8..e8fd9b64c5 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/map/trip-animation-path-settings.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/map/trip-animation-path-settings.component.ts @@ -14,7 +14,7 @@ /// limitations under the License. /// -import { Component, forwardRef, Input, OnInit } from '@angular/core'; +import { Component, DestroyRef, forwardRef, Input, OnInit } from '@angular/core'; import { ControlValueAccessor, UntypedFormBuilder, @@ -34,6 +34,7 @@ import { PolylineSettings } from '@home/components/widget/lib/maps/map-models'; import { WidgetService } from '@core/http/widget.service'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; @Component({ selector: 'tb-trip-animation-path-settings', @@ -72,7 +73,8 @@ export class TripAnimationPathSettingsComponent extends PageComponent implements constructor(protected store: Store, private translate: TranslateService, private widgetService: WidgetService, - private fb: UntypedFormBuilder) { + private fb: UntypedFormBuilder, + private destroyRef: DestroyRef) { super(store); } @@ -92,16 +94,24 @@ export class TripAnimationPathSettingsComponent extends PageComponent implements endDecoratorOffset: [null, []], decoratorRepeat: [null, []], }); - this.tripAnimationPathSettingsFormGroup.valueChanges.subscribe(() => { + this.tripAnimationPathSettingsFormGroup.valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateModel(); }); - this.tripAnimationPathSettingsFormGroup.get('useColorFunction').valueChanges.subscribe(() => { + this.tripAnimationPathSettingsFormGroup.get('useColorFunction').valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateValidators(true); }); - this.tripAnimationPathSettingsFormGroup.get('usePolylineDecorator').valueChanges.subscribe(() => { + this.tripAnimationPathSettingsFormGroup.get('usePolylineDecorator').valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateValidators(true); }); - this.tripAnimationPathSettingsFormGroup.get('useDecoratorCustomColor').valueChanges.subscribe(() => { + this.tripAnimationPathSettingsFormGroup.get('useDecoratorCustomColor').valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateValidators(true); }); this.updateValidators(false); diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/map/trip-animation-point-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/map/trip-animation-point-settings.component.ts index c934ff0b96..91ef694292 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/map/trip-animation-point-settings.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/map/trip-animation-point-settings.component.ts @@ -14,7 +14,7 @@ /// limitations under the License. /// -import { Component, forwardRef, Input, OnInit } from '@angular/core'; +import { Component, DestroyRef, forwardRef, Input, OnInit } from '@angular/core'; import { ControlValueAccessor, UntypedFormBuilder, @@ -35,6 +35,7 @@ import { PolylineSettings } from '@home/components/widget/lib/maps/map-models'; import { WidgetService } from '@core/http/widget.service'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; @Component({ selector: 'tb-trip-animation-point-settings', @@ -69,7 +70,8 @@ export class TripAnimationPointSettingsComponent extends PageComponent implement constructor(protected store: Store, private translate: TranslateService, private widgetService: WidgetService, - private fb: UntypedFormBuilder) { + private fb: UntypedFormBuilder, + private destroyRef: DestroyRef) { super(store); } @@ -84,16 +86,24 @@ export class TripAnimationPointSettingsComponent extends PageComponent implement pointAsAnchorFunction: [null, []], pointTooltipOnRightPanel: [null, []] }); - this.tripAnimationPointSettingsFormGroup.valueChanges.subscribe(() => { + this.tripAnimationPointSettingsFormGroup.valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateModel(); }); - this.tripAnimationPointSettingsFormGroup.get('showPoints').valueChanges.subscribe(() => { + this.tripAnimationPointSettingsFormGroup.get('showPoints').valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateValidators(true); }); - this.tripAnimationPointSettingsFormGroup.get('useColorPointFunction').valueChanges.subscribe(() => { + this.tripAnimationPointSettingsFormGroup.get('useColorPointFunction').valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateValidators(true); }); - this.tripAnimationPointSettingsFormGroup.get('usePointAsAnchor').valueChanges.subscribe(() => { + this.tripAnimationPointSettingsFormGroup.get('usePointAsAnchor').valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateValidators(true); }); this.updateValidators(false); diff --git a/ui-ngx/src/app/modules/home/components/widget/widget-config.component.ts b/ui-ngx/src/app/modules/home/components/widget/widget-config.component.ts index b6c5e02d2b..b70b75d52a 100644 --- a/ui-ngx/src/app/modules/home/components/widget/widget-config.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/widget-config.component.ts @@ -18,6 +18,7 @@ import { ChangeDetectorRef, Component, ComponentRef, + DestroyRef, forwardRef, Input, OnDestroy, @@ -84,6 +85,7 @@ import { coerceBoolean } from '@shared/decorators/coercion'; import { basicWidgetConfigComponentsMap } from '@home/components/widget/config/basic/basic-widget-config.module'; import { TimewindowConfigData } from '@home/components/widget/config/timewindow-config-panel.component'; import { DataKeySettingsFunction } from '@home/components/widget/config/data-keys.component.models'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import Timeout = NodeJS.Timeout; const emptySettingsSchema: JsonSchema = { @@ -213,7 +215,8 @@ export class WidgetConfigComponent extends PageComponent implements OnInit, OnDe private dialog: MatDialog, public translate: TranslateService, private fb: UntypedFormBuilder, - private cd: ChangeDetectorRef) { + private cd: ChangeDetectorRef, + private destroyRef: DestroyRef) { super(store); } @@ -248,7 +251,10 @@ export class WidgetConfigComponent extends PageComponent implements OnInit, OnDe }); merge(this.widgetSettings.get('showTitle').valueChanges, - this.widgetSettings.get('showTitleIcon').valueChanges).subscribe(() => { + this.widgetSettings.get('showTitleIcon').valueChanges + ).pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateWidgetSettingsEnabledState(); }); @@ -261,7 +267,9 @@ export class WidgetConfigComponent extends PageComponent implements OnInit, OnDe desktopHide: [false] }); - this.layoutSettings.get('resizable').valueChanges.subscribe(() => { + this.layoutSettings.get('resizable').valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateLayoutEnabledState(); }); diff --git a/ui-ngx/src/app/modules/home/pages/admin/mail-server.component.html b/ui-ngx/src/app/modules/home/pages/admin/mail-server.component.html index ff10de6fc2..35ba6048c0 100644 --- a/ui-ngx/src/app/modules/home/pages/admin/mail-server.component.html +++ b/ui-ngx/src/app/modules/home/pages/admin/mail-server.component.html @@ -243,23 +243,11 @@ - - admin.oauth2.scope - - - {{scope}} - cancel - - - - - {{ 'admin.oauth2.scope-required' | translate }} - - + + diff --git a/ui-ngx/src/app/modules/home/pages/admin/mail-server.component.ts b/ui-ngx/src/app/modules/home/pages/admin/mail-server.component.ts index 3db82626fe..9cf14e8c49 100644 --- a/ui-ngx/src/app/modules/home/pages/admin/mail-server.component.ts +++ b/ui-ngx/src/app/modules/home/pages/admin/mail-server.component.ts @@ -18,8 +18,7 @@ import { Component, Inject, OnDestroy, OnInit } from '@angular/core'; import { Store } from '@ngrx/store'; import { AppState } from '@core/core.state'; import { PageComponent } from '@shared/components/page.component'; -import { FormBuilder, FormGroup, UntypedFormArray, Validators } from '@angular/forms'; -import { ActivatedRoute, Router } from '@angular/router'; +import { FormBuilder, FormGroup, Validators } from '@angular/forms'; import { AdminSettings, MailConfigTemplate, @@ -37,9 +36,6 @@ import { forkJoin, Subject } from 'rxjs'; import { takeUntil } from 'rxjs/operators'; import { DomainSchema, domainSchemaTranslations, } from '@shared/models/oauth2.models'; import { WINDOW } from '@core/services/window.service'; -import { AuthService } from '@core/auth/auth.service'; -import { COMMA, ENTER } from '@angular/cdk/keycodes'; -import { MatChipInputEvent } from '@angular/material/chips'; @Component({ selector: 'tb-mail-server', @@ -51,7 +47,7 @@ export class MailServerComponent extends PageComponent implements OnInit, OnDest smtpProtocols = Object.values(SmtpProtocol); showChangePassword = false; - protocols = Object.values(DomainSchema).filter(value => value !== DomainSchema.MIXED); + protocols: DomainSchema[] = Object.values(DomainSchema).filter(value => value !== DomainSchema.MIXED); domainSchemaTranslations = domainSchemaTranslations; mailServerOauth2Provider = MailServerOauth2Provider; @@ -64,8 +60,6 @@ export class MailServerComponent extends PageComponent implements OnInit, OnDest templateProvider = ['CUSTOM']; - readonly separatorKeysCodes: number[] = [ENTER, COMMA]; - private destroy$ = new Subject(); private DOMAIN_AND_PORT_REGEXP = /^(?:\w+(?::\w+)?@)?[^\s/]+(?::\d+)?$/; private URL_REGEXP = /^[A-Za-z][A-Za-z\d.+-]*:\/*(?:\w+(?::\w+)?@)?[^\s/]+(?::\d+)?(?:\/[\w#!:.,?+=&%@\-/]*)?$/; @@ -98,7 +92,7 @@ export class MailServerComponent extends PageComponent implements OnInit, OnDest providerTenantId: [{value: '', disabled: true}, [Validators.required]], authUri: [{value: '', disabled: true}, [Validators.required, Validators.pattern(this.URL_REGEXP)]], tokenUri: [{value: '', disabled: true}, [Validators.required, Validators.pattern(this.URL_REGEXP)]], - scope: [], + scope: this.fb.control>({value: [], disabled: true}, Validators.required), redirectUri: [{ value:'', disabled: true}] }); @@ -134,10 +128,7 @@ export class MailServerComponent extends PageComponent implements OnInit, OnDest }); constructor(protected store: Store, - private router: Router, - private route: ActivatedRoute, private adminService: AdminService, - private authService: AuthService, private translate: TranslateService, public fb: FormBuilder, @Inject(WINDOW) private window: Window) { @@ -148,14 +139,14 @@ export class MailServerComponent extends PageComponent implements OnInit, OnDest this.mailServerSettingsForm(); this.domainFormConfiguration(); - forkJoin([ - this.adminService.getLoginProcessingUrl(), - this.adminService.getMailConfigTemplate(), - this.adminService.getAdminSettings('mail') - ]).subscribe(([loginProcessingUrl, mailConfigTemplate, adminSettings]) => { - this.loginProcessingUrl = loginProcessingUrl; - this.initTemplates(mailConfigTemplate); - this.adminSettings = adminSettings; + forkJoin({ + loginProcessingUrl: this.adminService.getLoginProcessingUrl(), + mailConfigTemplate: this.adminService.getMailConfigTemplate(), + adminSettings: this.adminService.getAdminSettings('mail') + }).subscribe((data) => { + this.loginProcessingUrl = data.loginProcessingUrl; + this.initTemplates(data.mailConfigTemplate); + this.adminSettings = data.adminSettings; if (this.adminSettings.jsonValue && isString(this.adminSettings.jsonValue.enableTls)) { this.adminSettings.jsonValue.enableTls = (this.adminSettings.jsonValue.enableTls as any) === 'true'; } @@ -187,7 +178,7 @@ export class MailServerComponent extends PageComponent implements OnInit, OnDest super.ngOnDestroy(); } - private initTemplates(templates): void { + private initTemplates(templates: Array): void { templates.map(provider => { delete provider.additionalInfo; this.templates.set(provider.providerId, provider); @@ -294,6 +285,7 @@ export class MailServerComponent extends PageComponent implements OnInit, OnDest this.mailSettings.get('clientId').enable({emitEvent: false}); this.mailSettings.get('clientSecret').enable({emitEvent: false}); this.mailSettings.get('redirectUri').enable({emitEvent: false}); + this.mailSettings.get('scope').enable({emitEvent: false}); if (this.mailSettings.get('providerId').value === this.mailServerOauth2Provider.CUSTOM) { this.mailSettings.get('authUri').enable({emitEvent: false}); this.mailSettings.get('tokenUri').enable({emitEvent: false}); @@ -307,6 +299,7 @@ export class MailServerComponent extends PageComponent implements OnInit, OnDest this.mailSettings.get('redirectUri').disable({emitEvent: false}); this.mailSettings.get('authUri').disable({emitEvent: false}); this.mailSettings.get('tokenUri').disable({emitEvent: false}); + this.mailSettings.get('scope').disable({emitEvent: false}); } } @@ -422,31 +415,6 @@ export class MailServerComponent extends PageComponent implements OnInit, OnDest return formValue; } - trackByParams(index: number): number { - return index; - } - - removeScope(i: number): void { - const controller = this.mailSettings.get('scope') as UntypedFormArray; - controller.removeAt(i); - controller.markAsTouched(); - controller.markAsDirty(); - } - - addScope(event: MatChipInputEvent): void { - const input = event.chipInput.inputElement; - const value = event.value; - const controller = this.mailSettings.get('scope') as UntypedFormArray; - if ((value.trim() !== '')) { - controller.push(this.fb.control(value.trim())); - controller.markAsDirty(); - } - - if (input) { - input.value = ''; - } - } - toggleEditMode(path: string): void { this.mailSettings.get(path).disabled ? this.mailSettings.get(path).enable() : this.mailSettings.get(path).disable(); } diff --git a/ui-ngx/src/app/modules/home/pages/admin/security-settings.component.ts b/ui-ngx/src/app/modules/home/pages/admin/security-settings.component.ts index 01eff581a5..f763f6e003 100644 --- a/ui-ngx/src/app/modules/home/pages/admin/security-settings.component.ts +++ b/ui-ngx/src/app/modules/home/pages/admin/security-settings.component.ts @@ -14,7 +14,7 @@ /// limitations under the License. /// -import { Component } from '@angular/core'; +import { Component, DestroyRef } from '@angular/core'; import { Store } from '@ngrx/store'; import { AppState } from '@core/core.state'; import { PageComponent } from '@shared/components/page.component'; @@ -37,6 +37,7 @@ import { AuthService } from '@core/auth/auth.service'; import { DialogService } from '@core/services/dialog.service'; import { TranslateService } from '@ngx-translate/core'; import { Observable, of } from 'rxjs'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; @Component({ selector: 'tb-security-settings', @@ -59,7 +60,8 @@ export class SecuritySettingsComponent extends PageComponent implements HasConfi private authService: AuthService, private dialogService: DialogService, private translate: TranslateService, - private fb: UntypedFormBuilder) { + private fb: UntypedFormBuilder, + private destroyRef: DestroyRef) { super(store); this.buildSecuritySettingsForm(); this.buildJwtSecuritySettingsForm(); @@ -102,7 +104,9 @@ export class SecuritySettingsComponent extends PageComponent implements HasConfi tokenExpirationTime: [0, [Validators.required, Validators.min(60), Validators.max(2147483647)]], refreshTokenExpTime: [0, [Validators.required, Validators.min(900), Validators.max(2147483647)]] }, {validators: this.refreshTokenTimeGreatTokenTime.bind(this)}); - this.jwtSecuritySettingsFormGroup.get('tokenExpirationTime').valueChanges.subscribe( + this.jwtSecuritySettingsFormGroup.get('tokenExpirationTime').valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe( () => this.jwtSecuritySettingsFormGroup.get('refreshTokenExpTime').updateValueAndValidity({onlySelf: true}) ); } diff --git a/ui-ngx/src/app/modules/home/pages/device-profile/device-profile-tabs.component.ts b/ui-ngx/src/app/modules/home/pages/device-profile/device-profile-tabs.component.ts index 4a519fc52b..65aab17297 100644 --- a/ui-ngx/src/app/modules/home/pages/device-profile/device-profile-tabs.component.ts +++ b/ui-ngx/src/app/modules/home/pages/device-profile/device-profile-tabs.component.ts @@ -14,7 +14,7 @@ /// limitations under the License. /// -import { Component } from '@angular/core'; +import { Component, DestroyRef } from '@angular/core'; import { Store } from '@ngrx/store'; import { AppState } from '@core/core.state'; import { EntityTabsComponent } from '../../components/entity/entity-tabs.component'; @@ -24,6 +24,7 @@ import { deviceTransportTypeHintMap, deviceTransportTypeTranslationMap } from '@shared/models/device.models'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; @Component({ selector: 'tb-device-profile-tabs', @@ -40,13 +41,16 @@ export class DeviceProfileTabsComponent extends EntityTabsComponent) { + constructor(protected store: Store, + private destroyRef: DestroyRef) { super(store); } ngOnInit() { super.ngOnInit(); - this.detailsForm.get('transportType').valueChanges.subscribe(() => { + this.detailsForm.get('transportType').valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.isTransportTypeChanged = true; }); } diff --git a/ui-ngx/src/app/modules/home/pages/device/data/default-device-configuration.component.ts b/ui-ngx/src/app/modules/home/pages/device/data/default-device-configuration.component.ts index 034d7c26de..46eafb44e5 100644 --- a/ui-ngx/src/app/modules/home/pages/device/data/default-device-configuration.component.ts +++ b/ui-ngx/src/app/modules/home/pages/device/data/default-device-configuration.component.ts @@ -14,7 +14,7 @@ /// limitations under the License. /// -import { Component, forwardRef, Input, OnInit } from '@angular/core'; +import { Component, DestroyRef, forwardRef, Input, OnInit } from '@angular/core'; import { ControlValueAccessor, UntypedFormBuilder, UntypedFormGroup, NG_VALUE_ACCESSOR, Validators } from '@angular/forms'; import { Store } from '@ngrx/store'; import { AppState } from '@app/core/core.state'; @@ -24,6 +24,7 @@ import { DeviceConfiguration, DeviceProfileType } from '@shared/models/device.models'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; @Component({ selector: 'tb-default-device-configuration', @@ -54,7 +55,8 @@ export class DefaultDeviceConfigurationComponent implements ControlValueAccessor private propagateChange = (v: any) => { }; constructor(private store: Store, - private fb: UntypedFormBuilder) { + private fb: UntypedFormBuilder, + private destroyRef: DestroyRef) { } registerOnChange(fn: any): void { @@ -68,7 +70,9 @@ export class DefaultDeviceConfigurationComponent implements ControlValueAccessor this.defaultDeviceConfigurationFormGroup = this.fb.group({ configuration: [null, Validators.required] }); - this.defaultDeviceConfigurationFormGroup.valueChanges.subscribe(() => { + this.defaultDeviceConfigurationFormGroup.valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateModel(); }); } diff --git a/ui-ngx/src/app/modules/home/pages/device/data/default-device-transport-configuration.component.ts b/ui-ngx/src/app/modules/home/pages/device/data/default-device-transport-configuration.component.ts index d04df8a40f..fdf2dfb2b2 100644 --- a/ui-ngx/src/app/modules/home/pages/device/data/default-device-transport-configuration.component.ts +++ b/ui-ngx/src/app/modules/home/pages/device/data/default-device-transport-configuration.component.ts @@ -14,7 +14,7 @@ /// limitations under the License. /// -import { Component, forwardRef, Input, OnInit } from '@angular/core'; +import { Component, DestroyRef, forwardRef, Input, OnInit } from '@angular/core'; import { ControlValueAccessor, UntypedFormBuilder, UntypedFormGroup, NG_VALUE_ACCESSOR, Validators } from '@angular/forms'; import { Store } from '@ngrx/store'; import { AppState } from '@app/core/core.state'; @@ -24,6 +24,7 @@ import { DeviceTransportConfiguration, DeviceTransportType } from '@shared/models/device.models'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; @Component({ selector: 'tb-default-device-transport-configuration', @@ -54,7 +55,8 @@ export class DefaultDeviceTransportConfigurationComponent implements ControlValu private propagateChange = (v: any) => { }; constructor(private store: Store, - private fb: UntypedFormBuilder) { + private fb: UntypedFormBuilder, + private destroyRef: DestroyRef) { } registerOnChange(fn: any): void { @@ -68,7 +70,9 @@ export class DefaultDeviceTransportConfigurationComponent implements ControlValu this.defaultDeviceTransportConfigurationFormGroup = this.fb.group({ configuration: [null, Validators.required] }); - this.defaultDeviceTransportConfigurationFormGroup.valueChanges.subscribe(() => { + this.defaultDeviceTransportConfigurationFormGroup.valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateModel(); }); } diff --git a/ui-ngx/src/app/modules/home/pages/device/data/device-configuration.component.ts b/ui-ngx/src/app/modules/home/pages/device/data/device-configuration.component.ts index 4748d4bc3c..732203cc2c 100644 --- a/ui-ngx/src/app/modules/home/pages/device/data/device-configuration.component.ts +++ b/ui-ngx/src/app/modules/home/pages/device/data/device-configuration.component.ts @@ -14,13 +14,14 @@ /// limitations under the License. /// -import { Component, forwardRef, Input, OnInit } from '@angular/core'; +import { Component, DestroyRef, forwardRef, Input, OnInit } from '@angular/core'; import { ControlValueAccessor, UntypedFormBuilder, UntypedFormGroup, NG_VALUE_ACCESSOR, Validators } from '@angular/forms'; import { Store } from '@ngrx/store'; import { AppState } from '@app/core/core.state'; import { coerceBooleanProperty } from '@angular/cdk/coercion'; import { DeviceConfiguration, DeviceProfileType } from '@shared/models/device.models'; import { deepClone } from '@core/utils'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; @Component({ selector: 'tb-device-configuration', @@ -55,7 +56,8 @@ export class DeviceConfigurationComponent implements ControlValueAccessor, OnIni private propagateChange = (v: any) => { }; constructor(private store: Store, - private fb: UntypedFormBuilder) { + private fb: UntypedFormBuilder, + private destroyRef: DestroyRef) { } registerOnChange(fn: any): void { @@ -69,7 +71,9 @@ export class DeviceConfigurationComponent implements ControlValueAccessor, OnIni this.deviceConfigurationFormGroup = this.fb.group({ configuration: [null, Validators.required] }); - this.deviceConfigurationFormGroup.valueChanges.subscribe(() => { + this.deviceConfigurationFormGroup.valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateModel(); }); } diff --git a/ui-ngx/src/app/modules/home/pages/device/data/device-data.component.ts b/ui-ngx/src/app/modules/home/pages/device/data/device-data.component.ts index ed1fd3ecd0..2032371121 100644 --- a/ui-ngx/src/app/modules/home/pages/device/data/device-data.component.ts +++ b/ui-ngx/src/app/modules/home/pages/device/data/device-data.component.ts @@ -14,7 +14,7 @@ /// limitations under the License. /// -import { Component, forwardRef, Input, OnInit } from '@angular/core'; +import { Component, DestroyRef, forwardRef, Input, OnInit } from '@angular/core'; import { ControlValueAccessor, UntypedFormBuilder, @@ -33,6 +33,7 @@ import { deviceProfileTypeConfigurationInfoMap, deviceTransportTypeConfigurationInfoMap } from '@shared/models/device.models'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; @Component({ selector: 'tb-device-data', @@ -73,7 +74,8 @@ export class DeviceDataComponent implements ControlValueAccessor, OnInit, Valida private propagateChange = (v: any) => { }; constructor(private store: Store, - private fb: UntypedFormBuilder) { + private fb: UntypedFormBuilder, + private destroyRef: DestroyRef) { } registerOnChange(fn: any): void { @@ -88,7 +90,9 @@ export class DeviceDataComponent implements ControlValueAccessor, OnInit, Valida configuration: [null, Validators.required], transportConfiguration: [null, Validators.required] }); - this.deviceDataFormGroup.valueChanges.subscribe(() => { + this.deviceDataFormGroup.valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateModel(); }); } diff --git a/ui-ngx/src/app/modules/home/pages/device/data/device-transport-configuration.component.ts b/ui-ngx/src/app/modules/home/pages/device/data/device-transport-configuration.component.ts index ecc09c9e4a..df9a1b4845 100644 --- a/ui-ngx/src/app/modules/home/pages/device/data/device-transport-configuration.component.ts +++ b/ui-ngx/src/app/modules/home/pages/device/data/device-transport-configuration.component.ts @@ -14,7 +14,7 @@ /// limitations under the License. /// -import { Component, forwardRef, Input, OnInit } from '@angular/core'; +import { Component, DestroyRef, forwardRef, Input, OnInit } from '@angular/core'; import { ControlValueAccessor, NG_VALIDATORS, @@ -30,6 +30,7 @@ import { AppState } from '@app/core/core.state'; import { coerceBooleanProperty } from '@angular/cdk/coercion'; import { DeviceTransportConfiguration, DeviceTransportType } from '@shared/models/device.models'; import { deepClone } from '@core/utils'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; @Component({ selector: 'tb-device-transport-configuration', @@ -70,7 +71,8 @@ export class DeviceTransportConfigurationComponent implements ControlValueAccess private propagateChange = (v: any) => { }; constructor(private store: Store, - private fb: UntypedFormBuilder) { + private fb: UntypedFormBuilder, + private destroyRef: DestroyRef) { } registerOnChange(fn: any): void { @@ -84,7 +86,9 @@ export class DeviceTransportConfigurationComponent implements ControlValueAccess this.deviceTransportConfigurationFormGroup = this.fb.group({ configuration: [null, Validators.required] }); - this.deviceTransportConfigurationFormGroup.valueChanges.subscribe(() => { + this.deviceTransportConfigurationFormGroup.valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateModel(); }); } diff --git a/ui-ngx/src/app/modules/home/pages/device/data/mqtt-device-transport-configuration.component.ts b/ui-ngx/src/app/modules/home/pages/device/data/mqtt-device-transport-configuration.component.ts index 453f982d95..4d6e77fc75 100644 --- a/ui-ngx/src/app/modules/home/pages/device/data/mqtt-device-transport-configuration.component.ts +++ b/ui-ngx/src/app/modules/home/pages/device/data/mqtt-device-transport-configuration.component.ts @@ -14,7 +14,7 @@ /// limitations under the License. /// -import { Component, forwardRef, Input, OnInit } from '@angular/core'; +import { Component, DestroyRef, forwardRef, Input, OnInit } from '@angular/core'; import { ControlValueAccessor, UntypedFormBuilder, UntypedFormGroup, NG_VALUE_ACCESSOR, Validators } from '@angular/forms'; import { Store } from '@ngrx/store'; import { AppState } from '@app/core/core.state'; @@ -23,6 +23,7 @@ import { DeviceTransportConfiguration, DeviceTransportType, MqttDeviceTransportConfiguration } from '@shared/models/device.models'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; @Component({ selector: 'tb-mqtt-device-transport-configuration', @@ -53,7 +54,8 @@ export class MqttDeviceTransportConfigurationComponent implements ControlValueAc private propagateChange = (v: any) => { }; constructor(private store: Store, - private fb: UntypedFormBuilder) { + private fb: UntypedFormBuilder, + private destroyRef: DestroyRef) { } registerOnChange(fn: any): void { @@ -67,7 +69,9 @@ export class MqttDeviceTransportConfigurationComponent implements ControlValueAc this.mqttDeviceTransportConfigurationFormGroup = this.fb.group({ configuration: [null, Validators.required] }); - this.mqttDeviceTransportConfigurationFormGroup.valueChanges.subscribe(() => { + this.mqttDeviceTransportConfigurationFormGroup.valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateModel(); }); } diff --git a/ui-ngx/src/app/modules/home/pages/device/data/snmp-device-transport-configuration.component.ts b/ui-ngx/src/app/modules/home/pages/device/data/snmp-device-transport-configuration.component.ts index 06d8565e07..c7685f1c32 100644 --- a/ui-ngx/src/app/modules/home/pages/device/data/snmp-device-transport-configuration.component.ts +++ b/ui-ngx/src/app/modules/home/pages/device/data/snmp-device-transport-configuration.component.ts @@ -14,7 +14,7 @@ /// limitations under the License. /// -import { Component, forwardRef, Input, OnInit } from '@angular/core'; +import { Component, DestroyRef, forwardRef, Input, OnInit } from '@angular/core'; import { ControlValueAccessor, UntypedFormBuilder, @@ -39,6 +39,7 @@ import { SnmpPrivacyProtocolTranslationMap } from '@shared/models/device.models'; import { isDefinedAndNotNull } from '@core/utils'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; @Component({ selector: 'tb-snmp-device-transport-configuration', @@ -82,7 +83,8 @@ export class SnmpDeviceTransportConfigurationComponent implements ControlValueAc private propagateChange = (v: any) => { }; constructor(private store: Store, - private fb: UntypedFormBuilder) { + private fb: UntypedFormBuilder, + private destroyRef: DestroyRef) { } registerOnChange(fn: any): void { @@ -107,10 +109,14 @@ export class SnmpDeviceTransportConfigurationComponent implements ControlValueAc privacyPassphrase: ['', [Validators.required, Validators.pattern('(.|\\s)*\\S(.|\\s)*')]], engineId: [''] }); - this.snmpDeviceTransportConfigurationFormGroup.get('protocolVersion').valueChanges.subscribe((protocol: SnmpDeviceProtocolVersion) => { + this.snmpDeviceTransportConfigurationFormGroup.get('protocolVersion').valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe((protocol: SnmpDeviceProtocolVersion) => { this.updateDisabledFormValue(protocol); }); - this.snmpDeviceTransportConfigurationFormGroup.valueChanges.subscribe(() => { + this.snmpDeviceTransportConfigurationFormGroup.valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateModel(); }); } diff --git a/ui-ngx/src/app/modules/home/pages/device/device.component.ts b/ui-ngx/src/app/modules/home/pages/device/device.component.ts index 24e9973f53..bea985e153 100644 --- a/ui-ngx/src/app/modules/home/pages/device/device.component.ts +++ b/ui-ngx/src/app/modules/home/pages/device/device.component.ts @@ -14,7 +14,7 @@ /// limitations under the License. /// -import { ChangeDetectorRef, Component, Inject } from '@angular/core'; +import { ChangeDetectorRef, Component, DestroyRef, Inject } from '@angular/core'; import { Store } from '@ngrx/store'; import { AppState } from '@core/core.state'; import { EntityComponent } from '../../components/entity/entity.component'; @@ -36,7 +36,7 @@ import { EntityTableConfig } from '@home/models/entity/entities-table-config.mod import { Subject } from 'rxjs'; import { OtaUpdateType } from '@shared/models/ota-package.models'; import { distinctUntilChanged } from 'rxjs/operators'; -import { getEntityDetailsPageURL } from '@core/utils'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; @Component({ selector: 'tb-device', @@ -58,7 +58,8 @@ export class DeviceComponent extends EntityComponent { @Inject('entity') protected entityValue: DeviceInfo, @Inject('entitiesTableConfig') protected entitiesTableConfigValue: EntityTableConfig, public fb: UntypedFormBuilder, - protected cd: ChangeDetectorRef) { + protected cd: ChangeDetectorRef, + private destroyRef: DestroyRef) { super(store, fb, entityValue, entitiesTableConfigValue, cd); } @@ -99,7 +100,8 @@ export class DeviceComponent extends EntityComponent { } ); form.get('deviceProfileId').valueChanges.pipe( - distinctUntilChanged((prev, curr) => prev?.id === curr?.id) + distinctUntilChanged((prev, curr) => prev?.id === curr?.id), + takeUntilDestroyed(this.destroyRef) ).subscribe(profileId => { if (profileId && this.isEdit) { this.entityForm.patchValue({ diff --git a/ui-ngx/src/app/modules/home/pages/mobile/applications/mobile-app-table-config.resolver.ts b/ui-ngx/src/app/modules/home/pages/mobile/applications/mobile-app-table-config.resolver.ts index 20ac575b2c..4de8628ec2 100644 --- a/ui-ngx/src/app/modules/home/pages/mobile/applications/mobile-app-table-config.resolver.ts +++ b/ui-ngx/src/app/modules/home/pages/mobile/applications/mobile-app-table-config.resolver.ts @@ -70,7 +70,7 @@ export class MobileAppTableConfigResolver { this.config.columns.push( new DateEntityTableColumn('createdTime', 'common.created-time', this.datePipe, '170px'), new EntityTableColumn('pkgName', 'mobile.application-package', '20%', (entity) => entity.pkgName ?? '', () => ({}), - false, () => ({}), () => undefined, false, + true, () => ({}), () => undefined, false, { name: this.translate.instant('mobile.copy-application-package'), icon: 'content_copy', @@ -85,7 +85,7 @@ export class MobileAppTableConfigResolver { }), new EntityTableColumn('appSecret', 'mobile.application-secret', '15%', (entity) => this.truncatePipe.transform(entity.appSecret, true, 10, '…'), () => ({}), - false, () => ({}), () => undefined, false, + true, () => ({}), () => undefined, false, { name: this.translate.instant('mobile.copy-application-secret'), icon: 'content_copy', diff --git a/ui-ngx/src/app/modules/home/pages/rulechain/rule-node-link.component.ts b/ui-ngx/src/app/modules/home/pages/rulechain/rule-node-link.component.ts index e397eb80d5..5d517ad2e8 100644 --- a/ui-ngx/src/app/modules/home/pages/rulechain/rule-node-link.component.ts +++ b/ui-ngx/src/app/modules/home/pages/rulechain/rule-node-link.component.ts @@ -20,6 +20,7 @@ import { FcRuleEdge, LinkLabel } from '@shared/models/rule-node.models'; import { coerceBooleanProperty } from '@angular/cdk/coercion'; import { TruncatePipe } from '@shared/pipe/truncate.pipe'; import { TranslateService } from '@ngx-translate/core'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; @Component({ selector: 'tb-rule-node-link', @@ -72,7 +73,9 @@ export class RuleNodeLinkComponent implements ControlValueAccessor, OnInit { this.ruleNodeLinkFormGroup = this.fb.group({ labels: [[], Validators.required] }); - this.ruleNodeLinkFormGroup.get('labels').valueChanges.subscribe( + this.ruleNodeLinkFormGroup.get('labels').valueChanges.pipe( + takeUntilDestroyed() + ).subscribe( (labels: string[]) => this.updateModel(labels) ); } diff --git a/ui-ngx/src/app/modules/home/pages/scada-symbol/metadata-components/scada-symbol-behavior-panel.component.ts b/ui-ngx/src/app/modules/home/pages/scada-symbol/metadata-components/scada-symbol-behavior-panel.component.ts index f7ce9c7a0e..2c2441d662 100644 --- a/ui-ngx/src/app/modules/home/pages/scada-symbol/metadata-components/scada-symbol-behavior-panel.component.ts +++ b/ui-ngx/src/app/modules/home/pages/scada-symbol/metadata-components/scada-symbol-behavior-panel.component.ts @@ -14,7 +14,7 @@ /// limitations under the License. /// -import { Component, EventEmitter, Input, OnInit, Output, ViewEncapsulation } from '@angular/core'; +import { Component, DestroyRef, EventEmitter, Input, OnInit, Output, ViewEncapsulation } from '@angular/core'; import { TbPopoverComponent } from '@shared/components/popover.component'; import { UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms'; import { merge } from 'rxjs'; @@ -32,6 +32,7 @@ import { mergeDeep } from '@core/utils'; import { WidgetAction, widgetType } from '@shared/models/widget.models'; import { IAliasController } from '@core/api/widget-api.models'; import { WidgetActionCallbacks } from '@home/components/widget/action/manage-widget-actions.component.models'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; @Component({ selector: 'tb-scada-symbol-behavior-panel', @@ -84,7 +85,8 @@ export class ScadaSymbolBehaviorPanelComponent implements OnInit { behaviorFormGroup: UntypedFormGroup; constructor(private fb: UntypedFormBuilder, - private widgetService: WidgetService) { + private widgetService: WidgetService, + private destroyRef: DestroyRef) { } ngOnInit(): void { @@ -109,7 +111,10 @@ export class ScadaSymbolBehaviorPanelComponent implements OnInit { this.behaviorFormGroup.disable({emitEvent: false}); } else { merge(this.behaviorFormGroup.get('type').valueChanges, - this.behaviorFormGroup.get('valueType').valueChanges).subscribe(() => { + this.behaviorFormGroup.get('valueType').valueChanges + ).pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateValidators(); }); this.updateValidators(); diff --git a/ui-ngx/src/app/modules/home/pages/scada-symbol/metadata-components/scada-symbol-behavior-row.component.ts b/ui-ngx/src/app/modules/home/pages/scada-symbol/metadata-components/scada-symbol-behavior-row.component.ts index ac73b10550..e172197d81 100644 --- a/ui-ngx/src/app/modules/home/pages/scada-symbol/metadata-components/scada-symbol-behavior-row.component.ts +++ b/ui-ngx/src/app/modules/home/pages/scada-symbol/metadata-components/scada-symbol-behavior-row.component.ts @@ -17,6 +17,7 @@ import { ChangeDetectorRef, Component, + DestroyRef, ElementRef, EventEmitter, forwardRef, @@ -58,6 +59,7 @@ import { import { IAliasController } from '@core/api/widget-api.models'; import { WidgetActionCallbacks } from '@home/components/widget/action/manage-widget-actions.component.models'; import { isNotEmptyTbFunction } from '@shared/models/js-function.models'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; export const behaviorValid = (behavior: ScadaSymbolBehavior): boolean => { if (!behavior.id || !behavior.name || !behavior.type) { @@ -143,7 +145,8 @@ export class ScadaSymbolBehaviorRowComponent implements ControlValueAccessor, On private popoverService: TbPopoverService, private renderer: Renderer2, private viewContainerRef: ViewContainerRef, - private behaviorsComponent: ScadaSymbolBehaviorsComponent) { + private behaviorsComponent: ScadaSymbolBehaviorsComponent, + private destroyRef: DestroyRef) { } ngOnInit() { @@ -152,10 +155,14 @@ export class ScadaSymbolBehaviorRowComponent implements ControlValueAccessor, On name: [null, [Validators.required]], type: [null, [Validators.required]] }); - this.behaviorRowFormGroup.valueChanges.subscribe( + this.behaviorRowFormGroup.valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe( () => this.updateModel() ); - this.behaviorRowFormGroup.get('type').valueChanges.subscribe((newType: ScadaSymbolBehaviorType) => { + this.behaviorRowFormGroup.get('type').valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe((newType: ScadaSymbolBehaviorType) => { this.onTypeChanged(newType); }); } diff --git a/ui-ngx/src/app/modules/home/pages/scada-symbol/metadata-components/scada-symbol-behaviors.component.ts b/ui-ngx/src/app/modules/home/pages/scada-symbol/metadata-components/scada-symbol-behaviors.component.ts index 0ad1e59e05..b2ca82b7ae 100644 --- a/ui-ngx/src/app/modules/home/pages/scada-symbol/metadata-components/scada-symbol-behaviors.component.ts +++ b/ui-ngx/src/app/modules/home/pages/scada-symbol/metadata-components/scada-symbol-behaviors.component.ts @@ -16,6 +16,7 @@ import { Component, + DestroyRef, forwardRef, HostBinding, Input, @@ -51,6 +52,7 @@ import { TranslateService } from '@ngx-translate/core'; import { mergeDeep } from '@core/utils'; import { IAliasController } from '@core/api/widget-api.models'; import { WidgetActionCallbacks } from '@home/components/widget/action/manage-widget-actions.component.models'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; @Component({ selector: 'tb-scada-symbol-metadata-behaviors', @@ -98,14 +100,17 @@ export class ScadaSymbolBehaviorsComponent implements ControlValueAccessor, OnIn private propagateChange = (_val: any) => {}; constructor(private fb: UntypedFormBuilder, - private translate: TranslateService) { + private translate: TranslateService, + private destroyRef: DestroyRef) { } ngOnInit() { this.behaviorsFormGroup = this.fb.group({ behaviors: this.fb.array([]) }); - this.behaviorsFormGroup.valueChanges.subscribe( + this.behaviorsFormGroup.valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe( () => { let behaviors: ScadaSymbolBehavior[] = this.behaviorsFormGroup.get('behaviors').value; if (behaviors) { diff --git a/ui-ngx/src/app/modules/home/pages/scada-symbol/metadata-components/scada-symbol-metadata-tags.component.ts b/ui-ngx/src/app/modules/home/pages/scada-symbol/metadata-components/scada-symbol-metadata-tags.component.ts index 42dfe8b7e2..99dc24b692 100644 --- a/ui-ngx/src/app/modules/home/pages/scada-symbol/metadata-components/scada-symbol-metadata-tags.component.ts +++ b/ui-ngx/src/app/modules/home/pages/scada-symbol/metadata-components/scada-symbol-metadata-tags.component.ts @@ -16,6 +16,7 @@ import { Component, + DestroyRef, forwardRef, HostBinding, Input, @@ -42,6 +43,7 @@ import { ScadaSymbolMetadataTagComponent } from '@home/pages/scada-symbol/metadata-components/scada-symbol-metadata-tag.component'; import { TbEditorCompleter } from '@shared/models/ace/completion.models'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; const tagIsEmpty = (tag: ScadaSymbolTag): boolean => !tag.stateRenderFunction && !tag.actions?.click?.actionFunction; @@ -90,7 +92,8 @@ export class ScadaSymbolMetadataTagsComponent implements ControlValueAccessor, O private propagateChange = (_val: any) => {}; - constructor(private fb: UntypedFormBuilder) { + constructor(private fb: UntypedFormBuilder, + private destroyRef: DestroyRef) { } ngOnInit() { @@ -100,7 +103,9 @@ export class ScadaSymbolMetadataTagsComponent implements ControlValueAccessor, O const tagsResult = this.setupTags(); this.tagsFormGroup.setControl('tags', this.prepareTagsFormArray(tagsResult.tags), {emitEvent: false}); - this.tagsFormGroup.valueChanges.subscribe( + this.tagsFormGroup.valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe( () => { let value: ScadaSymbolTag[] = this.tagsFormGroup.get('tags').value; if (value) { diff --git a/ui-ngx/src/app/modules/home/pages/scada-symbol/metadata-components/scada-symbol-metadata.component.ts b/ui-ngx/src/app/modules/home/pages/scada-symbol/metadata-components/scada-symbol-metadata.component.ts index a5d38991b9..29b61b4523 100644 --- a/ui-ngx/src/app/modules/home/pages/scada-symbol/metadata-components/scada-symbol-metadata.component.ts +++ b/ui-ngx/src/app/modules/home/pages/scada-symbol/metadata-components/scada-symbol-metadata.component.ts @@ -16,6 +16,7 @@ import { Component, + DestroyRef, forwardRef, Input, OnChanges, @@ -54,6 +55,7 @@ import { import { CustomTranslatePipe } from '@shared/pipe/custom-translate.pipe'; import { IAliasController } from '@core/api/widget-api.models'; import { WidgetActionCallbacks } from '@home/components/widget/action/manage-widget-actions.component.models'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; @Component({ selector: 'tb-scada-symbol-metadata', @@ -126,7 +128,8 @@ export class ScadaSymbolMetadataComponent extends PageComponent implements OnIni constructor(protected store: Store, private fb: UntypedFormBuilder, private translate: TranslateService, - private customTranslate: CustomTranslatePipe) { + private customTranslate: CustomTranslatePipe, + private destroyRef: DestroyRef) { super(store); } @@ -144,7 +147,9 @@ export class ScadaSymbolMetadataComponent extends PageComponent implements OnIni }); this.updateFunctionCompleters(emptyMetadata()); - this.metadataFormGroup.valueChanges.subscribe(() => { + this.metadataFormGroup.valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateModel(); }); } diff --git a/ui-ngx/src/app/modules/home/pages/scada-symbol/metadata-components/scada-symbol-properties.component.ts b/ui-ngx/src/app/modules/home/pages/scada-symbol/metadata-components/scada-symbol-properties.component.ts index 840302161b..5bcdc74a8a 100644 --- a/ui-ngx/src/app/modules/home/pages/scada-symbol/metadata-components/scada-symbol-properties.component.ts +++ b/ui-ngx/src/app/modules/home/pages/scada-symbol/metadata-components/scada-symbol-properties.component.ts @@ -16,6 +16,7 @@ import { Component, + DestroyRef, forwardRef, HostBinding, Input, @@ -42,6 +43,7 @@ import { ScadaSymbolPropertyRowComponent } from '@home/pages/scada-symbol/metadata-components/scada-symbol-property-row.component'; import { TranslateService } from '@ngx-translate/core'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; @Component({ selector: 'tb-scada-symbol-metadata-properties', @@ -85,14 +87,17 @@ export class ScadaSymbolPropertiesComponent implements ControlValueAccessor, OnI private propagateChange = (_val: any) => {}; constructor(private fb: UntypedFormBuilder, - private translate: TranslateService) { + private translate: TranslateService, + private destroyRef: DestroyRef) { } ngOnInit() { this.propertiesFormGroup = this.fb.group({ properties: this.fb.array([]) }); - this.propertiesFormGroup.valueChanges.subscribe( + this.propertiesFormGroup.valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe( () => { let properties: ScadaSymbolProperty[] = this.propertiesFormGroup.get('properties').value; if (properties) { diff --git a/ui-ngx/src/app/modules/home/pages/scada-symbol/metadata-components/scada-symbol-property-panel.component.ts b/ui-ngx/src/app/modules/home/pages/scada-symbol/metadata-components/scada-symbol-property-panel.component.ts index 4c59787c0f..045694ed46 100644 --- a/ui-ngx/src/app/modules/home/pages/scada-symbol/metadata-components/scada-symbol-property-panel.component.ts +++ b/ui-ngx/src/app/modules/home/pages/scada-symbol/metadata-components/scada-symbol-property-panel.component.ts @@ -14,7 +14,7 @@ /// limitations under the License. /// -import { Component, EventEmitter, Input, OnInit, Output, ViewEncapsulation } from '@angular/core'; +import { Component, DestroyRef, EventEmitter, Input, OnInit, Output, ViewEncapsulation } from '@angular/core'; import { TbPopoverComponent } from '@shared/components/popover.component'; import { UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms'; import { @@ -27,6 +27,7 @@ import { } from '@home/components/widget/lib/scada/scada-symbol.models'; import { defaultPropertyValue } from '@home/pages/scada-symbol/metadata-components/scada-symbol-property-row.component'; import { ValueType } from '@shared/models/constants'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; @Component({ selector: 'tb-scada-symbol-property-panel', @@ -71,7 +72,8 @@ export class ScadaSymbolPropertyPanelComponent implements OnInit { private propertyType: ScadaSymbolPropertyType; - constructor(private fb: UntypedFormBuilder) { + constructor(private fb: UntypedFormBuilder, + private destroyRef: DestroyRef) { } ngOnInit(): void { @@ -98,7 +100,9 @@ export class ScadaSymbolPropertyPanelComponent implements OnInit { if (this.disabled) { this.propertyFormGroup.disable({emitEvent: false}); } else { - this.propertyFormGroup.get('type').valueChanges.subscribe(() => { + this.propertyFormGroup.get('type').valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe(() => { this.updateValidators(); }); this.updateValidators(); diff --git a/ui-ngx/src/app/modules/home/pages/scada-symbol/metadata-components/scada-symbol-property-row.component.ts b/ui-ngx/src/app/modules/home/pages/scada-symbol/metadata-components/scada-symbol-property-row.component.ts index 3da851063f..60a544dc1e 100644 --- a/ui-ngx/src/app/modules/home/pages/scada-symbol/metadata-components/scada-symbol-property-row.component.ts +++ b/ui-ngx/src/app/modules/home/pages/scada-symbol/metadata-components/scada-symbol-property-row.component.ts @@ -17,6 +17,7 @@ import { ChangeDetectorRef, Component, + DestroyRef, ElementRef, EventEmitter, forwardRef, @@ -55,6 +56,7 @@ import { import { ScadaSymbolPropertiesComponent } from '@home/pages/scada-symbol/metadata-components/scada-symbol-properties.component'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; export const propertyValid = (property: ScadaSymbolProperty): boolean => !(!property.id || !property.name || !property.type); @@ -138,7 +140,8 @@ export class ScadaSymbolPropertyRowComponent implements ControlValueAccessor, On private popoverService: TbPopoverService, private renderer: Renderer2, private viewContainerRef: ViewContainerRef, - private propertiesComponent: ScadaSymbolPropertiesComponent) { + private propertiesComponent: ScadaSymbolPropertiesComponent, + private destroyRef: DestroyRef) { } ngOnInit() { @@ -147,10 +150,14 @@ export class ScadaSymbolPropertyRowComponent implements ControlValueAccessor, On name: [null, [Validators.required]], type: [null, [Validators.required]] }); - this.propertyRowFormGroup.valueChanges.subscribe( + this.propertyRowFormGroup.valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe( () => this.updateModel() ); - this.propertyRowFormGroup.get('type').valueChanges.subscribe((newType: ScadaSymbolPropertyType) => { + this.propertyRowFormGroup.get('type').valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe((newType: ScadaSymbolPropertyType) => { this.onTypeChanged(newType); }); } diff --git a/ui-ngx/src/app/modules/home/pages/scada-symbol/scada-symbol-editor.component.ts b/ui-ngx/src/app/modules/home/pages/scada-symbol/scada-symbol-editor.component.ts index e13cc953df..a87be5ee43 100644 --- a/ui-ngx/src/app/modules/home/pages/scada-symbol/scada-symbol-editor.component.ts +++ b/ui-ngx/src/app/modules/home/pages/scada-symbol/scada-symbol-editor.component.ts @@ -18,9 +18,11 @@ import { AfterViewInit, ChangeDetectorRef, Component, + DestroyRef, ElementRef, EventEmitter, - Input, NgZone, + Input, + NgZone, OnChanges, OnDestroy, OnInit, @@ -39,6 +41,7 @@ import { parseScadaSymbolsTagsFromContent, removeScadaSymbolMetadata } from '@home/components/widget/lib/scada/scada-symbol.models'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; export interface ScadaSymbolEditorData { scadaSymbolContent: string; @@ -106,7 +109,8 @@ export class ScadaSymbolEditorComponent implements OnInit, OnDestroy, AfterViewI } constructor(private cd: ChangeDetectorRef, - private zone: NgZone) { + private zone: NgZone, + private destroyRef: DestroyRef) { } ngOnInit(): void { @@ -115,7 +119,9 @@ export class ScadaSymbolEditorComponent implements OnInit, OnDestroy, AfterViewI } else { this.svgContentFormControl.enable({emitEvent: false}); } - this.svgContentFormControl.valueChanges.subscribe((svgContent) => { + this.svgContentFormControl.valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) + ).subscribe((svgContent) => { if (this.svgContent !== svgContent) { this.svgContent = svgContent; this.editObjectCallbacks.onSymbolEditObjectDirty(true); diff --git a/ui-ngx/src/app/modules/home/pages/user/user.component.html b/ui-ngx/src/app/modules/home/pages/user/user.component.html index 933e244290..3c52d89fc6 100644 --- a/ui-ngx/src/app/modules/home/pages/user/user.component.html +++ b/ui-ngx/src/app/modules/home/pages/user/user.component.html @@ -25,25 +25,25 @@