Browse Source

Merge remote-tracking branch 'origin/lts-4.2' into lts-4.3

pull/15439/head
Viacheslav Klimov 3 months ago
parent
commit
f42be47267
Failed to extract signature
  1. 2
      .gitignore
  2. 9
      application/src/test/java/org/thingsboard/server/transport/lwm2m/client/FwLwM2MDevice.java
  3. 7
      application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationReadCollectedValueTest.java
  4. 1
      dao/pom.xml
  5. 1
      netty-mqtt/pom.xml
  6. 4
      pom.xml
  7. 3
      ui-ngx/src/app/modules/home/components/attribute/attribute-table.component.html
  8. 6
      ui-ngx/src/app/modules/home/components/attribute/attribute-table.component.ts
  9. 14
      ui-ngx/src/app/modules/home/pages/notification/inbox/inbox-table-config.resolver.ts
  10. 4
      ui-ngx/src/app/shared/components/notification/notification.component.html
  11. 13
      ui-ngx/src/app/shared/components/notification/notification.component.ts

2
.gitignore

@ -37,4 +37,4 @@ rebuild-docker.sh
*/.run/**
.run/**
.run
.claude/
.claude

9
application/src/test/java/org/thingsboard/server/transport/lwm2m/client/FwLwM2MDevice.java

@ -171,7 +171,14 @@ public class FwLwM2MDevice extends BaseInstanceEnabler implements Destroyable {
if (this.leshanClient != null) {
log.info("Stop/reboot LwM2M client {}", this.leshanClient.getEndpoint(identity));
this.leshanClient.stop(false);
try {
this.leshanClient.stop(false);
} catch (Exception stopEx) {
// Leshan may throw NPE during CoAP observe-relation cleanup when the server
// reference is null (race condition in NotificationDataStore.toKey()).
// The client is still considered stopped at this point — proceed with restart.
log.warn("Exception during LwM2M client stop, proceeding with restart: {}", stopEx.getMessage());
}
log.info("Start after update fw LwM2M client {}", this.leshanClient.getEndpoint(identity));
this.leshanClient.start();

7
application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationReadCollectedValueTest.java

@ -21,6 +21,7 @@ import com.fasterxml.jackson.databind.node.ObjectNode;
import lombok.extern.slf4j.Slf4j;
import org.junit.Before;
import org.junit.Test;
import org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper;
import org.thingsboard.server.transport.lwm2m.rpc.AbstractRpcLwM2MIntegrationTest;
import java.util.concurrent.atomic.AtomicReference;
import static java.util.concurrent.TimeUnit.SECONDS;
@ -37,6 +38,12 @@ import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.RESOURCE_ID
@Slf4j
public class RpcLwm2mIntegrationReadCollectedValueTest extends AbstractRpcLwM2MIntegrationTest {
@Before
public void resetCollectedValueTimestamps() {
Lwm2mTestHelper.RESOURCE_ID_3303_12_5700_TS_0 = 0;
Lwm2mTestHelper.RESOURCE_ID_3303_12_5700_TS_1 = 0;
}
/**
* Read {"id":"/3303/12/5700"}
* Trigger a Send operation from the client with multiple values for the same resource as a payload

1
dao/pom.xml

@ -280,7 +280,6 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>${jar-plugin.version}</version>
<executions>
<execution>
<goals>

1
netty-mqtt/pom.xml

@ -125,7 +125,6 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.1.1</version>
<configuration>
<archive>
<manifest>

4
pom.xml

@ -72,7 +72,7 @@
<paho.mqttv5.client.version>1.2.5</paho.mqttv5.client.version>
<os-maven-plugin.version>1.7.1</os-maven-plugin.version>
<surefire.version>3.5.4</surefire.version>
<jar-plugin.version>3.4.0</jar-plugin.version>
<jar-plugin.version>3.5.0</jar-plugin.version>
<springdoc-swagger.version>2.8.8TB</springdoc-swagger.version>
<swagger-annotations.version>2.2.30</swagger-annotations.version>
<spatial4j.version>0.8</spatial4j.version>
@ -635,7 +635,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.1.1</version>
<version>${jar-plugin.version}</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>

3
ui-ngx/src/app/modules/home/components/attribute/attribute-table.component.html

@ -93,7 +93,8 @@
(click)="deleteTelemetry($event)">
<mat-icon>delete</mat-icon>
</button>
<button mat-raised-button color="accent"
<button [class.!hidden]="isSysAdmin"
mat-raised-button color="accent"
class="button-widget-action"
[disabled]="isLoading$ | async"
matTooltip="{{ 'attribute.show-on-widget' | translate }}"

6
ui-ngx/src/app/modules/home/components/attribute/attribute-table.component.ts

@ -56,6 +56,8 @@ import {
import { AttributeDatasource } from '@home/models/datasource/attribute-datasource';
import { AttributeService } from '@app/core/http/attribute.service';
import { EntityType } from '@shared/models/entity-type.models';
import { Authority } from '@shared/models/authority.enum';
import { getCurrentAuthUser } from '@core/auth/auth.selectors';
import { coerceBooleanProperty } from '@angular/cdk/coercion';
import {
AddAttributeDialogComponent,
@ -91,7 +93,6 @@ import { FormBuilder } from '@angular/forms';
import { AggregationType, defaultTimewindow } from '@shared/models/time/time.models';
import { TimeService } from '@core/services/time.service';
@Component({
selector: 'tb-attribute-table',
templateUrl: './attribute-table.component.html',
@ -186,6 +187,8 @@ export class AttributeTableComponent extends PageComponent implements AfterViewI
textSearch = this.fb.control('', {nonNullable: true});
isSysAdmin = false;
private destroy$ = new Subject<void>();
constructor(protected store: Store<AppState>,
@ -206,6 +209,7 @@ export class AttributeTableComponent extends PageComponent implements AfterViewI
private fb: FormBuilder,
private timeService: TimeService) {
super(store);
this.isSysAdmin = getCurrentAuthUser(this.store).authority === Authority.SYS_ADMIN;
this.dirtyValue = !this.activeValue;
const sortOrder: SortOrder = { property: 'key', direction: Direction.ASC };
this.pageLink = new PageLink(10, 0, null, sortOrder);

14
ui-ngx/src/app/modules/home/pages/notification/inbox/inbox-table-config.resolver.ts

@ -37,9 +37,10 @@ import {
InboxNotificationDialogComponent,
InboxNotificationDialogData
} from '@home/pages/notification/inbox/inbox-notification-dialog.component';
import { Injectable } from '@angular/core';
import { Injectable, SecurityContext } from '@angular/core';
import { ActivatedRouteSnapshot } from '@angular/router';
import { UtilsService } from '@core/services/utils.service';
import { DomSanitizer } from '@angular/platform-browser';
@Injectable()
export class InboxTableConfigResolver {
@ -50,7 +51,8 @@ export class InboxTableConfigResolver {
private translate: TranslateService,
private dialog: MatDialog,
private datePipe: DatePipe,
private utilsService: UtilsService) {
private utilsService: UtilsService,
private sanitizer: DomSanitizer) {
this.config.entityType = EntityType.NOTIFICATION;
this.config.detailsPanelEnabled = false;
@ -95,14 +97,14 @@ export class InboxTableConfigResolver {
new EntityTableColumn<Notification>('type', 'notification.type', '10%', (notification) =>
this.translate.instant(NotificationTemplateTypeTranslateMap.get(notification.type).name)),
new EntityTableColumn<Notification>('subject', 'notification.subject', '30%',
(entity) => this.utilsService.customTranslation(entity.subject, entity.subject)),
(entity) => this.sanitizer.sanitize(SecurityContext.HTML, this.utilsService.customTranslation(entity.subject, entity.subject))),
new EntityTableColumn<Notification>('text', 'notification.message', '60%',
(entity) => this.utilsService.customTranslation(entity.text, entity.text))
(entity) => this.sanitizer.sanitize(SecurityContext.HTML, this.utilsService.customTranslation(entity.text, entity.text)))
);
}
resolve(route: ActivatedRouteSnapshot): EntityTableConfig<Notification> {
resolve(_route: ActivatedRouteSnapshot): EntityTableConfig<Notification> {
return this.config;
}
@ -128,7 +130,7 @@ export class InboxTableConfigResolver {
});
}
private markAsRead($event, entity){
private markAsRead($event: Event, entity){
if ($event) {
$event.stopPropagation();
}

4
ui-ngx/src/app/shared/components/notification/notification.component.html

@ -28,8 +28,8 @@
</tb-icon>
</ng-template>
<div class="content flex-1">
<div class="title" [innerHTML]="(title | safe: 'html' )"></div>
<div class="message" [innerHTML]="(message | safe: 'html' )"></div>
<div class="title" [innerHTML]="title"></div>
<div class="message" [innerHTML]="message"></div>
<button *ngIf="showButton" mat-stroked-button class="button" color="primary"
(click)="navigate($event)">
{{ buttonLabel }}

13
ui-ngx/src/app/shared/components/notification/notification.component.ts

@ -14,7 +14,7 @@
/// limitations under the License.
///
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
import { Component, EventEmitter, Input, OnInit, Output, SecurityContext } from '@angular/core';
import {
ActionButtonLinkType,
Notification,
@ -33,6 +33,7 @@ import tinycolor from 'tinycolor2';
import { StateObject } from '@core/api/widget-api.models';
import { objToBase64URI } from '@core/utils';
import { coerceBoolean } from '@shared/decorators/coercion';
import { DomSanitizer } from '@angular/platform-browser';
@Component({
selector: 'tb-notification',
@ -71,7 +72,8 @@ export class NotificationComponent implements OnInit {
constructor(
private utils: UtilsService,
private router: Router
private router: Router,
private sanitizer: DomSanitizer
) {
}
@ -79,11 +81,10 @@ export class NotificationComponent implements OnInit {
this.showIcon = this.notification.additionalConfig?.icon?.enabled;
this.showButton = this.notification.additionalConfig?.actionButtonConfig?.enabled;
this.hideMarkAsReadButton = this.notification.status === NotificationStatus.READ;
this.title = this.utils.customTranslation(this.notification.subject, this.notification.subject);
this.message = this.utils.customTranslation(this.notification.text, this.notification.text);
this.title = this.sanitizer.sanitize(SecurityContext.HTML, this.utils.customTranslation(this.notification.subject));
this.message = this.sanitizer.sanitize(SecurityContext.HTML, this.utils.customTranslation(this.notification.text));
if (this.showButton) {
this.buttonLabel = this.utils.customTranslation(this.notification.additionalConfig.actionButtonConfig.text,
this.notification.additionalConfig.actionButtonConfig.text);
this.buttonLabel = this.utils.customTranslation(this.notification.additionalConfig.actionButtonConfig.text);
}
}

Loading…
Cancel
Save