Merge branch 'master' into fix/3969-LwM2M-resource-title-read-only
This commit is contained in:
commit
b1cc582691
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -18,7 +18,6 @@ package org.thingsboard.server.edge;
|
|||||||
import com.google.protobuf.AbstractMessage;
|
import com.google.protobuf.AbstractMessage;
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.springframework.test.context.TestPropertySource;
|
|
||||||
import org.thingsboard.common.util.JacksonUtil;
|
import org.thingsboard.common.util.JacksonUtil;
|
||||||
import org.thingsboard.server.common.data.StringUtils;
|
import org.thingsboard.server.common.data.StringUtils;
|
||||||
import org.thingsboard.server.common.data.notification.NotificationDeliveryMethod;
|
import org.thingsboard.server.common.data.notification.NotificationDeliveryMethod;
|
||||||
|
|||||||
@ -59,12 +59,7 @@ public class OAuth2EdgeTest extends AbstractEdgeTest {
|
|||||||
oAuth2Info.setEnabled(false);
|
oAuth2Info.setEnabled(false);
|
||||||
oAuth2Info.setEdgeEnabled(false);
|
oAuth2Info.setEdgeEnabled(false);
|
||||||
doPost("/api/oauth2/config", oAuth2Info, OAuth2Info.class);
|
doPost("/api/oauth2/config", oAuth2Info, OAuth2Info.class);
|
||||||
Assert.assertTrue(edgeImitator.waitForMessages());
|
Assert.assertFalse(edgeImitator.waitForMessages(5));
|
||||||
latestMessage = edgeImitator.getLatestMessage();
|
|
||||||
Assert.assertTrue(latestMessage instanceof OAuth2UpdateMsg);
|
|
||||||
oAuth2UpdateMsg = (OAuth2UpdateMsg) latestMessage;
|
|
||||||
result = JacksonUtil.fromString(oAuth2UpdateMsg.getEntity(), OAuth2Info.class, true);
|
|
||||||
Assert.assertEquals(oAuth2Info, result);
|
|
||||||
|
|
||||||
edgeImitator.ignoreType(OAuth2UpdateMsg.class);
|
edgeImitator.ignoreType(OAuth2UpdateMsg.class);
|
||||||
loginTenantAdmin();
|
loginTenantAdmin();
|
||||||
|
|||||||
@ -15,6 +15,7 @@
|
|||||||
*/
|
*/
|
||||||
package org.thingsboard.server.cache;
|
package org.thingsboard.server.cache;
|
||||||
|
|
||||||
|
import jakarta.annotation.PostConstruct;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
@ -22,7 +23,6 @@ import org.springframework.boot.context.properties.ConfigurationProperties;
|
|||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.thingsboard.server.common.data.CacheConstants;
|
import org.thingsboard.server.common.data.CacheConstants;
|
||||||
|
|
||||||
import jakarta.annotation.PostConstruct;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
|
|||||||
@ -29,7 +29,6 @@ import org.springframework.data.redis.core.types.Expiration;
|
|||||||
import org.springframework.data.redis.serializer.RedisSerializer;
|
import org.springframework.data.redis.serializer.RedisSerializer;
|
||||||
import org.springframework.data.redis.serializer.StringRedisSerializer;
|
import org.springframework.data.redis.serializer.StringRedisSerializer;
|
||||||
import org.thingsboard.server.common.data.FstStatsService;
|
import org.thingsboard.server.common.data.FstStatsService;
|
||||||
import redis.clients.jedis.Connection;
|
|
||||||
import redis.clients.jedis.Jedis;
|
import redis.clients.jedis.Jedis;
|
||||||
import redis.clients.jedis.JedisPool;
|
import redis.clients.jedis.JedisPool;
|
||||||
import redis.clients.jedis.util.JedisClusterCRC16;
|
import redis.clients.jedis.util.JedisClusterCRC16;
|
||||||
@ -40,6 +39,8 @@ import java.util.Collection;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.function.Function;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public abstract class RedisTbTransactionalCache<K extends Serializable, V extends Serializable> implements TbTransactionalCache<K, V> {
|
public abstract class RedisTbTransactionalCache<K extends Serializable, V extends Serializable> implements TbTransactionalCache<K, V> {
|
||||||
@ -57,6 +58,7 @@ public abstract class RedisTbTransactionalCache<K extends Serializable, V extend
|
|||||||
private final TbRedisSerializer<K, V> valueSerializer;
|
private final TbRedisSerializer<K, V> valueSerializer;
|
||||||
private final Expiration evictExpiration;
|
private final Expiration evictExpiration;
|
||||||
private final Expiration cacheTtl;
|
private final Expiration cacheTtl;
|
||||||
|
private final boolean cacheEnabled;
|
||||||
|
|
||||||
public RedisTbTransactionalCache(String cacheName,
|
public RedisTbTransactionalCache(String cacheName,
|
||||||
CacheSpecsMap cacheSpecsMap,
|
CacheSpecsMap cacheSpecsMap,
|
||||||
@ -73,10 +75,19 @@ public abstract class RedisTbTransactionalCache<K extends Serializable, V extend
|
|||||||
.map(CacheSpecs::getTimeToLiveInMinutes)
|
.map(CacheSpecs::getTimeToLiveInMinutes)
|
||||||
.map(t -> Expiration.from(t, TimeUnit.MINUTES))
|
.map(t -> Expiration.from(t, TimeUnit.MINUTES))
|
||||||
.orElseGet(Expiration::persistent);
|
.orElseGet(Expiration::persistent);
|
||||||
|
this.cacheEnabled = Optional.ofNullable(cacheSpecsMap)
|
||||||
|
.map(CacheSpecsMap::getSpecs)
|
||||||
|
.map(x -> x.get(cacheName))
|
||||||
|
.map(CacheSpecs::getMaxSize)
|
||||||
|
.map(size -> size > 0)
|
||||||
|
.orElse(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public TbCacheValueWrapper<V> get(K key) {
|
public TbCacheValueWrapper<V> get(K key) {
|
||||||
|
if (!cacheEnabled) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
try (var connection = connectionFactory.getConnection()) {
|
try (var connection = connectionFactory.getConnection()) {
|
||||||
byte[] rawKey = getRawKey(key);
|
byte[] rawKey = getRawKey(key);
|
||||||
byte[] rawValue = connection.get(rawKey);
|
byte[] rawValue = connection.get(rawKey);
|
||||||
@ -98,6 +109,9 @@ public abstract class RedisTbTransactionalCache<K extends Serializable, V extend
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void put(K key, V value) {
|
public void put(K key, V value) {
|
||||||
|
if (!cacheEnabled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
try (var connection = connectionFactory.getConnection()) {
|
try (var connection = connectionFactory.getConnection()) {
|
||||||
put(connection, key, value, RedisStringCommands.SetOption.UPSERT);
|
put(connection, key, value, RedisStringCommands.SetOption.UPSERT);
|
||||||
}
|
}
|
||||||
@ -105,6 +119,9 @@ public abstract class RedisTbTransactionalCache<K extends Serializable, V extend
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void putIfAbsent(K key, V value) {
|
public void putIfAbsent(K key, V value) {
|
||||||
|
if (!cacheEnabled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
try (var connection = connectionFactory.getConnection()) {
|
try (var connection = connectionFactory.getConnection()) {
|
||||||
put(connection, key, value, RedisStringCommands.SetOption.SET_IF_ABSENT);
|
put(connection, key, value, RedisStringCommands.SetOption.SET_IF_ABSENT);
|
||||||
}
|
}
|
||||||
@ -112,6 +129,9 @@ public abstract class RedisTbTransactionalCache<K extends Serializable, V extend
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void evict(K key) {
|
public void evict(K key) {
|
||||||
|
if (!cacheEnabled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
try (var connection = connectionFactory.getConnection()) {
|
try (var connection = connectionFactory.getConnection()) {
|
||||||
connection.del(getRawKey(key));
|
connection.del(getRawKey(key));
|
||||||
}
|
}
|
||||||
@ -119,6 +139,9 @@ public abstract class RedisTbTransactionalCache<K extends Serializable, V extend
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void evict(Collection<K> keys) {
|
public void evict(Collection<K> keys) {
|
||||||
|
if (!cacheEnabled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
//Redis expects at least 1 key to delete. Otherwise - ERR wrong number of arguments for 'del' command
|
//Redis expects at least 1 key to delete. Otherwise - ERR wrong number of arguments for 'del' command
|
||||||
if (keys.isEmpty()) {
|
if (keys.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
@ -130,6 +153,9 @@ public abstract class RedisTbTransactionalCache<K extends Serializable, V extend
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void evictOrPut(K key, V value) {
|
public void evictOrPut(K key, V value) {
|
||||||
|
if (!cacheEnabled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
try (var connection = connectionFactory.getConnection()) {
|
try (var connection = connectionFactory.getConnection()) {
|
||||||
var rawKey = getRawKey(key);
|
var rawKey = getRawKey(key);
|
||||||
var records = connection.del(rawKey);
|
var records = connection.del(rawKey);
|
||||||
@ -153,6 +179,14 @@ public abstract class RedisTbTransactionalCache<K extends Serializable, V extend
|
|||||||
return new RedisTbCacheTransaction<>(this, connection);
|
return new RedisTbCacheTransaction<>(this, connection);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <R> R getAndPutInTransaction(K key, Supplier<R> dbCall, Function<V, R> cacheValueToResult, Function<R, V> dbValueToCacheValue, boolean cacheNullValue) {
|
||||||
|
if (!cacheEnabled) {
|
||||||
|
return dbCall.get();
|
||||||
|
}
|
||||||
|
return TbTransactionalCache.super.getAndPutInTransaction(key, dbCall, cacheValueToResult, dbValueToCacheValue, cacheNullValue);
|
||||||
|
}
|
||||||
|
|
||||||
private RedisConnection getConnection(byte[] rawKey) {
|
private RedisConnection getConnection(byte[] rawKey) {
|
||||||
if (!connectionFactory.isRedisClusterAware()) {
|
if (!connectionFactory.isRedisClusterAware()) {
|
||||||
return connectionFactory.getConnection();
|
return connectionFactory.getConnection();
|
||||||
@ -214,6 +248,9 @@ public abstract class RedisTbTransactionalCache<K extends Serializable, V extend
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void put(RedisConnection connection, K key, V value, RedisStringCommands.SetOption setOption) {
|
public void put(RedisConnection connection, K key, V value, RedisStringCommands.SetOption setOption) {
|
||||||
|
if (!cacheEnabled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
byte[] rawKey = getRawKey(key);
|
byte[] rawKey = getRawKey(key);
|
||||||
byte[] rawValue = getRawValue(value);
|
byte[] rawValue = getRawValue(value);
|
||||||
connection.set(rawKey, rawValue, cacheTtl, setOption);
|
connection.set(rawKey, rawValue, cacheTtl, setOption);
|
||||||
|
|||||||
@ -60,15 +60,20 @@ public interface TbTransactionalCache<K extends Serializable, V extends Serializ
|
|||||||
}
|
}
|
||||||
|
|
||||||
default V getAndPutInTransaction(K key, Supplier<V> dbCall, boolean cacheNullValue) {
|
default V getAndPutInTransaction(K key, Supplier<V> dbCall, boolean cacheNullValue) {
|
||||||
|
return getAndPutInTransaction(key, dbCall, Function.identity(), Function.identity(), cacheNullValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
default <R> R getAndPutInTransaction(K key, Supplier<R> dbCall, Function<V, R> cacheValueToResult, Function<R, V> dbValueToCacheValue, boolean cacheNullValue) {
|
||||||
TbCacheValueWrapper<V> cacheValueWrapper = get(key);
|
TbCacheValueWrapper<V> cacheValueWrapper = get(key);
|
||||||
if (cacheValueWrapper != null) {
|
if (cacheValueWrapper != null) {
|
||||||
return cacheValueWrapper.get();
|
V cacheValue = cacheValueWrapper.get();
|
||||||
|
return cacheValue != null ? cacheValueToResult.apply(cacheValue) : null;
|
||||||
}
|
}
|
||||||
var cacheTransaction = newTransactionForKey(key);
|
var cacheTransaction = newTransactionForKey(key);
|
||||||
try {
|
try {
|
||||||
V dbValue = dbCall.get();
|
R dbValue = dbCall.get();
|
||||||
if (dbValue != null || cacheNullValue) {
|
if (dbValue != null || cacheNullValue) {
|
||||||
cacheTransaction.putIfAbsent(key, dbValue);
|
cacheTransaction.putIfAbsent(key, dbValueToCacheValue.apply(dbValue));
|
||||||
cacheTransaction.commit();
|
cacheTransaction.commit();
|
||||||
return dbValue;
|
return dbValue;
|
||||||
} else {
|
} else {
|
||||||
@ -94,27 +99,4 @@ public interface TbTransactionalCache<K extends Serializable, V extends Serializ
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
default <R> R getAndPutInTransaction(K key, Supplier<R> dbCall, Function<V, R> cacheValueToResult, Function<R, V> dbValueToCacheValue, boolean cacheNullValue) {
|
|
||||||
TbCacheValueWrapper<V> cacheValueWrapper = get(key);
|
|
||||||
if (cacheValueWrapper != null) {
|
|
||||||
var cacheValue = cacheValueWrapper.get();
|
|
||||||
return cacheValue == null ? null : cacheValueToResult.apply(cacheValue);
|
|
||||||
}
|
|
||||||
var cacheTransaction = newTransactionForKey(key);
|
|
||||||
try {
|
|
||||||
R dbValue = dbCall.get();
|
|
||||||
if (dbValue != null || cacheNullValue) {
|
|
||||||
cacheTransaction.putIfAbsent(key, dbValueToCacheValue.apply(dbValue));
|
|
||||||
cacheTransaction.commit();
|
|
||||||
return dbValue;
|
|
||||||
} else {
|
|
||||||
cacheTransaction.rollback();
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
} catch (Throwable e) {
|
|
||||||
cacheTransaction.rollback();
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -62,4 +62,5 @@ public class CacheSpecsMapTest {
|
|||||||
public void givenCacheConfig_whenCacheManagerReady_thenVerifyNonExistedCaches() {
|
public void givenCacheConfig_whenCacheManagerReady_thenVerifyNonExistedCaches() {
|
||||||
assertThat(cacheManager.getCache("rainbows_and_unicorns")).isNull();
|
assertThat(cacheManager.getCache("rainbows_and_unicorns")).isNull();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
}
|
||||||
|
|||||||
@ -19,6 +19,7 @@ import com.fasterxml.jackson.databind.JsonNode;
|
|||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
import lombok.Builder;
|
import lombok.Builder;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
import lombok.ToString;
|
||||||
import org.thingsboard.server.common.data.id.AlarmId;
|
import org.thingsboard.server.common.data.id.AlarmId;
|
||||||
import org.thingsboard.server.common.data.id.CustomerId;
|
import org.thingsboard.server.common.data.id.CustomerId;
|
||||||
import org.thingsboard.server.common.data.id.EntityId;
|
import org.thingsboard.server.common.data.id.EntityId;
|
||||||
@ -53,9 +54,12 @@ public class AlarmCreateOrUpdateActiveRequest implements AlarmModificationReques
|
|||||||
private long startTs;
|
private long startTs;
|
||||||
@Schema(description = "Timestamp of the alarm end time(last time update), in milliseconds", example = "1634111163522")
|
@Schema(description = "Timestamp of the alarm end time(last time update), in milliseconds", example = "1634111163522")
|
||||||
private long endTs;
|
private long endTs;
|
||||||
|
|
||||||
|
@ToString.Exclude
|
||||||
@NoXss
|
@NoXss
|
||||||
@Schema(description = "JSON object with alarm details")
|
@Schema(description = "JSON object with alarm details")
|
||||||
private JsonNode details;
|
private JsonNode details;
|
||||||
|
|
||||||
@Valid
|
@Valid
|
||||||
@Schema(description = "JSON object with propagation details")
|
@Schema(description = "JSON object with propagation details")
|
||||||
private AlarmPropagationInfo propagation;
|
private AlarmPropagationInfo propagation;
|
||||||
|
|||||||
@ -19,6 +19,7 @@ import com.fasterxml.jackson.databind.JsonNode;
|
|||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
import lombok.Builder;
|
import lombok.Builder;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
import lombok.ToString;
|
||||||
import org.thingsboard.server.common.data.id.AlarmId;
|
import org.thingsboard.server.common.data.id.AlarmId;
|
||||||
import org.thingsboard.server.common.data.id.TenantId;
|
import org.thingsboard.server.common.data.id.TenantId;
|
||||||
import org.thingsboard.server.common.data.id.UserId;
|
import org.thingsboard.server.common.data.id.UserId;
|
||||||
@ -47,9 +48,12 @@ public class AlarmUpdateRequest implements AlarmModificationRequest {
|
|||||||
private long startTs;
|
private long startTs;
|
||||||
@Schema(description = "Timestamp of the alarm end time(last time update), in milliseconds", example = "1634111163522")
|
@Schema(description = "Timestamp of the alarm end time(last time update), in milliseconds", example = "1634111163522")
|
||||||
private long endTs;
|
private long endTs;
|
||||||
|
|
||||||
|
@ToString.Exclude
|
||||||
@NoXss
|
@NoXss
|
||||||
@Schema(description = "JSON object with alarm details")
|
@Schema(description = "JSON object with alarm details")
|
||||||
private JsonNode details;
|
private JsonNode details;
|
||||||
|
|
||||||
@Valid
|
@Valid
|
||||||
@Schema(description = "JSON object with propagation details")
|
@Schema(description = "JSON object with propagation details")
|
||||||
private AlarmPropagationInfo propagation;
|
private AlarmPropagationInfo propagation;
|
||||||
|
|||||||
@ -342,9 +342,12 @@ public class JpaAlarmDao extends JpaAbstractDao<AlarmEntity, Alarm> implements A
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public AlarmApiCallResult createOrUpdateActiveAlarm(AlarmCreateOrUpdateActiveRequest request, boolean alarmCreationEnabled) {
|
public AlarmApiCallResult createOrUpdateActiveAlarm(AlarmCreateOrUpdateActiveRequest request, boolean alarmCreationEnabled) {
|
||||||
|
UUID tenantUUID = request.getTenantId().getId();
|
||||||
|
log.debug("[{}] createOrUpdateActiveAlarm [{}] {}", tenantUUID, alarmCreationEnabled, request);
|
||||||
|
|
||||||
AlarmPropagationInfo ap = getSafePropagationInfo(request.getPropagation());
|
AlarmPropagationInfo ap = getSafePropagationInfo(request.getPropagation());
|
||||||
return toAlarmApiResult(alarmRepository.createOrUpdateActiveAlarm(
|
return toAlarmApiResult(alarmRepository.createOrUpdateActiveAlarm(
|
||||||
request.getTenantId().getId(),
|
tenantUUID,
|
||||||
request.getCustomerId() != null ? request.getCustomerId().getId() : CustomerId.NULL_UUID,
|
request.getCustomerId() != null ? request.getCustomerId().getId() : CustomerId.NULL_UUID,
|
||||||
request.getEdgeAlarmId() != null ? request.getEdgeAlarmId().getId() : UUID.randomUUID(),
|
request.getEdgeAlarmId() != null ? request.getEdgeAlarmId().getId() : UUID.randomUUID(),
|
||||||
System.currentTimeMillis(),
|
System.currentTimeMillis(),
|
||||||
@ -364,10 +367,14 @@ public class JpaAlarmDao extends JpaAbstractDao<AlarmEntity, Alarm> implements A
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public AlarmApiCallResult updateAlarm(AlarmUpdateRequest request) {
|
public AlarmApiCallResult updateAlarm(AlarmUpdateRequest request) {
|
||||||
|
UUID tenantUUID = request.getTenantId().getId();
|
||||||
|
UUID alarmUUID = request.getAlarmId().getId();
|
||||||
|
log.debug("[{}][{}] updateAlarm {}", tenantUUID, alarmUUID, request);
|
||||||
|
|
||||||
AlarmPropagationInfo ap = getSafePropagationInfo(request.getPropagation());
|
AlarmPropagationInfo ap = getSafePropagationInfo(request.getPropagation());
|
||||||
return toAlarmApiResult(alarmRepository.updateAlarm(
|
return toAlarmApiResult(alarmRepository.updateAlarm(
|
||||||
request.getTenantId().getId(),
|
tenantUUID,
|
||||||
request.getAlarmId().getId(),
|
alarmUUID,
|
||||||
request.getSeverity().name(),
|
request.getSeverity().name(),
|
||||||
request.getStartTs(), request.getEndTs(),
|
request.getStartTs(), request.getEndTs(),
|
||||||
getDetailsAsString(request.getDetails()),
|
getDetailsAsString(request.getDetails()),
|
||||||
@ -380,11 +387,13 @@ public class JpaAlarmDao extends JpaAbstractDao<AlarmEntity, Alarm> implements A
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public AlarmApiCallResult acknowledgeAlarm(TenantId tenantId, AlarmId id, long ackTs) {
|
public AlarmApiCallResult acknowledgeAlarm(TenantId tenantId, AlarmId id, long ackTs) {
|
||||||
|
log.debug("[{}][{}] acknowledgeAlarm [{}]", tenantId, id, ackTs);
|
||||||
return toAlarmApiResult(alarmRepository.acknowledgeAlarm(tenantId.getId(), id.getId(), ackTs));
|
return toAlarmApiResult(alarmRepository.acknowledgeAlarm(tenantId.getId(), id.getId(), ackTs));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public AlarmApiCallResult clearAlarm(TenantId tenantId, AlarmId id, long clearTs, JsonNode details) {
|
public AlarmApiCallResult clearAlarm(TenantId tenantId, AlarmId id, long clearTs, JsonNode details) {
|
||||||
|
log.debug("[{}][{}] clearAlarm [{}]", tenantId, id, clearTs);
|
||||||
return toAlarmApiResult(alarmRepository.clearAlarm(tenantId.getId(), id.getId(), clearTs, details != null ? getDetailsAsString(details) : null));
|
return toAlarmApiResult(alarmRepository.clearAlarm(tenantId.getId(), id.getId(), clearTs, details != null ? getDetailsAsString(details) : null));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
82
dao/src/test/java/org/thingsboard/server/dao/cache/RedisTbTransactionalCacheTest.java
vendored
Normal file
82
dao/src/test/java/org/thingsboard/server/dao/cache/RedisTbTransactionalCacheTest.java
vendored
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
/**
|
||||||
|
* Copyright © 2016-2024 The Thingsboard Authors
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.thingsboard.server.dao.cache;
|
||||||
|
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.junit.jupiter.api.extension.ExtendWith;
|
||||||
|
import org.springframework.boot.test.mock.mockito.MockBean;
|
||||||
|
import org.springframework.data.redis.connection.RedisConnection;
|
||||||
|
import org.springframework.data.redis.connection.RedisConnectionFactory;
|
||||||
|
import org.springframework.test.context.ContextConfiguration;
|
||||||
|
import org.springframework.test.context.TestPropertySource;
|
||||||
|
import org.springframework.test.context.junit.jupiter.SpringExtension;
|
||||||
|
import org.thingsboard.server.cache.CacheSpecsMap;
|
||||||
|
import org.thingsboard.server.cache.RedisSslCredentials;
|
||||||
|
import org.thingsboard.server.cache.TBRedisCacheConfiguration;
|
||||||
|
import org.thingsboard.server.common.data.id.DeviceId;
|
||||||
|
import org.thingsboard.server.common.data.relation.RelationTypeGroup;
|
||||||
|
import org.thingsboard.server.dao.relation.RelationCacheKey;
|
||||||
|
import org.thingsboard.server.dao.relation.RelationRedisCache;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import static org.mockito.Mockito.never;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
|
import static org.mockito.Mockito.verifyNoInteractions;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
@ExtendWith(SpringExtension.class)
|
||||||
|
@ContextConfiguration(classes = {RelationRedisCache.class, CacheSpecsMap.class, TBRedisCacheConfiguration.class})
|
||||||
|
@TestPropertySource(properties = {
|
||||||
|
"cache.type=redis",
|
||||||
|
"cache.specs.relations.timeToLiveInMinutes=1440",
|
||||||
|
"cache.specs.relations.maxSize=0",
|
||||||
|
})
|
||||||
|
@Slf4j
|
||||||
|
public class RedisTbTransactionalCacheTest {
|
||||||
|
|
||||||
|
@MockBean
|
||||||
|
private RelationRedisCache relationRedisCache;
|
||||||
|
@MockBean
|
||||||
|
private RedisConnectionFactory connectionFactory;
|
||||||
|
@MockBean
|
||||||
|
private RedisConnection redisConnection;
|
||||||
|
@MockBean
|
||||||
|
private RedisSslCredentials redisSslCredentials;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNoOpWhenCacheDisabled() {
|
||||||
|
when(connectionFactory.getConnection()).thenReturn(redisConnection);
|
||||||
|
|
||||||
|
relationRedisCache.put(createRelationCacheKey(), null);
|
||||||
|
relationRedisCache.putIfAbsent(createRelationCacheKey(), null);
|
||||||
|
relationRedisCache.evict(createRelationCacheKey());
|
||||||
|
relationRedisCache.evict(List.of(createRelationCacheKey()));
|
||||||
|
relationRedisCache.getAndPutInTransaction(createRelationCacheKey(), null, false);
|
||||||
|
relationRedisCache.getAndPutInTransaction(createRelationCacheKey(), null, null, null, false);
|
||||||
|
relationRedisCache.getOrFetchFromDB(createRelationCacheKey(), null, false, false);
|
||||||
|
|
||||||
|
verify(connectionFactory, never()).getConnection();
|
||||||
|
verifyNoInteractions(redisConnection);
|
||||||
|
}
|
||||||
|
|
||||||
|
private RelationCacheKey createRelationCacheKey() {
|
||||||
|
return new RelationCacheKey(new DeviceId(UUID.randomUUID()), new DeviceId(UUID.randomUUID()), null, RelationTypeGroup.COMMON);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -58,7 +58,6 @@ import org.thingsboard.server.dao.device.DeviceService;
|
|||||||
import org.thingsboard.server.dao.relation.RelationService;
|
import org.thingsboard.server.dao.relation.RelationService;
|
||||||
import org.thingsboard.server.dao.user.UserService;
|
import org.thingsboard.server.dao.user.UserService;
|
||||||
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
@ -245,8 +244,8 @@ public class AlarmServiceTest extends AbstractServiceTest {
|
|||||||
// Check child relation
|
// Check child relation
|
||||||
PageData<AlarmInfo> alarms = alarmService.findAlarmsV2(tenantId, AlarmQueryV2.builder()
|
PageData<AlarmInfo> alarms = alarmService.findAlarmsV2(tenantId, AlarmQueryV2.builder()
|
||||||
.affectedEntityId(childId)
|
.affectedEntityId(childId)
|
||||||
.severityList(Arrays.asList(AlarmSeverity.CRITICAL))
|
.severityList(List.of(AlarmSeverity.CRITICAL))
|
||||||
.statusList(Arrays.asList(AlarmSearchStatus.ACTIVE, AlarmSearchStatus.UNACK)).pageLink(
|
.statusList(List.of(AlarmSearchStatus.ACTIVE, AlarmSearchStatus.UNACK)).pageLink(
|
||||||
new TimePageLink(1, 0, "",
|
new TimePageLink(1, 0, "",
|
||||||
new SortOrder("createdTime", SortOrder.Direction.DESC), 0L, System.currentTimeMillis())
|
new SortOrder("createdTime", SortOrder.Direction.DESC), 0L, System.currentTimeMillis())
|
||||||
).build());
|
).build());
|
||||||
@ -257,8 +256,8 @@ public class AlarmServiceTest extends AbstractServiceTest {
|
|||||||
// Check parent relation
|
// Check parent relation
|
||||||
alarms = alarmService.findAlarmsV2(tenantId, AlarmQueryV2.builder()
|
alarms = alarmService.findAlarmsV2(tenantId, AlarmQueryV2.builder()
|
||||||
.affectedEntityId(parentId)
|
.affectedEntityId(parentId)
|
||||||
.severityList(Arrays.asList(AlarmSeverity.CRITICAL))
|
.severityList(List.of(AlarmSeverity.CRITICAL))
|
||||||
.statusList(Arrays.asList(AlarmSearchStatus.ACTIVE, AlarmSearchStatus.UNACK)).pageLink(
|
.statusList(List.of(AlarmSearchStatus.ACTIVE, AlarmSearchStatus.UNACK)).pageLink(
|
||||||
new TimePageLink(1, 0, "",
|
new TimePageLink(1, 0, "",
|
||||||
new SortOrder("createdTime", SortOrder.Direction.DESC), 0L, System.currentTimeMillis())
|
new SortOrder("createdTime", SortOrder.Direction.DESC), 0L, System.currentTimeMillis())
|
||||||
).build());
|
).build());
|
||||||
@ -272,8 +271,8 @@ public class AlarmServiceTest extends AbstractServiceTest {
|
|||||||
// Check child relation
|
// Check child relation
|
||||||
alarms = alarmService.findAlarmsV2(tenantId, AlarmQueryV2.builder()
|
alarms = alarmService.findAlarmsV2(tenantId, AlarmQueryV2.builder()
|
||||||
.affectedEntityId(childId)
|
.affectedEntityId(childId)
|
||||||
.severityList(Arrays.asList(AlarmSeverity.CRITICAL))
|
.severityList(List.of(AlarmSeverity.CRITICAL))
|
||||||
.statusList(Arrays.asList(AlarmSearchStatus.ACTIVE, AlarmSearchStatus.UNACK)).pageLink(
|
.statusList(List.of(AlarmSearchStatus.ACTIVE, AlarmSearchStatus.UNACK)).pageLink(
|
||||||
new TimePageLink(1, 0, "",
|
new TimePageLink(1, 0, "",
|
||||||
new SortOrder("createdTime", SortOrder.Direction.DESC), 0L, System.currentTimeMillis())
|
new SortOrder("createdTime", SortOrder.Direction.DESC), 0L, System.currentTimeMillis())
|
||||||
).build());
|
).build());
|
||||||
@ -284,8 +283,8 @@ public class AlarmServiceTest extends AbstractServiceTest {
|
|||||||
// Check parent relation
|
// Check parent relation
|
||||||
alarms = alarmService.findAlarmsV2(tenantId, AlarmQueryV2.builder()
|
alarms = alarmService.findAlarmsV2(tenantId, AlarmQueryV2.builder()
|
||||||
.affectedEntityId(parentId)
|
.affectedEntityId(parentId)
|
||||||
.severityList(Arrays.asList(AlarmSeverity.CRITICAL))
|
.severityList(List.of(AlarmSeverity.CRITICAL))
|
||||||
.statusList(Arrays.asList(AlarmSearchStatus.ACTIVE, AlarmSearchStatus.UNACK)).pageLink(
|
.statusList(List.of(AlarmSearchStatus.ACTIVE, AlarmSearchStatus.UNACK)).pageLink(
|
||||||
new TimePageLink(1, 0, "",
|
new TimePageLink(1, 0, "",
|
||||||
new SortOrder("createdTime", SortOrder.Direction.DESC), 0L, System.currentTimeMillis())
|
new SortOrder("createdTime", SortOrder.Direction.DESC), 0L, System.currentTimeMillis())
|
||||||
).build());
|
).build());
|
||||||
@ -298,8 +297,8 @@ public class AlarmServiceTest extends AbstractServiceTest {
|
|||||||
|
|
||||||
alarms = alarmService.findAlarmsV2(tenantId, AlarmQueryV2.builder()
|
alarms = alarmService.findAlarmsV2(tenantId, AlarmQueryV2.builder()
|
||||||
.affectedEntityId(childId)
|
.affectedEntityId(childId)
|
||||||
.severityList(Arrays.asList(AlarmSeverity.CRITICAL))
|
.severityList(List.of(AlarmSeverity.CRITICAL))
|
||||||
.statusList(Arrays.asList(AlarmSearchStatus.ACTIVE, AlarmSearchStatus.ACK)).pageLink(
|
.statusList(List.of(AlarmSearchStatus.ACTIVE, AlarmSearchStatus.ACK)).pageLink(
|
||||||
new TimePageLink(1, 0, "",
|
new TimePageLink(1, 0, "",
|
||||||
new SortOrder("createdTime", SortOrder.Direction.DESC), 0L, System.currentTimeMillis())
|
new SortOrder("createdTime", SortOrder.Direction.DESC), 0L, System.currentTimeMillis())
|
||||||
).build());
|
).build());
|
||||||
@ -310,8 +309,8 @@ public class AlarmServiceTest extends AbstractServiceTest {
|
|||||||
// Check not existing relation
|
// Check not existing relation
|
||||||
alarms = alarmService.findAlarmsV2(tenantId, AlarmQueryV2.builder()
|
alarms = alarmService.findAlarmsV2(tenantId, AlarmQueryV2.builder()
|
||||||
.affectedEntityId(childId)
|
.affectedEntityId(childId)
|
||||||
.severityList(Arrays.asList(AlarmSeverity.CRITICAL))
|
.severityList(List.of(AlarmSeverity.CRITICAL))
|
||||||
.statusList(Arrays.asList(AlarmSearchStatus.ACTIVE, AlarmSearchStatus.UNACK)).pageLink(
|
.statusList(List.of(AlarmSearchStatus.ACTIVE, AlarmSearchStatus.UNACK)).pageLink(
|
||||||
new TimePageLink(1, 0, "",
|
new TimePageLink(1, 0, "",
|
||||||
new SortOrder("createdTime", SortOrder.Direction.DESC), 0L, System.currentTimeMillis())
|
new SortOrder("createdTime", SortOrder.Direction.DESC), 0L, System.currentTimeMillis())
|
||||||
).build());
|
).build());
|
||||||
@ -323,8 +322,8 @@ public class AlarmServiceTest extends AbstractServiceTest {
|
|||||||
|
|
||||||
alarms = alarmService.findAlarmsV2(tenantId, AlarmQueryV2.builder()
|
alarms = alarmService.findAlarmsV2(tenantId, AlarmQueryV2.builder()
|
||||||
.affectedEntityId(childId)
|
.affectedEntityId(childId)
|
||||||
.severityList(Arrays.asList(AlarmSeverity.CRITICAL))
|
.severityList(List.of(AlarmSeverity.CRITICAL))
|
||||||
.statusList(Arrays.asList(AlarmSearchStatus.CLEARED, AlarmSearchStatus.ACK)).pageLink(
|
.statusList(List.of(AlarmSearchStatus.CLEARED, AlarmSearchStatus.ACK)).pageLink(
|
||||||
new TimePageLink(1, 0, "",
|
new TimePageLink(1, 0, "",
|
||||||
new SortOrder("createdTime", SortOrder.Direction.DESC), 0L, System.currentTimeMillis())
|
new SortOrder("createdTime", SortOrder.Direction.DESC), 0L, System.currentTimeMillis())
|
||||||
).build());
|
).build());
|
||||||
@ -334,7 +333,7 @@ public class AlarmServiceTest extends AbstractServiceTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testFindAssignedAlarm() throws ExecutionException, InterruptedException {
|
public void testFindAssignedAlarm() {
|
||||||
|
|
||||||
AssetId parentId = new AssetId(Uuids.timeBased());
|
AssetId parentId = new AssetId(Uuids.timeBased());
|
||||||
AssetId childId = new AssetId(Uuids.timeBased());
|
AssetId childId = new AssetId(Uuids.timeBased());
|
||||||
@ -368,7 +367,6 @@ public class AlarmServiceTest extends AbstractServiceTest {
|
|||||||
|
|
||||||
PageData<AlarmInfo> alarms = alarmService.findAlarms(tenantId, AlarmQuery.builder()
|
PageData<AlarmInfo> alarms = alarmService.findAlarms(tenantId, AlarmQuery.builder()
|
||||||
.assigneeId(tenantUser.getId())
|
.assigneeId(tenantUser.getId())
|
||||||
.fetchOriginator(true)
|
|
||||||
.pageLink(new TimePageLink(1, 0, "",
|
.pageLink(new TimePageLink(1, 0, "",
|
||||||
new SortOrder("createdTime", SortOrder.Direction.DESC), 0L, System.currentTimeMillis())
|
new SortOrder("createdTime", SortOrder.Direction.DESC), 0L, System.currentTimeMillis())
|
||||||
).build());
|
).build());
|
||||||
@ -405,7 +403,7 @@ public class AlarmServiceTest extends AbstractServiceTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testFindCustomerAlarm() throws ExecutionException, InterruptedException {
|
public void testFindCustomerAlarm() {
|
||||||
Customer customer = new Customer();
|
Customer customer = new Customer();
|
||||||
customer.setTitle("TestCustomer");
|
customer.setTitle("TestCustomer");
|
||||||
customer.setTenantId(tenantId);
|
customer.setTenantId(tenantId);
|
||||||
@ -451,10 +449,10 @@ public class AlarmServiceTest extends AbstractServiceTest {
|
|||||||
pageLink.setStartTs(0L);
|
pageLink.setStartTs(0L);
|
||||||
pageLink.setEndTs(System.currentTimeMillis());
|
pageLink.setEndTs(System.currentTimeMillis());
|
||||||
pageLink.setSearchPropagatedAlarms(true);
|
pageLink.setSearchPropagatedAlarms(true);
|
||||||
pageLink.setSeverityList(Arrays.asList(AlarmSeverity.CRITICAL, AlarmSeverity.WARNING));
|
pageLink.setSeverityList(List.of(AlarmSeverity.CRITICAL, AlarmSeverity.WARNING));
|
||||||
pageLink.setStatusList(Arrays.asList(AlarmSearchStatus.ACTIVE));
|
pageLink.setStatusList(List.of(AlarmSearchStatus.ACTIVE));
|
||||||
|
|
||||||
PageData<AlarmData> tenantAlarms = alarmService.findAlarmDataByQueryForEntities(tenantId, toQuery(pageLink), Arrays.asList(tenantDevice.getId(), customerDevice.getId()));
|
PageData<AlarmData> tenantAlarms = alarmService.findAlarmDataByQueryForEntities(tenantId, toQuery(pageLink), List.of(tenantDevice.getId(), customerDevice.getId()));
|
||||||
Assert.assertEquals(2, tenantAlarms.getData().size());
|
Assert.assertEquals(2, tenantAlarms.getData().size());
|
||||||
|
|
||||||
PageData<AlarmData> customerAlarms = alarmService.findAlarmDataByQueryForEntities(tenantId, toQuery(pageLink), Collections.singletonList(customerDevice.getId()));
|
PageData<AlarmData> customerAlarms = alarmService.findAlarmDataByQueryForEntities(tenantId, toQuery(pageLink), Collections.singletonList(customerDevice.getId()));
|
||||||
@ -473,7 +471,7 @@ public class AlarmServiceTest extends AbstractServiceTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testFindPropagatedCustomerAssetAlarm() throws ExecutionException, InterruptedException {
|
public void testFindPropagatedCustomerAssetAlarm() {
|
||||||
Customer customer = new Customer();
|
Customer customer = new Customer();
|
||||||
customer.setTitle("TestCustomer");
|
customer.setTitle("TestCustomer");
|
||||||
customer.setTenantId(tenantId);
|
customer.setTenantId(tenantId);
|
||||||
@ -525,8 +523,8 @@ public class AlarmServiceTest extends AbstractServiceTest {
|
|||||||
pageLink.setStartTs(0L);
|
pageLink.setStartTs(0L);
|
||||||
pageLink.setEndTs(System.currentTimeMillis());
|
pageLink.setEndTs(System.currentTimeMillis());
|
||||||
pageLink.setSearchPropagatedAlarms(true);
|
pageLink.setSearchPropagatedAlarms(true);
|
||||||
pageLink.setSeverityList(Arrays.asList(AlarmSeverity.CRITICAL, AlarmSeverity.WARNING));
|
pageLink.setSeverityList(List.of(AlarmSeverity.CRITICAL, AlarmSeverity.WARNING));
|
||||||
pageLink.setStatusList(Arrays.asList(AlarmSearchStatus.ACTIVE));
|
pageLink.setStatusList(List.of(AlarmSearchStatus.ACTIVE));
|
||||||
|
|
||||||
//TEST that propagated alarms are visible on the asset level.
|
//TEST that propagated alarms are visible on the asset level.
|
||||||
PageData<AlarmData> customerAlarms = alarmService.findAlarmDataByQueryForEntities(tenantId, toQuery(pageLink), Collections.singletonList(customerAsset.getId()));
|
PageData<AlarmData> customerAlarms = alarmService.findAlarmDataByQueryForEntities(tenantId, toQuery(pageLink), Collections.singletonList(customerAsset.getId()));
|
||||||
@ -576,7 +574,7 @@ public class AlarmServiceTest extends AbstractServiceTest {
|
|||||||
pageLink.setStartTs(0L);
|
pageLink.setStartTs(0L);
|
||||||
pageLink.setEndTs(System.currentTimeMillis());
|
pageLink.setEndTs(System.currentTimeMillis());
|
||||||
pageLink.setSearchPropagatedAlarms(true);
|
pageLink.setSearchPropagatedAlarms(true);
|
||||||
pageLink.setSeverityList(Arrays.asList(AlarmSeverity.CRITICAL, AlarmSeverity.WARNING));
|
pageLink.setSeverityList(List.of(AlarmSeverity.CRITICAL, AlarmSeverity.WARNING));
|
||||||
pageLink.setStatusList(Collections.singletonList(AlarmSearchStatus.ACTIVE));
|
pageLink.setStatusList(Collections.singletonList(AlarmSearchStatus.ACTIVE));
|
||||||
|
|
||||||
//TEST that propagated alarms are visible on the asset level.
|
//TEST that propagated alarms are visible on the asset level.
|
||||||
@ -599,7 +597,7 @@ public class AlarmServiceTest extends AbstractServiceTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testFindHighestAlarmSeverity() throws ExecutionException, InterruptedException {
|
public void testFindHighestAlarmSeverity() {
|
||||||
Customer customer = new Customer();
|
Customer customer = new Customer();
|
||||||
customer.setTitle("TestCustomer");
|
customer.setTitle("TestCustomer");
|
||||||
customer.setTenantId(tenantId);
|
customer.setTenantId(tenantId);
|
||||||
@ -679,8 +677,8 @@ public class AlarmServiceTest extends AbstractServiceTest {
|
|||||||
pageLink.setStartTs(0L);
|
pageLink.setStartTs(0L);
|
||||||
pageLink.setEndTs(System.currentTimeMillis());
|
pageLink.setEndTs(System.currentTimeMillis());
|
||||||
pageLink.setSearchPropagatedAlarms(false);
|
pageLink.setSearchPropagatedAlarms(false);
|
||||||
pageLink.setSeverityList(Arrays.asList(AlarmSeverity.CRITICAL, AlarmSeverity.WARNING));
|
pageLink.setSeverityList(List.of(AlarmSeverity.CRITICAL, AlarmSeverity.WARNING));
|
||||||
pageLink.setStatusList(Arrays.asList(AlarmSearchStatus.ACTIVE));
|
pageLink.setStatusList(List.of(AlarmSearchStatus.ACTIVE));
|
||||||
|
|
||||||
PageData<AlarmData> alarms = alarmService.findAlarmDataByQueryForEntities(tenantId, toQuery(pageLink), Collections.singletonList(childId));
|
PageData<AlarmData> alarms = alarmService.findAlarmDataByQueryForEntities(tenantId, toQuery(pageLink), Collections.singletonList(childId));
|
||||||
|
|
||||||
@ -695,8 +693,8 @@ public class AlarmServiceTest extends AbstractServiceTest {
|
|||||||
pageLink.setStartTs(0L);
|
pageLink.setStartTs(0L);
|
||||||
pageLink.setEndTs(System.currentTimeMillis());
|
pageLink.setEndTs(System.currentTimeMillis());
|
||||||
pageLink.setSearchPropagatedAlarms(false);
|
pageLink.setSearchPropagatedAlarms(false);
|
||||||
pageLink.setSeverityList(Arrays.asList(AlarmSeverity.CRITICAL, AlarmSeverity.WARNING));
|
pageLink.setSeverityList(List.of(AlarmSeverity.CRITICAL, AlarmSeverity.WARNING));
|
||||||
pageLink.setStatusList(Arrays.asList(AlarmSearchStatus.ACTIVE));
|
pageLink.setStatusList(List.of(AlarmSearchStatus.ACTIVE));
|
||||||
|
|
||||||
alarms = alarmService.findAlarmDataByQueryForEntities(tenantId, toQuery(pageLink), Collections.singletonList(childId));
|
alarms = alarmService.findAlarmDataByQueryForEntities(tenantId, toQuery(pageLink), Collections.singletonList(childId));
|
||||||
Assert.assertNotNull(alarms.getData());
|
Assert.assertNotNull(alarms.getData());
|
||||||
@ -722,8 +720,8 @@ public class AlarmServiceTest extends AbstractServiceTest {
|
|||||||
pageLink.setStartTs(0L);
|
pageLink.setStartTs(0L);
|
||||||
pageLink.setEndTs(System.currentTimeMillis());
|
pageLink.setEndTs(System.currentTimeMillis());
|
||||||
pageLink.setSearchPropagatedAlarms(true);
|
pageLink.setSearchPropagatedAlarms(true);
|
||||||
pageLink.setSeverityList(Arrays.asList(AlarmSeverity.CRITICAL, AlarmSeverity.WARNING));
|
pageLink.setSeverityList(List.of(AlarmSeverity.CRITICAL, AlarmSeverity.WARNING));
|
||||||
pageLink.setStatusList(Arrays.asList(AlarmSearchStatus.ACTIVE));
|
pageLink.setStatusList(List.of(AlarmSearchStatus.ACTIVE));
|
||||||
|
|
||||||
alarms = alarmService.findAlarmDataByQueryForEntities(tenantId, toQuery(pageLink), Collections.singletonList(childId));
|
alarms = alarmService.findAlarmDataByQueryForEntities(tenantId, toQuery(pageLink), Collections.singletonList(childId));
|
||||||
Assert.assertNotNull(alarms.getData());
|
Assert.assertNotNull(alarms.getData());
|
||||||
@ -738,8 +736,8 @@ public class AlarmServiceTest extends AbstractServiceTest {
|
|||||||
pageLink.setStartTs(0L);
|
pageLink.setStartTs(0L);
|
||||||
pageLink.setEndTs(System.currentTimeMillis());
|
pageLink.setEndTs(System.currentTimeMillis());
|
||||||
pageLink.setSearchPropagatedAlarms(true);
|
pageLink.setSearchPropagatedAlarms(true);
|
||||||
pageLink.setSeverityList(Arrays.asList(AlarmSeverity.CRITICAL, AlarmSeverity.WARNING));
|
pageLink.setSeverityList(List.of(AlarmSeverity.CRITICAL, AlarmSeverity.WARNING));
|
||||||
pageLink.setStatusList(Arrays.asList(AlarmSearchStatus.ACTIVE));
|
pageLink.setStatusList(List.of(AlarmSearchStatus.ACTIVE));
|
||||||
|
|
||||||
alarms = alarmService.findAlarmDataByQueryForEntities(tenantId, toQuery(pageLink), Collections.singletonList(parentId));
|
alarms = alarmService.findAlarmDataByQueryForEntities(tenantId, toQuery(pageLink), Collections.singletonList(parentId));
|
||||||
Assert.assertNotNull(alarms.getData());
|
Assert.assertNotNull(alarms.getData());
|
||||||
@ -748,7 +746,6 @@ public class AlarmServiceTest extends AbstractServiceTest {
|
|||||||
|
|
||||||
PageData<AlarmInfo> alarmsInfoData = alarmService.findAlarms(tenantId, AlarmQuery.builder()
|
PageData<AlarmInfo> alarmsInfoData = alarmService.findAlarms(tenantId, AlarmQuery.builder()
|
||||||
.affectedEntityId(childId)
|
.affectedEntityId(childId)
|
||||||
.fetchOriginator(true)
|
|
||||||
.status(AlarmStatus.ACTIVE_UNACK).pageLink(
|
.status(AlarmStatus.ACTIVE_UNACK).pageLink(
|
||||||
new TimePageLink(10, 0, "",
|
new TimePageLink(10, 0, "",
|
||||||
new SortOrder("createdTime", SortOrder.Direction.DESC), 0L, System.currentTimeMillis())
|
new SortOrder("createdTime", SortOrder.Direction.DESC), 0L, System.currentTimeMillis())
|
||||||
@ -759,7 +756,6 @@ public class AlarmServiceTest extends AbstractServiceTest {
|
|||||||
|
|
||||||
alarmsInfoData = alarmService.findAlarms(tenantId, AlarmQuery.builder()
|
alarmsInfoData = alarmService.findAlarms(tenantId, AlarmQuery.builder()
|
||||||
.affectedEntityId(parentId)
|
.affectedEntityId(parentId)
|
||||||
.fetchOriginator(true)
|
|
||||||
.status(AlarmStatus.ACTIVE_UNACK).pageLink(
|
.status(AlarmStatus.ACTIVE_UNACK).pageLink(
|
||||||
new TimePageLink(10, 0, "",
|
new TimePageLink(10, 0, "",
|
||||||
new SortOrder("createdTime", SortOrder.Direction.DESC), 0L, System.currentTimeMillis())
|
new SortOrder("createdTime", SortOrder.Direction.DESC), 0L, System.currentTimeMillis())
|
||||||
@ -770,7 +766,6 @@ public class AlarmServiceTest extends AbstractServiceTest {
|
|||||||
|
|
||||||
alarmsInfoData = alarmService.findAlarms(tenantId, AlarmQuery.builder()
|
alarmsInfoData = alarmService.findAlarms(tenantId, AlarmQuery.builder()
|
||||||
.affectedEntityId(parentId2)
|
.affectedEntityId(parentId2)
|
||||||
.fetchOriginator(true)
|
|
||||||
.status(AlarmStatus.ACTIVE_UNACK).pageLink(
|
.status(AlarmStatus.ACTIVE_UNACK).pageLink(
|
||||||
new TimePageLink(10, 0, "",
|
new TimePageLink(10, 0, "",
|
||||||
new SortOrder("createdTime", SortOrder.Direction.DESC), 0L, System.currentTimeMillis())
|
new SortOrder("createdTime", SortOrder.Direction.DESC), 0L, System.currentTimeMillis())
|
||||||
@ -786,8 +781,8 @@ public class AlarmServiceTest extends AbstractServiceTest {
|
|||||||
pageLink.setStartTs(0L);
|
pageLink.setStartTs(0L);
|
||||||
pageLink.setEndTs(System.currentTimeMillis());
|
pageLink.setEndTs(System.currentTimeMillis());
|
||||||
pageLink.setSearchPropagatedAlarms(true);
|
pageLink.setSearchPropagatedAlarms(true);
|
||||||
pageLink.setSeverityList(Arrays.asList(AlarmSeverity.CRITICAL, AlarmSeverity.WARNING));
|
pageLink.setSeverityList(List.of(AlarmSeverity.CRITICAL, AlarmSeverity.WARNING));
|
||||||
pageLink.setStatusList(Arrays.asList(AlarmSearchStatus.ACTIVE));
|
pageLink.setStatusList(List.of(AlarmSearchStatus.ACTIVE));
|
||||||
|
|
||||||
alarms = alarmService.findAlarmDataByQueryForEntities(tenantId, toQuery(pageLink), Collections.singletonList(parentId));
|
alarms = alarmService.findAlarmDataByQueryForEntities(tenantId, toQuery(pageLink), Collections.singletonList(parentId));
|
||||||
Assert.assertNotNull(alarms.getData());
|
Assert.assertNotNull(alarms.getData());
|
||||||
@ -803,8 +798,8 @@ public class AlarmServiceTest extends AbstractServiceTest {
|
|||||||
pageLink.setStartTs(0L);
|
pageLink.setStartTs(0L);
|
||||||
pageLink.setEndTs(System.currentTimeMillis());
|
pageLink.setEndTs(System.currentTimeMillis());
|
||||||
pageLink.setSearchPropagatedAlarms(true);
|
pageLink.setSearchPropagatedAlarms(true);
|
||||||
pageLink.setSeverityList(Arrays.asList(AlarmSeverity.CRITICAL, AlarmSeverity.WARNING));
|
pageLink.setSeverityList(List.of(AlarmSeverity.CRITICAL, AlarmSeverity.WARNING));
|
||||||
pageLink.setStatusList(Arrays.asList(AlarmSearchStatus.ACTIVE));
|
pageLink.setStatusList(List.of(AlarmSearchStatus.ACTIVE));
|
||||||
|
|
||||||
alarms = alarmService.findAlarmDataByQueryForEntities(tenantId, toQuery(pageLink), Collections.singletonList(childId));
|
alarms = alarmService.findAlarmDataByQueryForEntities(tenantId, toQuery(pageLink), Collections.singletonList(childId));
|
||||||
Assert.assertNotNull(alarms.getData());
|
Assert.assertNotNull(alarms.getData());
|
||||||
@ -813,7 +808,7 @@ public class AlarmServiceTest extends AbstractServiceTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testCountAlarmsUsingAlarmDataQuery() throws ExecutionException, InterruptedException {
|
public void testCountAlarmsUsingAlarmDataQuery() {
|
||||||
AssetId childId = new AssetId(Uuids.timeBased());
|
AssetId childId = new AssetId(Uuids.timeBased());
|
||||||
|
|
||||||
long ts = System.currentTimeMillis();
|
long ts = System.currentTimeMillis();
|
||||||
@ -829,7 +824,7 @@ public class AlarmServiceTest extends AbstractServiceTest {
|
|||||||
.startTs(0L)
|
.startTs(0L)
|
||||||
.endTs(System.currentTimeMillis())
|
.endTs(System.currentTimeMillis())
|
||||||
.searchPropagatedAlarms(false)
|
.searchPropagatedAlarms(false)
|
||||||
.severityList(Arrays.asList(AlarmSeverity.CRITICAL, AlarmSeverity.WARNING))
|
.severityList(List.of(AlarmSeverity.CRITICAL, AlarmSeverity.WARNING))
|
||||||
.statusList(List.of(AlarmSearchStatus.ACTIVE))
|
.statusList(List.of(AlarmSearchStatus.ACTIVE))
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
@ -841,7 +836,7 @@ public class AlarmServiceTest extends AbstractServiceTest {
|
|||||||
.startTs(0L)
|
.startTs(0L)
|
||||||
.endTs(System.currentTimeMillis())
|
.endTs(System.currentTimeMillis())
|
||||||
.searchPropagatedAlarms(true)
|
.searchPropagatedAlarms(true)
|
||||||
.severityList(Arrays.asList(AlarmSeverity.CRITICAL, AlarmSeverity.WARNING))
|
.severityList(List.of(AlarmSeverity.CRITICAL, AlarmSeverity.WARNING))
|
||||||
.statusList(List.of(AlarmSearchStatus.ACTIVE))
|
.statusList(List.of(AlarmSearchStatus.ACTIVE))
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
@ -866,7 +861,7 @@ public class AlarmServiceTest extends AbstractServiceTest {
|
|||||||
.startTs(0L)
|
.startTs(0L)
|
||||||
.endTs(System.currentTimeMillis())
|
.endTs(System.currentTimeMillis())
|
||||||
.searchPropagatedAlarms(true)
|
.searchPropagatedAlarms(true)
|
||||||
.severityList(Arrays.asList(AlarmSeverity.CRITICAL, AlarmSeverity.WARNING))
|
.severityList(List.of(AlarmSeverity.CRITICAL, AlarmSeverity.WARNING))
|
||||||
.statusList(List.of(AlarmSearchStatus.ACTIVE, AlarmSearchStatus.CLEARED))
|
.statusList(List.of(AlarmSearchStatus.ACTIVE, AlarmSearchStatus.CLEARED))
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
@ -939,6 +934,6 @@ public class AlarmServiceTest extends AbstractServiceTest {
|
|||||||
).build());
|
).build());
|
||||||
Assert.assertNotNull(alarms.getData());
|
Assert.assertNotNull(alarms.getData());
|
||||||
Assert.assertEquals(0, alarms.getData().size());
|
Assert.assertEquals(0, alarms.getData().size());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -27,10 +27,10 @@ import org.springframework.http.HttpMethod;
|
|||||||
import org.springframework.http.HttpStatus;
|
import org.springframework.http.HttpStatus;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.http.client.reactive.ReactorClientHttpConnector;
|
import org.springframework.http.client.reactive.ReactorClientHttpConnector;
|
||||||
import org.springframework.web.client.RestClientResponseException;
|
|
||||||
import org.springframework.web.reactive.function.BodyInserters;
|
import org.springframework.web.reactive.function.BodyInserters;
|
||||||
import org.springframework.web.reactive.function.client.WebClient;
|
import org.springframework.web.reactive.function.client.WebClient;
|
||||||
import org.springframework.web.reactive.function.client.WebClient.RequestBodySpec;
|
import org.springframework.web.reactive.function.client.WebClient.RequestBodySpec;
|
||||||
|
import org.springframework.web.reactive.function.client.WebClientResponseException;
|
||||||
import org.springframework.web.util.UriComponentsBuilder;
|
import org.springframework.web.util.UriComponentsBuilder;
|
||||||
import org.thingsboard.common.util.JacksonUtil;
|
import org.thingsboard.common.util.JacksonUtil;
|
||||||
import org.thingsboard.rule.engine.api.TbContext;
|
import org.thingsboard.rule.engine.api.TbContext;
|
||||||
@ -132,6 +132,7 @@ public class TbHttpClient {
|
|||||||
|
|
||||||
this.webClient = WebClient.builder()
|
this.webClient = WebClient.builder()
|
||||||
.clientConnector(new ReactorClientHttpConnector(httpClient))
|
.clientConnector(new ReactorClientHttpConnector(httpClient))
|
||||||
|
.defaultHeader(HttpHeaders.CONNECTION, "close") //In previous realization this header was present! (Added for hotfix "Connection reset")
|
||||||
.build();
|
.build();
|
||||||
} catch (SSLException e) {
|
} catch (SSLException e) {
|
||||||
throw new TbNodeException(e);
|
throw new TbNodeException(e);
|
||||||
@ -170,7 +171,7 @@ public class TbHttpClient {
|
|||||||
BiConsumer<TbMsg, Throwable> onFailure) {
|
BiConsumer<TbMsg, Throwable> onFailure) {
|
||||||
try {
|
try {
|
||||||
if (semaphore != null && !semaphore.tryAcquire(config.getReadTimeoutMs(), TimeUnit.MILLISECONDS)) {
|
if (semaphore != null && !semaphore.tryAcquire(config.getReadTimeoutMs(), TimeUnit.MILLISECONDS)) {
|
||||||
ctx.tellFailure(msg, new RuntimeException("Timeout during waiting for reply!"));
|
onFailure.accept(msg, new RuntimeException("Timeout during waiting for reply!"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -183,10 +184,10 @@ public class TbHttpClient {
|
|||||||
.uri(uri)
|
.uri(uri)
|
||||||
.headers(headers -> prepareHeaders(headers, msg));
|
.headers(headers -> prepareHeaders(headers, msg));
|
||||||
|
|
||||||
if (HttpMethod.POST.equals(method) || HttpMethod.PUT.equals(method) ||
|
if ((HttpMethod.POST.equals(method) || HttpMethod.PUT.equals(method) ||
|
||||||
HttpMethod.PATCH.equals(method) || HttpMethod.DELETE.equals(method) ||
|
HttpMethod.PATCH.equals(method) || HttpMethod.DELETE.equals(method)) &&
|
||||||
!config.isIgnoreRequestBody()) {
|
!config.isIgnoreRequestBody()) {
|
||||||
request.body(BodyInserters.fromValue(getData(msg, config.isIgnoreRequestBody(), config.isParseToPlainText())));
|
request.body(BodyInserters.fromValue(getData(msg, config.isParseToPlainText())));
|
||||||
}
|
}
|
||||||
|
|
||||||
request
|
request
|
||||||
@ -236,11 +237,9 @@ public class TbHttpClient {
|
|||||||
return uri;
|
return uri;
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getData(TbMsg tbMsg, boolean ignoreBody, boolean parseToPlainText) {
|
private Object getData(TbMsg tbMsg, boolean parseToPlainText) {
|
||||||
if (!ignoreBody && parseToPlainText) {
|
String data = tbMsg.getData();
|
||||||
return JacksonUtil.toPlainText(tbMsg.getData());
|
return parseToPlainText ? JacksonUtil.toPlainText(data) : JacksonUtil.toJsonNode(data);
|
||||||
}
|
|
||||||
return tbMsg.getData();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private TbMsg processResponse(TbContext ctx, TbMsg origMsg, ResponseEntity<String> response) {
|
private TbMsg processResponse(TbContext ctx, TbMsg origMsg, ResponseEntity<String> response) {
|
||||||
@ -283,10 +282,9 @@ public class TbHttpClient {
|
|||||||
private TbMsg processException(TbMsg origMsg, Throwable e) {
|
private TbMsg processException(TbMsg origMsg, Throwable e) {
|
||||||
TbMsgMetaData metaData = origMsg.getMetaData();
|
TbMsgMetaData metaData = origMsg.getMetaData();
|
||||||
metaData.putValue(ERROR, e.getClass() + ": " + e.getMessage());
|
metaData.putValue(ERROR, e.getClass() + ": " + e.getMessage());
|
||||||
if (e instanceof RestClientResponseException) {
|
if (e instanceof WebClientResponseException restClientResponseException) {
|
||||||
RestClientResponseException restClientResponseException = (RestClientResponseException) e;
|
|
||||||
metaData.putValue(STATUS, restClientResponseException.getStatusText());
|
metaData.putValue(STATUS, restClientResponseException.getStatusText());
|
||||||
metaData.putValue(STATUS_CODE, restClientResponseException.getRawStatusCode() + "");
|
metaData.putValue(STATUS_CODE, restClientResponseException.getStatusCode().value() + "");
|
||||||
metaData.putValue(ERROR_BODY, restClientResponseException.getResponseBodyAsString());
|
metaData.putValue(ERROR_BODY, restClientResponseException.getResponseBodyAsString());
|
||||||
}
|
}
|
||||||
return TbMsg.transformMsgMetadata(origMsg, metaData);
|
return TbMsg.transformMsgMetadata(origMsg, metaData);
|
||||||
|
|||||||
@ -168,7 +168,7 @@ public class TbRestApiCallNodeTest extends AbstractRuleNodeUpgradeTest {
|
|||||||
try {
|
try {
|
||||||
assertEquals(path, request.getRequestLine().getUri(), "Request path matches");
|
assertEquals(path, request.getRequestLine().getUri(), "Request path matches");
|
||||||
assertTrue(request.containsHeader("Content-Type"), "Content-Type included");
|
assertTrue(request.containsHeader("Content-Type"), "Content-Type included");
|
||||||
assertEquals("text/plain;charset=UTF-8",
|
assertEquals("application/json",
|
||||||
request.getFirstHeader("Content-Type").getValue(), "Content-Type value");
|
request.getFirstHeader("Content-Type").getValue(), "Content-Type value");
|
||||||
assertTrue(request.containsHeader("Content-Length"), "Content-Length included");
|
assertTrue(request.containsHeader("Content-Length"), "Content-Length included");
|
||||||
assertEquals("2",
|
assertEquals("2",
|
||||||
|
|||||||
@ -456,6 +456,10 @@ export class UtilsService {
|
|||||||
return isDefined(value);
|
return isDefined(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public isDefinedAndNotNull(value: any): boolean {
|
||||||
|
return isDefinedAndNotNull(value);
|
||||||
|
}
|
||||||
|
|
||||||
public defaultValue(value: any, defaultValue: any): any {
|
public defaultValue(value: any, defaultValue: any): any {
|
||||||
if (isDefinedAndNotNull(value)) {
|
if (isDefinedAndNotNull(value)) {
|
||||||
return value;
|
return value;
|
||||||
|
|||||||
@ -160,7 +160,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<tb-chart-fill-settings
|
<tb-chart-fill-settings
|
||||||
formControlName="barBackgroundSettings"
|
formControlName="barBackgroundSettings"
|
||||||
title="widgets.chart.background"
|
titleText="widgets.chart.background"
|
||||||
fillNoneTitle="widgets.chart.fill-type-solid">
|
fillNoneTitle="widgets.chart.fill-type-solid">
|
||||||
</tb-chart-fill-settings>
|
</tb-chart-fill-settings>
|
||||||
<tb-time-series-no-aggregation-bar-width-settings
|
<tb-time-series-no-aggregation-bar-width-settings
|
||||||
|
|||||||
@ -203,23 +203,29 @@ export class UnreadNotificationWidgetComponent implements OnInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
markAsRead(id: string) {
|
markAsRead(id: string) {
|
||||||
const cmd = NotificationSubscriber.createMarkAsReadCommand(this.notificationWsService, [id]);
|
if (!this.ctx.isEdit && !this.ctx.isPreview) {
|
||||||
cmd.subscribe();
|
const cmd = NotificationSubscriber.createMarkAsReadCommand(this.notificationWsService, [id]);
|
||||||
|
cmd.subscribe();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
markAsAllRead($event: Event) {
|
markAsAllRead($event: Event) {
|
||||||
if ($event) {
|
if (!this.ctx.isEdit && !this.ctx.isPreview) {
|
||||||
$event.stopPropagation();
|
if ($event) {
|
||||||
|
$event.stopPropagation();
|
||||||
|
}
|
||||||
|
const cmd = NotificationSubscriber.createMarkAllAsReadCommand(this.notificationWsService);
|
||||||
|
cmd.subscribe();
|
||||||
}
|
}
|
||||||
const cmd = NotificationSubscriber.createMarkAllAsReadCommand(this.notificationWsService);
|
|
||||||
cmd.subscribe();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
viewAll($event: Event) {
|
viewAll($event: Event) {
|
||||||
if ($event) {
|
if (!this.ctx.isEdit && !this.ctx.isPreview) {
|
||||||
$event.stopPropagation();
|
if ($event) {
|
||||||
|
$event.stopPropagation();
|
||||||
|
}
|
||||||
|
this.router.navigateByUrl(this.router.parseUrl('/notification/inbox')).then(() => {});
|
||||||
}
|
}
|
||||||
this.router.navigateByUrl(this.router.parseUrl('/notification/inbox')).then(() => {});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
trackById(index: number, item: NotificationRequest): string {
|
trackById(index: number, item: NotificationRequest): string {
|
||||||
|
|||||||
@ -169,6 +169,6 @@ export class TimeSeriesChartWidgetComponent implements OnInit, OnDestroy, AfterV
|
|||||||
}
|
}
|
||||||
|
|
||||||
public toggleLegendKey(legendKey: LegendKey) {
|
public toggleLegendKey(legendKey: LegendKey) {
|
||||||
this.timeSeriesChart.toggleKey(legendKey.dataKey);
|
this.timeSeriesChart.toggleKey(legendKey.dataKey, legendKey.dataIndex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -56,7 +56,14 @@ import {
|
|||||||
measureAxisNameSize
|
measureAxisNameSize
|
||||||
} from '@home/components/widget/lib/chart/echarts-widget.models';
|
} from '@home/components/widget/lib/chart/echarts-widget.models';
|
||||||
import { DateFormatProcessor, ValueSourceType } from '@shared/models/widget-settings.models';
|
import { DateFormatProcessor, ValueSourceType } from '@shared/models/widget-settings.models';
|
||||||
import { formattedDataFormDatasourceData, formatValue, isDefinedAndNotNull, isEqual, mergeDeep } from '@core/utils';
|
import {
|
||||||
|
formattedDataFormDatasourceData,
|
||||||
|
formatValue,
|
||||||
|
isDefined,
|
||||||
|
isDefinedAndNotNull,
|
||||||
|
isEqual,
|
||||||
|
mergeDeep
|
||||||
|
} from '@core/utils';
|
||||||
import { DataKey, Datasource, DatasourceType, FormattedData, widgetType } from '@shared/models/widget.models';
|
import { DataKey, Datasource, DatasourceType, FormattedData, widgetType } from '@shared/models/widget.models';
|
||||||
import * as echarts from 'echarts/core';
|
import * as echarts from 'echarts/core';
|
||||||
import { CallbackDataParams, PiecewiseVisualMapOption } from 'echarts/types/dist/shared';
|
import { CallbackDataParams, PiecewiseVisualMapOption } from 'echarts/types/dist/shared';
|
||||||
@ -300,7 +307,7 @@ export class TbTimeSeriesChart {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public toggleKey(dataKey: DataKey): void {
|
public toggleKey(dataKey: DataKey, dataIndex?: number): void {
|
||||||
const enable = dataKey.hidden;
|
const enable = dataKey.hidden;
|
||||||
const dataItem = this.dataItems.find(d => d.dataKey === dataKey);
|
const dataItem = this.dataItems.find(d => d.dataKey === dataKey);
|
||||||
if (dataItem) {
|
if (dataItem) {
|
||||||
@ -320,6 +327,9 @@ export class TbTimeSeriesChart {
|
|||||||
this.timeSeriesChart.setOption(this.timeSeriesChartOptions, this.stackMode ? {notMerge: true} : {replaceMerge: mergeList});
|
this.timeSeriesChart.setOption(this.timeSeriesChartOptions, this.stackMode ? {notMerge: true} : {replaceMerge: mergeList});
|
||||||
this.updateAxes();
|
this.updateAxes();
|
||||||
dataKey.hidden = !enable;
|
dataKey.hidden = !enable;
|
||||||
|
if (isDefined(dataIndex)) {
|
||||||
|
this.ctx.defaultSubscription.updateDataVisibility(dataIndex);
|
||||||
|
}
|
||||||
if (enable) {
|
if (enable) {
|
||||||
this.timeSeriesChart.dispatchAction({
|
this.timeSeriesChart.dispatchAction({
|
||||||
type: 'highlight',
|
type: 'highlight',
|
||||||
|
|||||||
@ -79,7 +79,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<tb-chart-fill-settings
|
<tb-chart-fill-settings
|
||||||
formControlName="barBackgroundSettings"
|
formControlName="barBackgroundSettings"
|
||||||
title="widgets.chart.background"
|
titleText="widgets.chart.background"
|
||||||
fillNoneTitle="widgets.chart.fill-type-solid">
|
fillNoneTitle="widgets.chart.fill-type-solid">
|
||||||
</tb-chart-fill-settings>
|
</tb-chart-fill-settings>
|
||||||
<tb-time-series-no-aggregation-bar-width-settings
|
<tb-time-series-no-aggregation-bar-width-settings
|
||||||
|
|||||||
@ -77,7 +77,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<tb-chart-fill-settings
|
<tb-chart-fill-settings
|
||||||
formControlName="backgroundSettings"
|
formControlName="backgroundSettings"
|
||||||
title="widgets.chart.background"
|
titleText="widgets.chart.background"
|
||||||
fillNoneTitle="widgets.chart.fill-type-solid">
|
fillNoneTitle="widgets.chart.fill-type-solid">
|
||||||
</tb-chart-fill-settings>
|
</tb-chart-fill-settings>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
|||||||
@ -18,7 +18,7 @@
|
|||||||
<ng-container [formGroup]="fillSettingsFormGroup">
|
<ng-container [formGroup]="fillSettingsFormGroup">
|
||||||
<div class="tb-form-row column">
|
<div class="tb-form-row column">
|
||||||
<div class="tb-form-row no-border no-padding space-between">
|
<div class="tb-form-row no-border no-padding space-between">
|
||||||
<div>{{ title | translate }}</div>
|
<div>{{ titleText | translate }}</div>
|
||||||
<tb-toggle-select formControlName="type">
|
<tb-toggle-select formControlName="type">
|
||||||
<tb-toggle-option *ngFor="let type of chartFillTypes" [value]="type">{{ chartFillTypeTranslationMap.get(type) | translate }}</tb-toggle-option>
|
<tb-toggle-option *ngFor="let type of chartFillTypes" [value]="type">{{ chartFillTypeTranslationMap.get(type) | translate }}</tb-toggle-option>
|
||||||
</tb-toggle-select>
|
</tb-toggle-select>
|
||||||
|
|||||||
@ -55,7 +55,7 @@ export class ChartFillSettingsComponent implements OnInit, ControlValueAccessor
|
|||||||
disabled: boolean;
|
disabled: boolean;
|
||||||
|
|
||||||
@Input()
|
@Input()
|
||||||
title = 'widgets.chart.fill';
|
titleText = 'widgets.chart.fill';
|
||||||
|
|
||||||
@Input()
|
@Input()
|
||||||
fillNoneTitle = 'widgets.chart.fill-type-none';
|
fillNoneTitle = 'widgets.chart.fill-type-none';
|
||||||
|
|||||||
@ -487,6 +487,7 @@ export class WidgetComponent extends PageComponent implements OnInit, AfterViewI
|
|||||||
}
|
}
|
||||||
if (!this.widgetContext.inited && this.isReady()) {
|
if (!this.widgetContext.inited && this.isReady()) {
|
||||||
this.widgetContext.inited = true;
|
this.widgetContext.inited = true;
|
||||||
|
this.widgetContext.destroyed = false;
|
||||||
this.dashboardWidget.updateWidgetParams();
|
this.dashboardWidget.updateWidgetParams();
|
||||||
this.widgetContext.detectContainerChanges();
|
this.widgetContext.detectContainerChanges();
|
||||||
if (this.cafs.init) {
|
if (this.cafs.init) {
|
||||||
|
|||||||
@ -449,6 +449,8 @@ export class WidgetContext {
|
|||||||
labelPattern.destroy();
|
labelPattern.destroy();
|
||||||
}
|
}
|
||||||
this.labelPatterns.clear();
|
this.labelPatterns.clear();
|
||||||
|
this.width = undefined;
|
||||||
|
this.height = undefined;
|
||||||
this.destroyed = true;
|
this.destroyed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -25,11 +25,17 @@ import {
|
|||||||
SimpleChanges,
|
SimpleChanges,
|
||||||
ViewChild
|
ViewChild
|
||||||
} from '@angular/core';
|
} from '@angular/core';
|
||||||
import { ControlValueAccessor, UntypedFormBuilder, UntypedFormGroup, NG_VALUE_ACCESSOR, Validators } from '@angular/forms';
|
import {
|
||||||
|
ControlValueAccessor,
|
||||||
|
NG_VALIDATORS,
|
||||||
|
NG_VALUE_ACCESSOR,
|
||||||
|
UntypedFormBuilder,
|
||||||
|
UntypedFormGroup,
|
||||||
|
ValidationErrors,
|
||||||
|
Validators
|
||||||
|
} from '@angular/forms';
|
||||||
import { Observable } from 'rxjs';
|
import { Observable } from 'rxjs';
|
||||||
import { filter, map, mergeMap, share, tap } from 'rxjs/operators';
|
import { filter, map, mergeMap, share, tap } from 'rxjs/operators';
|
||||||
import { Store } from '@ngrx/store';
|
|
||||||
import { AppState } from '@app/core/core.state';
|
|
||||||
import { TranslateService } from '@ngx-translate/core';
|
import { TranslateService } from '@ngx-translate/core';
|
||||||
import { EntityType } from '@shared/models/entity-type.models';
|
import { EntityType } from '@shared/models/entity-type.models';
|
||||||
import { BaseData } from '@shared/models/base-data';
|
import { BaseData } from '@shared/models/base-data';
|
||||||
@ -49,6 +55,11 @@ import { SubscriptSizing } from '@angular/material/form-field';
|
|||||||
provide: NG_VALUE_ACCESSOR,
|
provide: NG_VALUE_ACCESSOR,
|
||||||
useExisting: forwardRef(() => EntityListComponent),
|
useExisting: forwardRef(() => EntityListComponent),
|
||||||
multi: true
|
multi: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
provide: NG_VALIDATORS,
|
||||||
|
useExisting: forwardRef(() => EntityListComponent),
|
||||||
|
multi: true
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
@ -56,7 +67,7 @@ export class EntityListComponent implements ControlValueAccessor, OnInit, AfterV
|
|||||||
|
|
||||||
entityListFormGroup: UntypedFormGroup;
|
entityListFormGroup: UntypedFormGroup;
|
||||||
|
|
||||||
modelValue: Array<string> | null;
|
private modelValue: Array<string> | null;
|
||||||
|
|
||||||
@Input()
|
@Input()
|
||||||
entityType: EntityType;
|
entityType: EntityType;
|
||||||
@ -108,17 +119,16 @@ export class EntityListComponent implements ControlValueAccessor, OnInit, AfterV
|
|||||||
|
|
||||||
private propagateChange = (v: any) => { };
|
private propagateChange = (v: any) => { };
|
||||||
|
|
||||||
constructor(private store: Store<AppState>,
|
constructor(public translate: TranslateService,
|
||||||
public translate: TranslateService,
|
|
||||||
private entityService: EntityService,
|
private entityService: EntityService,
|
||||||
private fb: UntypedFormBuilder) {
|
private fb: UntypedFormBuilder) {
|
||||||
this.entityListFormGroup = this.fb.group({
|
this.entityListFormGroup = this.fb.group({
|
||||||
entities: [this.entities, this.required ? [Validators.required] : []],
|
entities: [this.entities],
|
||||||
entity: [null]
|
entity: [null]
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
updateValidators() {
|
private updateValidators() {
|
||||||
this.entityListFormGroup.get('entities').setValidators(this.required ? [Validators.required] : []);
|
this.entityListFormGroup.get('entities').setValidators(this.required ? [Validators.required] : []);
|
||||||
this.entityListFormGroup.get('entities').updateValueAndValidity();
|
this.entityListFormGroup.get('entities').updateValueAndValidity();
|
||||||
}
|
}
|
||||||
@ -189,7 +199,13 @@ export class EntityListComponent implements ControlValueAccessor, OnInit, AfterV
|
|||||||
this.dirty = true;
|
this.dirty = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
reset() {
|
validate(): ValidationErrors | null {
|
||||||
|
return this.entityListFormGroup.valid ? null : {
|
||||||
|
entities: {valid: false}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private reset() {
|
||||||
this.entities = [];
|
this.entities = [];
|
||||||
this.entityListFormGroup.get('entities').setValue(this.entities);
|
this.entityListFormGroup.get('entities').setValue(this.entities);
|
||||||
this.modelValue = null;
|
this.modelValue = null;
|
||||||
@ -201,7 +217,7 @@ export class EntityListComponent implements ControlValueAccessor, OnInit, AfterV
|
|||||||
this.dirty = true;
|
this.dirty = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
add(entity: BaseData<EntityId>): void {
|
private add(entity: BaseData<EntityId>): void {
|
||||||
if (!this.modelValue || this.modelValue.indexOf(entity.id.id) === -1) {
|
if (!this.modelValue || this.modelValue.indexOf(entity.id.id) === -1) {
|
||||||
if (!this.modelValue) {
|
if (!this.modelValue) {
|
||||||
this.modelValue = [];
|
this.modelValue = [];
|
||||||
@ -214,7 +230,7 @@ export class EntityListComponent implements ControlValueAccessor, OnInit, AfterV
|
|||||||
this.clear();
|
this.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
remove(entity: BaseData<EntityId>) {
|
public remove(entity: BaseData<EntityId>) {
|
||||||
let index = this.entities.indexOf(entity);
|
let index = this.entities.indexOf(entity);
|
||||||
if (index >= 0) {
|
if (index >= 0) {
|
||||||
this.entities.splice(index, 1);
|
this.entities.splice(index, 1);
|
||||||
@ -229,11 +245,11 @@ export class EntityListComponent implements ControlValueAccessor, OnInit, AfterV
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
displayEntityFn(entity?: BaseData<EntityId>): string | undefined {
|
public displayEntityFn(entity?: BaseData<EntityId>): string | undefined {
|
||||||
return entity ? entity.name : undefined;
|
return entity ? entity.name : undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
fetchEntities(searchText?: string): Observable<Array<BaseData<EntityId>>> {
|
private fetchEntities(searchText?: string): Observable<Array<BaseData<EntityId>>> {
|
||||||
this.searchText = searchText;
|
this.searchText = searchText;
|
||||||
|
|
||||||
return this.entityService.getEntitiesByNameFilter(this.entityType, searchText,
|
return this.entityService.getEntitiesByNameFilter(this.entityType, searchText,
|
||||||
@ -241,14 +257,14 @@ export class EntityListComponent implements ControlValueAccessor, OnInit, AfterV
|
|||||||
map((data) => data ? data : []));
|
map((data) => data ? data : []));
|
||||||
}
|
}
|
||||||
|
|
||||||
onFocus() {
|
public onFocus() {
|
||||||
if (this.dirty) {
|
if (this.dirty) {
|
||||||
this.entityListFormGroup.get('entity').updateValueAndValidity({onlySelf: true, emitEvent: true});
|
this.entityListFormGroup.get('entity').updateValueAndValidity({onlySelf: true, emitEvent: true});
|
||||||
this.dirty = false;
|
this.dirty = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
clear(value: string = '') {
|
private clear(value: string = '') {
|
||||||
this.entityInput.nativeElement.value = value;
|
this.entityInput.nativeElement.value = value;
|
||||||
this.entityListFormGroup.get('entity').patchValue(value, {emitEvent: true});
|
this.entityListFormGroup.get('entity').patchValue(value, {emitEvent: true});
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
@ -257,8 +273,7 @@ export class EntityListComponent implements ControlValueAccessor, OnInit, AfterV
|
|||||||
}, 0);
|
}, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
textIsNotEmpty(text: string): boolean {
|
public textIsNotEmpty(text: string): boolean {
|
||||||
return (text && text.length > 0);
|
return (text && text.length > 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user