Merge branch 'rc' into features/add_tooltip_option_to_show_stack_mode_total_value_on_timeseries_chart_widgets

This commit is contained in:
Paolo Cristiani 2025-06-15 11:11:06 +02:00 committed by GitHub
commit 1129568dbb
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
14 changed files with 44 additions and 41 deletions

View File

@ -103,13 +103,13 @@ public class NetworkReceive implements Receive {
if (maxSize != UNLIMITED && receiveSize > maxSize) {
throw new ThingsboardKafkaClientError("Invalid receive (size = " + receiveSize + " larger than " + maxSize + ")");
}
requestedBufferSize = receiveSize; //may be 0 for some payloads (SASL)
requestedBufferSize = receiveSize; // may be 0 for some payloads (SASL)
if (receiveSize == 0) {
buffer = EMPTY_BUFFER;
}
}
}
if (buffer == null && requestedBufferSize != -1) { //we know the size we want but havent been able to allocate it yet
if (buffer == null && requestedBufferSize != -1) { // we know the size we want but haven't been able to allocate it yet
if (requestedBufferSize > TB_LOG_REQUESTED_BUFFER_SIZE) {
String stackTrace = Arrays.stream(Thread.currentThread().getStackTrace()).map(StackTraceElement::toString).collect(Collectors.joining("|"));
log.error("Allocating buffer of size {} for source {}", requestedBufferSize, source);

View File

@ -70,11 +70,12 @@ public class DefaultCalculatedFieldCache implements CalculatedFieldCache {
@AfterStartUp(order = AfterStartUp.CF_READ_CF_SERVICE)
public void init() {
//TODO: move to separate place to avoid circular references with the ActorSystemContext (@Lazy for tsSubService)
PageDataIterable<CalculatedField> cfs = new PageDataIterable<>(calculatedFieldService::findAllCalculatedFields, initFetchPackSize);
cfs.forEach(cf -> {
calculatedFields.putIfAbsent(cf.getId(), cf);
actorSystemContext.tell(new CalculatedFieldInitMsg(cf.getTenantId(), cf));
if (cf != null) {
calculatedFields.putIfAbsent(cf.getId(), cf);
actorSystemContext.tell(new CalculatedFieldInitMsg(cf.getTenantId(), cf));
}
});
calculatedFields.values().forEach(cf -> {
entityIdCalculatedFields.computeIfAbsent(cf.getEntityId(), id -> new CopyOnWriteArrayList<>()).add(cf);

View File

@ -16,6 +16,7 @@
package org.thingsboard.server.common.data.cf.configuration;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import org.thingsboard.server.common.data.cf.CalculatedFieldLink;
@ -36,6 +37,7 @@ import java.util.Map;
@JsonSubTypes.Type(value = SimpleCalculatedFieldConfiguration.class, name = "SIMPLE"),
@JsonSubTypes.Type(value = ScriptCalculatedFieldConfiguration.class, name = "SCRIPT")
})
@JsonIgnoreProperties(ignoreUnknown = true)
public interface CalculatedFieldConfiguration {
@JsonIgnore

View File

@ -79,7 +79,6 @@ public class DefaultNativeCalculatedFieldRepository implements NativeCalculatedF
JsonNode configuration = JacksonUtil.toJsonNode((String) row.get("configuration"));
long version = row.get("version") != null ? (long) row.get("version") : 0;
String debugSettings = (String) row.get("debug_settings");
Object externalIdObj = row.get("external_id");
CalculatedField calculatedField = new CalculatedField();
calculatedField.setId(new CalculatedFieldId(id));
@ -89,7 +88,12 @@ public class DefaultNativeCalculatedFieldRepository implements NativeCalculatedF
calculatedField.setType(type);
calculatedField.setName(name);
calculatedField.setConfigurationVersion(configurationVersion);
calculatedField.setConfiguration(JacksonUtil.treeToValue(configuration, CalculatedFieldConfiguration.class));
try {
calculatedField.setConfiguration(JacksonUtil.treeToValue(configuration, CalculatedFieldConfiguration.class));
} catch (Exception e) {
log.error("Invalid configuration for CalculatedField [{}]. Skipping.", id, e);
return null;
}
calculatedField.setVersion(version);
calculatedField.setDebugSettings(JacksonUtil.fromString(debugSettings, DebugSettings.class));
@ -118,7 +122,6 @@ public class DefaultNativeCalculatedFieldRepository implements NativeCalculatedF
EntityType entityType = EntityType.valueOf((String) row.get("entity_type"));
UUID entityId = (UUID) row.get("entity_id");
UUID calculatedFieldId = (UUID) row.get("calculated_field_id");
JsonNode configuration = JacksonUtil.toJsonNode((String) row.get("configuration"));
CalculatedFieldLink calculatedFieldLink = new CalculatedFieldLink();
calculatedFieldLink.setId(new CalculatedFieldLinkId(id));

22
pom.xml
View File

@ -42,19 +42,19 @@
<jakarta.xml.bind-api.version>4.0.2</jakarta.xml.bind-api.version>
<javax.xml.bind-api.version>2.4.0-b180830.0359</javax.xml.bind-api.version>
<jaxb-runtime.version>4.0.5</jaxb-runtime.version>
<tomcat.version>10.1.40</tomcat.version> <!-- Vulnerability fix, Remove after update spring-boot to new version-->
<tomcat.version>10.1.42</tomcat.version> <!-- Vulnerability fix, Remove after update spring-boot to new version-->
<net.minidev.json-smart>2.5.2</net.minidev.json-smart> <!-- Vulnerability fix, CVE-2024-57699, Remove after update spring-boot 3.2.12 to a newer version-->
<spring-boot.version>3.2.12</spring-boot.version>
<spring-data.version>3.2.12</spring-data.version>
<spring-data-redis.version>3.2.12</spring-data-redis.version>
<spring.version>6.1.15</spring.version>
<spring.version>6.1.21</spring.version>
<spring-redis.version>6.2.11</spring-redis.version>
<spring-security.version>6.3.8</spring-security.version>
<spring-security.version>6.3.9</spring-security.version>
<jedis.version>5.1.5</jedis.version>
<jjwt.version>0.12.5</jjwt.version>
<slf4j.version>2.0.13</slf4j.version>
<log4j.version>2.23.1</log4j.version>
<logback.version>1.5.5</logback.version>
<slf4j.version>2.0.17</slf4j.version>
<log4j.version>2.24.3</log4j.version>
<logback.version>1.5.18</logback.version>
<rat.version>0.10</rat.version> <!-- unused -->
<cassandra.version>4.17.0</cassandra.version>
<metrics.version>4.2.25</metrics.version>
@ -83,7 +83,7 @@
<freemarker.version>2.3.32</freemarker.version>
<mail.version>2.0.1</mail.version>
<curator.version>5.6.0</curator.version>
<zookeeper.version>3.9.2</zookeeper.version>
<zookeeper.version>3.9.3</zookeeper.version>
<protobuf.version>3.25.5</protobuf.version> <!-- A Major v4 does not support by the pubsub yet-->
<grpc.version>1.63.0</grpc.version>
<tbel.version>1.2.6</tbel.version>
@ -103,7 +103,7 @@
<jts.version>1.19.0</jts.version>
<bouncycastle.version>1.78.1</bouncycastle.version>
<winsw.version>2.0.1</winsw.version>
<postgresql.driver.version>42.7.5</postgresql.driver.version>
<postgresql.driver.version>42.7.7</postgresql.driver.version>
<sonar.exclusions>org/thingsboard/server/gen/**/*,
org/thingsboard/server/extensions/core/plugin/telemetry/gen/**/*
</sonar.exclusions>
@ -113,7 +113,7 @@
<!-- IMPORTANT: If you change the version of the kafka client, make sure to synchronize our overwritten implementation of the
org.apache.kafka.common.network.NetworkReceive class in the application module. It addresses the issue https://issues.apache.org/jira/browse/KAFKA-4090.
Here is the source to track https://github.com/apache/kafka/tree/trunk/clients/src/main/java/org/apache/kafka/common/network -->
<kafka.version>3.7.2</kafka.version>
<kafka.version>3.9.1</kafka.version>
<bucket4j.version>8.10.1</bucket4j.version>
<antlr.version>3.5.3</antlr.version>
<snakeyaml.version>2.2</snakeyaml.version>
@ -158,7 +158,7 @@
<allure-maven.version>2.12.0</allure-maven.version>
<opensmpp.version>3.0.2</opensmpp.version>
<jgit.version>6.9.0.202403050737-r</jgit.version>
<jgit.version>6.10.1.202505221210-r</jgit.version>
<exp4j.version>0.4.8</exp4j.version>
<aerogear-otp.version>1.0.0</aerogear-otp.version>
@ -1178,7 +1178,7 @@
<!-- ...Vulnerability fix - transitive dependency from Spring Boot, remove after Spring Boot upgrade -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<artifactId>spring-boot-starter</artifactId>
<version>${spring-boot.version}</version>
</dependency>
<dependency>

View File

@ -30,7 +30,7 @@ import {
getTimewindowConfig,
setTimewindowConfig
} from '@home/components/widget/config/timewindow-config-panel.component';
import { formatValue, isUndefined } from '@core/utils';
import { formatValue, isDefined, isUndefined } from '@core/utils';
import { Component } from '@angular/core';
import {
convertLevelColorsSettingsToColorProcessor,
@ -115,7 +115,7 @@ export class DigitalSimpleGaugeBasicConfigComponent extends BasicWidgetConfigCom
minMaxColor: [settings.minMaxFont?.color, []],
showValue: [settings.showValue, []],
decimals: [configData.config.decimals, []],
decimals: [isDefined(configData.config.decimals) ? configData.config.decimals : settings.decimals, []],
units: [configData.config.units, []],
valueFont: [settings.valueFont, []],
valueColor: [settings.valueFont?.color, []],
@ -157,6 +157,9 @@ export class DigitalSimpleGaugeBasicConfigComponent extends BasicWidgetConfigCom
this.widgetConfig.config.settings.showValue = config.showValue;
this.widgetConfig.config.units = config.units;
this.widgetConfig.config.decimals = config.decimals;
if (isDefined(this.widgetConfig.config.settings.decimals)) {
delete this.widgetConfig.config.settings.decimals;
}
this.widgetConfig.config.settings.valueFont = config.valueFont;
this.widgetConfig.config.settings.valueFont.color = config.valueColor;

View File

@ -57,6 +57,7 @@ export class KnobComponent extends BasicActionWidgetComponent implements OnInit,
maxValue: number;
newValue = 0;
private decimals: number;
private startDeg = -1;
private currentDeg = 0;
private rotation = 0;
@ -143,9 +144,10 @@ export class KnobComponent extends BasicActionWidgetComponent implements OnInit,
actionLabel: this.ctx.translate.instant('widgets.slider.on-value-change')};
this.valueSetter = this.createValueSetter(valueChangeSettings);
this.decimals = isDefined(this.ctx.decimals) ? this.ctx.decimals : 0;
this.valueFormat = ValueFormatProcessor.fromSettings(this.ctx.$injector, {
units: this.ctx.units,
decimals: this.ctx.decimals,
decimals: this.decimals,
showZeroDecimals: true
});
@ -299,7 +301,7 @@ export class KnobComponent extends BasicActionWidgetComponent implements OnInit,
}
private turn(ratio: number) {
this.newValue = Number((this.minValue + (this.maxValue - this.minValue) * ratio).toFixed(this.ctx.decimals));
this.newValue = Number((this.minValue + (this.maxValue - this.minValue) * ratio).toFixed(this.decimals));
if (this.canvasBar.value !== this.newValue) {
this.canvasBar.value = this.newValue;
}

View File

@ -57,7 +57,7 @@ export class KnobControlWidgetSettingsComponent extends WidgetSettingsComponent
protected prepareInputSettings(settings: WidgetSettings): WidgetSettings {
const knobSettings = prepareKnobSettings(deepClone(settings) as any) as WidgetSettings;
knobSettings.valueDecimals = this.widgetConfig?.config?.decimals ?? 2;
knobSettings.valueDecimals = this.widgetConfig?.config?.decimals;
knobSettings.valueUnits = deepClone(this.widgetConfig?.config?.units);
return super.prepareInputSettings(knobSettings);
}

View File

@ -37,7 +37,7 @@ import {
digitalGaugeLayoutTranslations,
DigitalGaugeType
} from '@home/components/widget/lib/digital-gauge.models';
import { formatValue } from '@core/utils';
import { formatValue, isDefined } from '@core/utils';
import {
ColorSettings,
ColorType,
@ -247,6 +247,10 @@ export class DigitalGaugeWidgetSettingsComponent extends WidgetSettingsComponent
settings.titleFont.color = this.digitalGaugeWidgetSettingsForm.get('titleColor').value;
settings.labelFont.color = this.digitalGaugeWidgetSettingsForm.get('labelColor').value;
if (isDefined(settings.decimals)) {
delete settings.decimals;
}
return settings;
}

View File

@ -160,7 +160,7 @@ export const ZIP_TYPE: FileType = {
};
export const CSV_TYPE: FileType = {
mimeType: 'attachament/csv',
mimeType: 'text/csv',
extension: 'csv'
};

View File

@ -431,7 +431,7 @@ export const initModelFromDefaultTimewindow = (value: Timewindow, quickIntervalO
if (isDefined(value.history.quickInterval)) {
model.history.quickInterval = value.history.quickInterval;
}
if (isDefined(value.history.fixedTimewindow)) {
if (isDefinedAndNotNull(value.history.fixedTimewindow)) {
if (isDefined(value.history.fixedTimewindow.startTimeMs)) {
model.history.fixedTimewindow.startTimeMs = value.history.fixedTimewindow.startTimeMs;
}

View File

@ -45,7 +45,7 @@ export const knobWidgetDefaultSettings: KnobSettings = {
defaultValue: 50,
executeRpc: {
method: 'getValue',
requestTimeout: 500,
requestTimeout: 5000,
requestPersistent: false,
persistentPollingInterval: 5000
},
@ -70,7 +70,7 @@ export const knobWidgetDefaultSettings: KnobSettings = {
action: SetValueAction.EXECUTE_RPC,
executeRpc: {
method: 'setValue',
requestTimeout: 500,
requestTimeout: 5000,
requestPersistent: false,
persistentPollingInterval: 5000
},

View File

@ -91,11 +91,5 @@ return [];
{:copy-code}
```
<br>
You can see real life example, how to use this node in this tutorial:
- [Data function based on telemetry from 2 devices{:target="_blank"}](${siteBaseUrl}/docs${docPlatformPrefix}/user-guide/rule-engine-2-0/tutorials/function-based-on-telemetry-from-two-devices#delta-temperature-rule-chain)
<br>
<br>

View File

@ -91,11 +91,5 @@ return [];
{:copy-code}
```
<br>
You can see real life example, how to use this node in this tutorial:
- [Data function based on telemetry from 2 devices{:target="_blank"}](${siteBaseUrl}/docs${docPlatformPrefix}/user-guide/rule-engine-2-0/tutorials/function-based-on-telemetry-from-two-devices#delta-temperature-rule-chain)
<br>
<br>