From 3d3a8ffc057d98820f0b612265fb8ca5223bed13 Mon Sep 17 00:00:00 2001 From: mpetrov Date: Mon, 3 Mar 2025 15:55:39 +0200 Subject: [PATCH 1/8] Added debug settings service --- .../calculated-fields-table-config.ts | 61 ++++++----------- .../calculated-fields-table.component.ts | 11 ++- ...ntity-debug-settings-button.component.html | 2 +- .../entity-debug-settings-button.component.ts | 46 +++++-------- .../debug/entity-debug-settings.service.ts | 68 +++++++++++++++++++ .../home/components/home-components.module.ts | 4 +- ui-ngx/src/app/shared/models/entity.models.ts | 11 +++ ui-ngx/src/app/shared/shared.module.ts | 2 + 8 files changed, 123 insertions(+), 82 deletions(-) create mode 100644 ui-ngx/src/app/modules/home/components/entity/debug/entity-debug-settings.service.ts diff --git a/ui-ngx/src/app/modules/home/components/calculated-fields/calculated-fields-table-config.ts b/ui-ngx/src/app/modules/home/components/calculated-fields/calculated-fields-table-config.ts index 6932860be4..9cb04ee04a 100644 --- a/ui-ngx/src/app/modules/home/components/calculated-fields/calculated-fields-table-config.ts +++ b/ui-ngx/src/app/modules/home/components/calculated-fields/calculated-fields-table-config.ts @@ -29,10 +29,7 @@ import { AppState } from '@core/core.state'; import { getCurrentAuthState, getCurrentAuthUser } from '@core/auth/auth.selectors'; import { DestroyRef, Renderer2 } from '@angular/core'; import { EntityDebugSettings } from '@shared/models/entity.models'; -import { DurationLeftPipe } from '@shared/pipe/duration-left.pipe'; import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; -import { TbPopoverService } from '@shared/components/popover.service'; -import { EntityDebugSettingsPanelComponent } from '@home/components/entity/debug/entity-debug-settings-panel.component'; import { CalculatedFieldsService } from '@core/http/calculated-fields.service'; import { catchError, filter, switchMap, tap } from 'rxjs/operators'; import { @@ -53,6 +50,7 @@ import { } from './components/public-api'; import { ImportExportService } from '@shared/import-export/import-export.service'; import { isObject } from '@core/utils'; +import { EntityDebugSettingsService } from '@home/components/entity/debug/entity-debug-settings.service'; export class CalculatedFieldsTableConfig extends EntityTableConfig { @@ -71,12 +69,11 @@ export class CalculatedFieldsTableConfig extends EntityTableConfig, - private durationLeft: DurationLeftPipe, - private popoverService: TbPopoverService, private destroyRef: DestroyRef, private renderer: Renderer2, public entityName: string, - private importExportService: ImportExportService + private importExportService: ImportExportService, + private entityDebugSettingsService: EntityDebugSettingsService, ) { super(); this.tableTitle = this.translate.instant('entity.type-calculated-fields'); @@ -131,10 +128,10 @@ export class CalculatedFieldsTableConfig extends EntityTableConfig this.getDebugConfigLabel(entity?.debugSettings), + nameFunction: entity => this.entityDebugSettingsService.getDebugConfigLabel(entity?.debugSettings), icon: 'mdi:bug', isEnabled: () => true, - iconFunction: ({ debugSettings }) => this.isDebugActive(debugSettings?.allEnabledUntil) || debugSettings?.failuresEnabled ? 'mdi:bug' : 'mdi:bug-outline', + iconFunction: ({ debugSettings }) => this.entityDebugSettingsService.isDebugActive(debugSettings?.allEnabledUntil) || debugSettings?.failuresEnabled ? 'mdi:bug' : 'mdi:bug-outline', onAction: ($event, entity) => this.onOpenDebugConfig($event, entity), }, { @@ -160,26 +157,20 @@ export class CalculatedFieldsTableConfig extends EntityTableConfig { - this.onDebugConfigChanged(id.id, settings); - debugStrategyPopover.hide(); - }); - } + + this.entityDebugSettingsService.viewContainerRef = viewContainerRef; + this.entityDebugSettingsService.renderer = this.renderer; + + this.entityDebugSettingsService.openDebugStrategyPanel({ + debugSettings, + debugConfig: { + debugLimitsConfiguration: this.calculatedFieldsDebugPerTenantLimitsConfiguration, + maxDebugModeDuration: this.maxDebugModeDuration, + entityLabel: this.translate.instant('debug-settings.calculated-field'), + additionalActionConfig, + }, + onSettingsAppliedFn: settings => this.onDebugConfigChanged(id.id, settings) + }, $event.target as Element); } private editCalculatedField(calculatedField: CalculatedField, isDirty = false): void { @@ -239,20 +230,6 @@ export class CalculatedFieldsTableConfig extends EntityTableConfig this.updateData()); } - private getDebugConfigLabel(debugSettings: EntityDebugSettings): string { - const isDebugActive = this.isDebugActive(debugSettings?.allEnabledUntil); - - if (!isDebugActive) { - return debugSettings?.failuresEnabled ? this.translate.instant('debug-settings.failures') : this.translate.instant('common.disabled'); - } else { - return this.durationLeft.transform(debugSettings?.allEnabledUntil); - } - } - - private isDebugActive(allEnabledUntil: number): boolean { - return allEnabledUntil > new Date().getTime(); - } - private onDebugConfigChanged(id: string, debugSettings: EntityDebugSettings): void { this.calculatedFieldsService.getCalculatedFieldById(id).pipe( switchMap(field => this.calculatedFieldsService.saveCalculatedField({ ...field, debugSettings })), diff --git a/ui-ngx/src/app/modules/home/components/calculated-fields/calculated-fields-table.component.ts b/ui-ngx/src/app/modules/home/components/calculated-fields/calculated-fields-table.component.ts index be6fb11480..82d96b9557 100644 --- a/ui-ngx/src/app/modules/home/components/calculated-fields/calculated-fields-table.component.ts +++ b/ui-ngx/src/app/modules/home/components/calculated-fields/calculated-fields-table.component.ts @@ -31,10 +31,9 @@ import { MatDialog } from '@angular/material/dialog'; import { Store } from '@ngrx/store'; import { AppState } from '@core/core.state'; import { CalculatedFieldsTableConfig } from '@home/components/calculated-fields/calculated-fields-table-config'; -import { DurationLeftPipe } from '@shared/pipe/duration-left.pipe'; -import { TbPopoverService } from '@shared/components/popover.service'; import { CalculatedFieldsService } from '@core/http/calculated-fields.service'; import { ImportExportService } from '@shared/import-export/import-export.service'; +import { EntityDebugSettingsService } from '@home/components/entity/debug/entity-debug-settings.service'; @Component({ selector: 'tb-calculated-fields-table', @@ -56,11 +55,10 @@ export class CalculatedFieldsTableComponent { private translate: TranslateService, private dialog: MatDialog, private store: Store, - private durationLeft: DurationLeftPipe, - private popoverService: TbPopoverService, private cd: ChangeDetectorRef, private renderer: Renderer2, private importExportService: ImportExportService, + private entityDebugSettingsService: EntityDebugSettingsService, private destroyRef: DestroyRef) { effect(() => { @@ -71,12 +69,11 @@ export class CalculatedFieldsTableComponent { this.dialog, this.entityId(), this.store, - this.durationLeft, - this.popoverService, this.destroyRef, this.renderer, this.entityName(), - this.importExportService + this.importExportService, + this.entityDebugSettingsService, ); this.cd.markForCheck(); } diff --git a/ui-ngx/src/app/modules/home/components/entity/debug/entity-debug-settings-button.component.html b/ui-ngx/src/app/modules/home/components/entity/debug/entity-debug-settings-button.component.html index a6033df8cb..4243044fc8 100644 --- a/ui-ngx/src/app/modules/home/components/entity/debug/entity-debug-settings-button.component.html +++ b/ui-ngx/src/app/modules/home/components/entity/debug/entity-debug-settings-button.component.html @@ -21,7 +21,7 @@ #matButton [class.active]="((isDebugAllActive$ | async) || failuresEnabled) && !disabled" [disabled]="disabled" - (click)="openDebugStrategyPanel($event, matButton)"> + (click)="onOpenDebugStrategyPanel($event, matButton)"> bug_report @if (isDebugAllActive$ | async) { {{ (allEnabled$ | async) === false ? (allEnabledUntil | durationLeft) : (maxDebugModeDuration | milliSecondsToTimeString: true : true) }} diff --git a/ui-ngx/src/app/modules/home/components/entity/debug/entity-debug-settings-button.component.ts b/ui-ngx/src/app/modules/home/components/entity/debug/entity-debug-settings-button.component.ts index 852da5f7bf..99a08494fc 100644 --- a/ui-ngx/src/app/modules/home/components/entity/debug/entity-debug-settings-button.component.ts +++ b/ui-ngx/src/app/modules/home/components/entity/debug/entity-debug-settings-button.component.ts @@ -20,15 +20,11 @@ import { Component, forwardRef, Input, - Renderer2, - ViewContainerRef } from '@angular/core'; import { CommonModule } from '@angular/common'; import { SharedModule } from '@shared/shared.module'; import { DurationLeftPipe } from '@shared/pipe/duration-left.pipe'; -import { TbPopoverService } from '@shared/components/popover.service'; import { MatButton } from '@angular/material/button'; -import { EntityDebugSettingsPanelComponent } from './entity-debug-settings-panel.component'; import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { BehaviorSubject, of, shareReplay, timer } from 'rxjs'; import { SECOND, MINUTE } from '@shared/models/time/time.models'; @@ -38,6 +34,7 @@ import { getCurrentAuthState } from '@core/auth/auth.selectors'; import { AppState } from '@core/core.state'; import { Store } from '@ngrx/store'; import { ControlValueAccessor, FormBuilder, NG_VALUE_ACCESSOR } from '@angular/forms'; +import { EntityDebugSettingsService } from '@home/components/entity/debug/entity-debug-settings.service'; @Component({ selector: 'tb-entity-debug-settings-button', @@ -54,6 +51,7 @@ import { ControlValueAccessor, FormBuilder, NG_VALUE_ACCESSOR } from '@angular/f useExisting: forwardRef(() => EntityDebugSettingsButtonComponent), multi: true }, + EntityDebugSettingsService ], changeDetection: ChangeDetectionStrategy.OnPush }) @@ -92,11 +90,9 @@ export class EntityDebugSettingsButtonComponent implements ControlValueAccessor private propagateChange: (settings: EntityDebugSettings) => void = () => {}; - constructor(private popoverService: TbPopoverService, - private renderer: Renderer2, - private store: Store, - private viewContainerRef: ViewContainerRef, + constructor(private store: Store, private fb: FormBuilder, + private entityDebugSettingsService: EntityDebugSettingsService, private cd : ChangeDetectorRef, ) { this.debugSettingsFormGroup.valueChanges.pipe( @@ -118,33 +114,23 @@ export class EntityDebugSettingsButtonComponent implements ControlValueAccessor return this.debugSettingsFormGroup.get('allEnabledUntil').value; } - openDebugStrategyPanel($event: Event, matButton: MatButton): void { + onOpenDebugStrategyPanel($event: Event, matButton: MatButton): void { if ($event) { $event.stopPropagation(); } - const trigger = matButton._elementRef.nativeElement; - const debugSettings = this.debugSettingsFormGroup.value; - - if (this.popoverService.hasPopover(trigger)) { - this.popoverService.hidePopover(trigger); - } else { - const debugStrategyPopover = this.popoverService.displayPopover(trigger, this.renderer, - this.viewContainerRef, EntityDebugSettingsPanelComponent, 'bottom', true, null, - { - ...debugSettings, - maxDebugModeDuration: this.maxDebugModeDuration, - debugLimitsConfiguration: this.debugLimitsConfiguration, - entityLabel: this.entityLabel, - additionalActionConfig: this.additionalActionConfig, - }, - {}, - {}, {}, true); - debugStrategyPopover.tbComponentRef.instance.onSettingsApplied.subscribe((settings: EntityDebugSettings) => { + this.entityDebugSettingsService.openDebugStrategyPanel({ + debugSettings: this.debugSettingsFormGroup.value, + debugConfig: { + maxDebugModeDuration: this.maxDebugModeDuration, + debugLimitsConfiguration: this.debugLimitsConfiguration, + entityLabel: this.entityLabel, + additionalActionConfig: this.additionalActionConfig, + }, + onSettingsAppliedFn: settings => { this.debugSettingsFormGroup.patchValue(settings); this.cd.markForCheck(); - debugStrategyPopover.hide(); - }); - } + } + }, matButton._elementRef.nativeElement); } registerOnChange(fn: (settings: EntityDebugSettings) => void): void { diff --git a/ui-ngx/src/app/modules/home/components/entity/debug/entity-debug-settings.service.ts b/ui-ngx/src/app/modules/home/components/entity/debug/entity-debug-settings.service.ts new file mode 100644 index 0000000000..c53bc5b777 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/entity/debug/entity-debug-settings.service.ts @@ -0,0 +1,68 @@ +/// +/// Copyright © 2016-2025 The Thingsboard Authors +/// +/// Licensed under the Apache License, Version 2.0 (the "License"); +/// you may not use this file except in compliance with the License. +/// You may obtain a copy of the License at +/// +/// http://www.apache.org/licenses/LICENSE-2.0 +/// +/// Unless required by applicable law or agreed to in writing, software +/// distributed under the License is distributed on an "AS IS" BASIS, +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +/// See the License for the specific language governing permissions and +/// limitations under the License. +/// + +import { Injectable, Optional, Renderer2, ViewContainerRef } from '@angular/core'; +import { EntityDebugSettingsPanelComponent } from '@home/components/entity/debug/entity-debug-settings-panel.component'; +import { EntityDebugSettingPanelConfig, EntityDebugSettings } from '@shared/models/entity.models'; +import { TbPopoverService } from '@shared/components/popover.service'; +import { TranslateService } from '@ngx-translate/core'; +import { DurationLeftPipe } from '@shared/pipe/duration-left.pipe'; + +@Injectable() +export class EntityDebugSettingsService { + + constructor( + private popoverService: TbPopoverService, + @Optional() public renderer: Renderer2, + @Optional() public viewContainerRef: ViewContainerRef, + private translate: TranslateService, + private durationLeft: DurationLeftPipe, + ) {} + + openDebugStrategyPanel(panelConfig: EntityDebugSettingPanelConfig, trigger: Element): void { + if (this.popoverService.hasPopover(trigger)) { + this.popoverService.hidePopover(trigger); + } else { + const debugStrategyPopover = this.popoverService.displayPopover(trigger, this.renderer, + this.viewContainerRef, EntityDebugSettingsPanelComponent, 'bottom', true, null, + { + ...panelConfig.debugSettings, + ...panelConfig.debugConfig, + }, + {}, + {}, {}, true); + debugStrategyPopover.tbComponentRef.instance.onSettingsApplied.subscribe(settings => { + panelConfig.onSettingsAppliedFn(settings); + debugStrategyPopover.hide(); + }); + } + } + + + getDebugConfigLabel(debugSettings: EntityDebugSettings): string { + const isDebugActive = this.isDebugActive(debugSettings?.allEnabledUntil); + + if (!isDebugActive) { + return debugSettings?.failuresEnabled ? this.translate.instant('debug-settings.failures') : this.translate.instant('common.disabled'); + } else { + return this.durationLeft.transform(debugSettings?.allEnabledUntil); + } + } + + isDebugActive(allEnabledUntil: number): boolean { + return allEnabledUntil > new Date().getTime(); + } +} diff --git a/ui-ngx/src/app/modules/home/components/home-components.module.ts b/ui-ngx/src/app/modules/home/components/home-components.module.ts index e680232129..76998669fd 100644 --- a/ui-ngx/src/app/modules/home/components/home-components.module.ts +++ b/ui-ngx/src/app/modules/home/components/home-components.module.ts @@ -184,7 +184,6 @@ import { import { EntityChipsComponent } from '@home/components/entity/entity-chips.component'; import { DashboardViewComponent } from '@home/components/dashboard-view/dashboard-view.component'; import { CalculatedFieldsTableComponent } from '@home/components/calculated-fields/calculated-fields-table.component'; -import { DurationLeftPipe } from '@shared/pipe/duration-left.pipe'; import { CalculatedFieldDialogComponent } from '@home/components/calculated-fields/components/dialog/calculated-field-dialog.component'; import { EntityDebugSettingsButtonComponent @@ -204,6 +203,7 @@ import { import { CalculatedFieldTestArgumentsComponent } from '@home/components/calculated-fields/components/test-arguments/calculated-field-test-arguments.component'; +import { EntityDebugSettingsService } from '@home/components/entity/debug/entity-debug-settings.service'; @NgModule({ declarations: @@ -504,7 +504,7 @@ import { providers: [ WidgetComponentService, CustomDialogService, - DurationLeftPipe, + EntityDebugSettingsService, {provide: EMBED_DASHBOARD_DIALOG_TOKEN, useValue: EmbedDashboardDialogComponent}, {provide: COMPLEX_FILTER_PREDICATE_DIALOG_COMPONENT_TOKEN, useValue: ComplexFilterPredicateDialogComponent}, {provide: DASHBOARD_PAGE_COMPONENT_TOKEN, useValue: DashboardPageComponent}, diff --git a/ui-ngx/src/app/shared/models/entity.models.ts b/ui-ngx/src/app/shared/models/entity.models.ts index 6fe8cd040e..87536fdc54 100644 --- a/ui-ngx/src/app/shared/models/entity.models.ts +++ b/ui-ngx/src/app/shared/models/entity.models.ts @@ -203,6 +203,17 @@ export interface EntityDebugSettings { allEnabledUntil?: number; } +export interface EntityDebugSettingPanelConfig { + debugSettings: EntityDebugSettings; + debugConfig: { + maxDebugModeDuration: number; + debugLimitsConfiguration: string; + entityLabel?: string; + additionalActionConfig?: AdditionalDebugActionConfig; + } + onSettingsAppliedFn: (settings: EntityDebugSettings) => void; +} + export interface EntityTestScriptResult { output: string; error: string; diff --git a/ui-ngx/src/app/shared/shared.module.ts b/ui-ngx/src/app/shared/shared.module.ts index 7eb622029f..8eec19379e 100644 --- a/ui-ngx/src/app/shared/shared.module.ts +++ b/ui-ngx/src/app/shared/shared.module.ts @@ -225,6 +225,7 @@ import { GroupingIntervalOptionsComponent } from '@shared/components/time/aggreg import { JsFuncModulesComponent } from '@shared/components/js-func-modules.component'; import { JsFuncModuleRowComponent } from '@shared/components/js-func-module-row.component'; import { EntityKeyAutocompleteComponent } from '@shared/components/entity/entity-key-autocomplete.component'; +import { DurationLeftPipe } from '@shared/pipe/duration-left.pipe'; export function MarkedOptionsFactory(markedOptionsService: MarkedOptionsService) { return markedOptionsService; @@ -244,6 +245,7 @@ export function MarkedOptionsFactory(markedOptionsService: MarkedOptionsService) ShortNumberPipe, ImagePipe, CustomTranslatePipe, + DurationLeftPipe, { provide: FlowInjectionToken, useValue: Flow From 9d4be3a9b38eed204052eaa29c7617265e84f606 Mon Sep 17 00:00:00 2001 From: mpetrov Date: Mon, 3 Mar 2025 16:44:34 +0200 Subject: [PATCH 2/8] optimization --- .../calculated-fields/calculated-fields-table-config.ts | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/calculated-fields/calculated-fields-table-config.ts b/ui-ngx/src/app/modules/home/components/calculated-fields/calculated-fields-table-config.ts index 9cb04ee04a..ddf52642f0 100644 --- a/ui-ngx/src/app/modules/home/components/calculated-fields/calculated-fields-table-config.ts +++ b/ui-ngx/src/app/modules/home/components/calculated-fields/calculated-fields-table-config.ts @@ -153,13 +153,15 @@ export class CalculatedFieldsTableConfig extends EntityTableConfig this.openDebugEventsDialog(calculatedField) }; - const { viewContainerRef } = this.getTable(); if ($event) { $event.stopPropagation(); } - this.entityDebugSettingsService.viewContainerRef = viewContainerRef; - this.entityDebugSettingsService.renderer = this.renderer; + const { viewContainerRef, renderer } = this.entityDebugSettingsService; + if (!viewContainerRef || !renderer) { + this.entityDebugSettingsService.viewContainerRef = this.getTable().viewContainerRef; + this.entityDebugSettingsService.renderer = this.renderer; + } this.entityDebugSettingsService.openDebugStrategyPanel({ debugSettings, From c1a70dcbaa6c5e5cf4cad330e26024066f7d5f34 Mon Sep 17 00:00:00 2001 From: mpetrov Date: Mon, 3 Mar 2025 16:55:35 +0200 Subject: [PATCH 3/8] optimization --- .../calculated-fields/calculated-fields-table.component.ts | 1 + .../src/app/modules/home/components/home-components.module.ts | 2 -- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/calculated-fields/calculated-fields-table.component.ts b/ui-ngx/src/app/modules/home/components/calculated-fields/calculated-fields-table.component.ts index 82d96b9557..c1dd0bbd5a 100644 --- a/ui-ngx/src/app/modules/home/components/calculated-fields/calculated-fields-table.component.ts +++ b/ui-ngx/src/app/modules/home/components/calculated-fields/calculated-fields-table.component.ts @@ -40,6 +40,7 @@ import { EntityDebugSettingsService } from '@home/components/entity/debug/entity templateUrl: './calculated-fields-table.component.html', styleUrls: ['./calculated-fields-table.component.scss'], changeDetection: ChangeDetectionStrategy.OnPush, + providers: [EntityDebugSettingsService] }) export class CalculatedFieldsTableComponent { diff --git a/ui-ngx/src/app/modules/home/components/home-components.module.ts b/ui-ngx/src/app/modules/home/components/home-components.module.ts index 76998669fd..ac0296e2a5 100644 --- a/ui-ngx/src/app/modules/home/components/home-components.module.ts +++ b/ui-ngx/src/app/modules/home/components/home-components.module.ts @@ -203,7 +203,6 @@ import { import { CalculatedFieldTestArgumentsComponent } from '@home/components/calculated-fields/components/test-arguments/calculated-field-test-arguments.component'; -import { EntityDebugSettingsService } from '@home/components/entity/debug/entity-debug-settings.service'; @NgModule({ declarations: @@ -504,7 +503,6 @@ import { EntityDebugSettingsService } from '@home/components/entity/debug/entity providers: [ WidgetComponentService, CustomDialogService, - EntityDebugSettingsService, {provide: EMBED_DASHBOARD_DIALOG_TOKEN, useValue: EmbedDashboardDialogComponent}, {provide: COMPLEX_FILTER_PREDICATE_DIALOG_COMPONENT_TOKEN, useValue: ComplexFilterPredicateDialogComponent}, {provide: DASHBOARD_PAGE_COMPONENT_TOKEN, useValue: DashboardPageComponent}, From ca350601bb47853738d9280fb21bd12e821e08ed Mon Sep 17 00:00:00 2001 From: mpetrov Date: Fri, 7 Mar 2025 14:46:25 +0200 Subject: [PATCH 4/8] Resolved conflicts --- .../calculated-fields/calculated-fields-table.component.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/calculated-fields/calculated-fields-table.component.ts b/ui-ngx/src/app/modules/home/components/calculated-fields/calculated-fields-table.component.ts index 91a4d69252..e10c4b301e 100644 --- a/ui-ngx/src/app/modules/home/components/calculated-fields/calculated-fields-table.component.ts +++ b/ui-ngx/src/app/modules/home/components/calculated-fields/calculated-fields-table.component.ts @@ -58,8 +58,6 @@ export class CalculatedFieldsTableComponent { private dialog: MatDialog, private store: Store, private datePipe: DatePipe, - private durationLeft: DurationLeftPipe, - private popoverService: TbPopoverService, private cd: ChangeDetectorRef, private renderer: Renderer2, private importExportService: ImportExportService, From bdec59af0e9f91b3fd5217d63270041cba4c523b Mon Sep 17 00:00:00 2001 From: mpetrov Date: Tue, 11 Mar 2025 18:36:07 +0200 Subject: [PATCH 5/8] Resolved review comments --- .../entity-debug-settings-button.component.ts | 3 +- .../entity-debug-settings-panel.component.ts | 3 +- .../debug/entity-debug-settings.model.ts | 33 +++++++++++++++++++ .../debug/entity-debug-settings.service.ts | 3 +- .../shared/models/calculated-field.models.ts | 2 +- ui-ngx/src/app/shared/models/entity.models.ts | 16 --------- 6 files changed, 40 insertions(+), 20 deletions(-) create mode 100644 ui-ngx/src/app/modules/home/components/entity/debug/entity-debug-settings.model.ts diff --git a/ui-ngx/src/app/modules/home/components/entity/debug/entity-debug-settings-button.component.ts b/ui-ngx/src/app/modules/home/components/entity/debug/entity-debug-settings-button.component.ts index 99a08494fc..85a90aef63 100644 --- a/ui-ngx/src/app/modules/home/components/entity/debug/entity-debug-settings-button.component.ts +++ b/ui-ngx/src/app/modules/home/components/entity/debug/entity-debug-settings-button.component.ts @@ -28,13 +28,14 @@ import { MatButton } from '@angular/material/button'; import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { BehaviorSubject, of, shareReplay, timer } from 'rxjs'; import { SECOND, MINUTE } from '@shared/models/time/time.models'; -import { AdditionalDebugActionConfig, EntityDebugSettings } from '@shared/models/entity.models'; +import { EntityDebugSettings } from '@shared/models/entity.models'; import { map, switchMap, takeWhile } from 'rxjs/operators'; import { getCurrentAuthState } from '@core/auth/auth.selectors'; import { AppState } from '@core/core.state'; import { Store } from '@ngrx/store'; import { ControlValueAccessor, FormBuilder, NG_VALUE_ACCESSOR } from '@angular/forms'; import { EntityDebugSettingsService } from '@home/components/entity/debug/entity-debug-settings.service'; +import { AdditionalDebugActionConfig } from '@home/components/entity/debug/entity-debug-settings.model'; @Component({ selector: 'tb-entity-debug-settings-button', diff --git a/ui-ngx/src/app/modules/home/components/entity/debug/entity-debug-settings-panel.component.ts b/ui-ngx/src/app/modules/home/components/entity/debug/entity-debug-settings-panel.component.ts index 5fd3613296..1f95a93084 100644 --- a/ui-ngx/src/app/modules/home/components/entity/debug/entity-debug-settings-panel.component.ts +++ b/ui-ngx/src/app/modules/home/components/entity/debug/entity-debug-settings-panel.component.ts @@ -32,8 +32,9 @@ import { SECOND } from '@shared/models/time/time.models'; import { DurationLeftPipe } from '@shared/pipe/duration-left.pipe'; import { of, shareReplay, timer } from 'rxjs'; import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; -import { AdditionalDebugActionConfig, EntityDebugSettings } from '@shared/models/entity.models'; +import { EntityDebugSettings } from '@shared/models/entity.models'; import { distinctUntilChanged, map, startWith, switchMap, takeWhile } from 'rxjs/operators'; +import { AdditionalDebugActionConfig } from '@home/components/entity/debug/entity-debug-settings.model'; @Component({ selector: 'tb-entity-debug-settings-panel', diff --git a/ui-ngx/src/app/modules/home/components/entity/debug/entity-debug-settings.model.ts b/ui-ngx/src/app/modules/home/components/entity/debug/entity-debug-settings.model.ts new file mode 100644 index 0000000000..6560580502 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/entity/debug/entity-debug-settings.model.ts @@ -0,0 +1,33 @@ +/// +/// Copyright © 2016-2025 The Thingsboard Authors +/// +/// Licensed under the Apache License, Version 2.0 (the "License"); +/// you may not use this file except in compliance with the License. +/// You may obtain a copy of the License at +/// +/// http://www.apache.org/licenses/LICENSE-2.0 +/// +/// Unless required by applicable law or agreed to in writing, software +/// distributed under the License is distributed on an "AS IS" BASIS, +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +/// See the License for the specific language governing permissions and +/// limitations under the License. +/// + +import { EntityDebugSettings } from '@shared/models/entity.models'; + +export interface AdditionalDebugActionConfig void> { + action: Action; + title: string; +} + +export interface EntityDebugSettingPanelConfig { + debugSettings: EntityDebugSettings; + debugConfig: { + maxDebugModeDuration: number; + debugLimitsConfiguration: string; + entityLabel?: string; + additionalActionConfig?: AdditionalDebugActionConfig; + } + onSettingsAppliedFn: (settings: EntityDebugSettings) => void; +} diff --git a/ui-ngx/src/app/modules/home/components/entity/debug/entity-debug-settings.service.ts b/ui-ngx/src/app/modules/home/components/entity/debug/entity-debug-settings.service.ts index c53bc5b777..873d8f0f3f 100644 --- a/ui-ngx/src/app/modules/home/components/entity/debug/entity-debug-settings.service.ts +++ b/ui-ngx/src/app/modules/home/components/entity/debug/entity-debug-settings.service.ts @@ -16,10 +16,11 @@ import { Injectable, Optional, Renderer2, ViewContainerRef } from '@angular/core'; import { EntityDebugSettingsPanelComponent } from '@home/components/entity/debug/entity-debug-settings-panel.component'; -import { EntityDebugSettingPanelConfig, EntityDebugSettings } from '@shared/models/entity.models'; +import { EntityDebugSettings } from '@shared/models/entity.models'; import { TbPopoverService } from '@shared/components/popover.service'; import { TranslateService } from '@ngx-translate/core'; import { DurationLeftPipe } from '@shared/pipe/duration-left.pipe'; +import { EntityDebugSettingPanelConfig } from '@home/components/entity/debug/entity-debug-settings.model'; @Injectable() export class EntityDebugSettingsService { diff --git a/ui-ngx/src/app/shared/models/calculated-field.models.ts b/ui-ngx/src/app/shared/models/calculated-field.models.ts index 7083ce7ae0..c7b37e46f5 100644 --- a/ui-ngx/src/app/shared/models/calculated-field.models.ts +++ b/ui-ngx/src/app/shared/models/calculated-field.models.ts @@ -15,7 +15,6 @@ /// import { - AdditionalDebugActionConfig, HasEntityDebugSettings, HasTenantId, HasVersion @@ -34,6 +33,7 @@ import { dotOperatorHighlightRule, endGroupHighlightRule } from '@shared/models/ace/ace.models'; +import { AdditionalDebugActionConfig } from '@home/components/entity/debug/entity-debug-settings.model'; export interface CalculatedField extends Omit, 'label'>, HasVersion, HasEntityDebugSettings, HasTenantId, ExportableEntity { configuration: CalculatedFieldConfiguration; diff --git a/ui-ngx/src/app/shared/models/entity.models.ts b/ui-ngx/src/app/shared/models/entity.models.ts index 87536fdc54..5aa526b583 100644 --- a/ui-ngx/src/app/shared/models/entity.models.ts +++ b/ui-ngx/src/app/shared/models/entity.models.ts @@ -203,25 +203,9 @@ export interface EntityDebugSettings { allEnabledUntil?: number; } -export interface EntityDebugSettingPanelConfig { - debugSettings: EntityDebugSettings; - debugConfig: { - maxDebugModeDuration: number; - debugLimitsConfiguration: string; - entityLabel?: string; - additionalActionConfig?: AdditionalDebugActionConfig; - } - onSettingsAppliedFn: (settings: EntityDebugSettings) => void; -} - export interface EntityTestScriptResult { output: string; error: string; } -export interface AdditionalDebugActionConfig void> { - action: Action; - title: string; -} - export type VersionedEntity = EntityInfoData & HasVersion | RuleChainMetaData; From 78fc8445a7a41ee19d322386eba7c5678a839917 Mon Sep 17 00:00:00 2001 From: Vladyslav_Prykhodko Date: Fri, 14 Mar 2025 11:32:38 +0200 Subject: [PATCH 6/8] UI: Refactoring calculate fields models refactoring --- .../calculated-fields-table-config.ts | 15 +++++++------- .../calculated-field-dialog.component.ts | 16 ++++++++++++++- ...ated-field-script-test-dialog.component.ts | 10 +++++++++- .../shared/models/calculated-field.models.ts | 20 +------------------ 4 files changed, 32 insertions(+), 29 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/calculated-fields/calculated-fields-table-config.ts b/ui-ngx/src/app/modules/home/components/calculated-fields/calculated-fields-table-config.ts index 5689f176e9..5e7d532623 100644 --- a/ui-ngx/src/app/modules/home/components/calculated-fields/calculated-fields-table-config.ts +++ b/ui-ngx/src/app/modules/home/components/calculated-fields/calculated-fields-table-config.ts @@ -39,28 +39,27 @@ import { catchError, filter, switchMap, tap } from 'rxjs/operators'; import { ArgumentType, CalculatedField, - CalculatedFieldEventArguments, CalculatedFieldDebugDialogData, - CalculatedFieldDialogData, - CalculatedFieldTestScriptDialogData, + CalculatedFieldEventArguments, + CalculatedFieldType, + CalculatedFieldTypeTranslations, getCalculatedFieldArgumentsEditorCompleter, getCalculatedFieldArgumentsHighlights, - CalculatedFieldTypeTranslations, - CalculatedFieldType, } from '@shared/models/calculated-field.models'; import { CalculatedFieldDebugDialogComponent, CalculatedFieldDialogComponent, - CalculatedFieldScriptTestDialogComponent + CalculatedFieldDialogData, + CalculatedFieldScriptTestDialogComponent, + CalculatedFieldTestScriptDialogData } from './components/public-api'; import { ImportExportService } from '@shared/import-export/import-export.service'; import { isObject } from '@core/utils'; import { EntityDebugSettingsService } from '@home/components/entity/debug/entity-debug-settings.service'; import { DatePipe } from '@angular/common'; -export class CalculatedFieldsTableConfig extends EntityTableConfig { +export class CalculatedFieldsTableConfig extends EntityTableConfig { - // TODO: [Calculated Fields] remove hardcode when BE variable implemented readonly calculatedFieldsDebugPerTenantLimitsConfiguration = getCurrentAuthState(this.store)['calculatedFieldsDebugPerTenantLimitsConfiguration'] || '1:1'; readonly maxDebugModeDuration = getCurrentAuthState(this.store).maxDebugModeDurationMinutes * MINUTE; diff --git a/ui-ngx/src/app/modules/home/components/calculated-fields/components/dialog/calculated-field-dialog.component.ts b/ui-ngx/src/app/modules/home/components/calculated-fields/components/dialog/calculated-field-dialog.component.ts index 0c3e7464cd..631a55f0f6 100644 --- a/ui-ngx/src/app/modules/home/components/calculated-fields/components/dialog/calculated-field-dialog.component.ts +++ b/ui-ngx/src/app/modules/home/components/calculated-fields/components/dialog/calculated-field-dialog.component.ts @@ -25,7 +25,7 @@ import { CalculatedField, CalculatedFieldConfiguration, calculatedFieldDefaultScript, - CalculatedFieldDialogData, + CalculatedFieldTestScriptFn, CalculatedFieldType, CalculatedFieldTypeTranslations, getCalculatedFieldArgumentsEditorCompleter, @@ -41,6 +41,20 @@ import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { ScriptLanguage } from '@shared/models/rule-node.models'; import { CalculatedFieldsService } from '@core/http/calculated-fields.service'; import { Observable } from 'rxjs'; +import { EntityId } from '@shared/models/id/entity-id'; +import { AdditionalDebugActionConfig } from '@home/components/entity/debug/entity-debug-settings.model'; + +export interface CalculatedFieldDialogData { + value?: CalculatedField; + buttonTitle: string; + entityId: EntityId; + debugLimitsConfiguration: string; + tenantId: string; + entityName?: string; + additionalDebugActionConfig: AdditionalDebugActionConfig<(calculatedField: CalculatedField) => void>; + getTestScriptDialogFn: CalculatedFieldTestScriptFn; + isDirty?: boolean; +} @Component({ selector: 'tb-calculated-field-dialog', diff --git a/ui-ngx/src/app/modules/home/components/calculated-fields/components/test-dialog/calculated-field-script-test-dialog.component.ts b/ui-ngx/src/app/modules/home/components/calculated-fields/components/test-dialog/calculated-field-script-test-dialog.component.ts index 78c3b17bcb..fbc389939f 100644 --- a/ui-ngx/src/app/modules/home/components/calculated-fields/components/test-dialog/calculated-field-script-test-dialog.component.ts +++ b/ui-ngx/src/app/modules/home/components/calculated-fields/components/test-dialog/calculated-field-script-test-dialog.component.ts @@ -41,9 +41,17 @@ import { filter } from 'rxjs/operators'; import { ArgumentType, CalculatedFieldEventArguments, - CalculatedFieldTestScriptDialogData, + CalculatedFieldTestScriptInputParams, TestArgumentTypeMap } from '@shared/models/calculated-field.models'; +import { TbEditorCompleter } from '@shared/models/ace/completion.models'; +import { AceHighlightRules } from '@shared/models/ace/ace.models'; + +export interface CalculatedFieldTestScriptDialogData extends CalculatedFieldTestScriptInputParams { + argumentsEditorCompleter: TbEditorCompleter; + argumentsHighlightRules: AceHighlightRules; + openCalculatedFieldEdit?: boolean; +} @Component({ selector: 'tb-calculated-field-script-test-dialog', diff --git a/ui-ngx/src/app/shared/models/calculated-field.models.ts b/ui-ngx/src/app/shared/models/calculated-field.models.ts index c7b37e46f5..8afd280f3a 100644 --- a/ui-ngx/src/app/shared/models/calculated-field.models.ts +++ b/ui-ngx/src/app/shared/models/calculated-field.models.ts @@ -149,18 +149,6 @@ export interface CalculatedFieldArgumentValue extends CalculatedFieldArgument { export type CalculatedFieldTestScriptFn = (calculatedField: CalculatedField, argumentsObj?: Record, closeAllOnSave?: boolean) => Observable; -export interface CalculatedFieldDialogData { - value?: CalculatedField; - buttonTitle: string; - entityId: EntityId; - debugLimitsConfiguration: string; - tenantId: string; - entityName?: string; - additionalDebugActionConfig: AdditionalDebugActionConfig<(calculatedField: CalculatedField) => void>; - getTestScriptDialogFn: CalculatedFieldTestScriptFn; - isDirty?: boolean; -} - export interface CalculatedFieldDebugDialogData { tenantId: string; value: CalculatedField; @@ -172,12 +160,6 @@ export interface CalculatedFieldTestScriptInputParams { expression: string; } -export interface CalculatedFieldTestScriptDialogData extends CalculatedFieldTestScriptInputParams { - argumentsEditorCompleter: TbEditorCompleter; - argumentsHighlightRules: AceHighlightRules; - openCalculatedFieldEdit?: boolean; -} - export interface ArgumentEntityTypeParams { title: string; entityType: EntityType @@ -560,7 +542,7 @@ const calculatedFieldSingleArgumentValueHighlightRules: AceHighlightRules = { } const calculatedFieldRollingArgumentValueFunctionsHighlightRules: Array = - ['max', 'min', 'avg', 'mean', 'std', 'median', 'count', 'last', 'first', 'sum', 'merge', 'mergeAll'].map(funcName => ({ + Object.keys(CalculatedFieldRollingValueArgumentFunctionsAutocomplete).map(funcName => ({ token: 'tb.calculated-field-func', regex: `\\b${funcName}\\b`, next: 'no_regex' From faff769cda3d455de24269a85f9583cdbc04d57f Mon Sep 17 00:00:00 2001 From: Vladyslav_Prykhodko Date: Fri, 14 Mar 2025 11:34:13 +0200 Subject: [PATCH 7/8] UI: Refactoring calculate fields models refactoring --- ui-ngx/src/app/shared/models/calculated-field.models.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/ui-ngx/src/app/shared/models/calculated-field.models.ts b/ui-ngx/src/app/shared/models/calculated-field.models.ts index 8afd280f3a..c124e39a32 100644 --- a/ui-ngx/src/app/shared/models/calculated-field.models.ts +++ b/ui-ngx/src/app/shared/models/calculated-field.models.ts @@ -33,7 +33,6 @@ import { dotOperatorHighlightRule, endGroupHighlightRule } from '@shared/models/ace/ace.models'; -import { AdditionalDebugActionConfig } from '@home/components/entity/debug/entity-debug-settings.model'; export interface CalculatedField extends Omit, 'label'>, HasVersion, HasEntityDebugSettings, HasTenantId, ExportableEntity { configuration: CalculatedFieldConfiguration; From 2fec80eef2543db18c6649a25066c5447aef4864 Mon Sep 17 00:00:00 2001 From: Vladyslav_Prykhodko Date: Fri, 14 Mar 2025 11:49:15 +0200 Subject: [PATCH 8/8] UI: Refactoring calculate fields models refactoring --- .../calculated-fields-table-config.ts | 3 +-- .../calculated-field-debug-dialog.component.ts | 12 +++++++++++- .../src/app/shared/models/calculated-field.models.ts | 6 ------ 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/calculated-fields/calculated-fields-table-config.ts b/ui-ngx/src/app/modules/home/components/calculated-fields/calculated-fields-table-config.ts index 5e7d532623..2c0418bd4f 100644 --- a/ui-ngx/src/app/modules/home/components/calculated-fields/calculated-fields-table-config.ts +++ b/ui-ngx/src/app/modules/home/components/calculated-fields/calculated-fields-table-config.ts @@ -39,7 +39,6 @@ import { catchError, filter, switchMap, tap } from 'rxjs/operators'; import { ArgumentType, CalculatedField, - CalculatedFieldDebugDialogData, CalculatedFieldEventArguments, CalculatedFieldType, CalculatedFieldTypeTranslations, @@ -47,7 +46,7 @@ import { getCalculatedFieldArgumentsHighlights, } from '@shared/models/calculated-field.models'; import { - CalculatedFieldDebugDialogComponent, + CalculatedFieldDebugDialogComponent, CalculatedFieldDebugDialogData, CalculatedFieldDialogComponent, CalculatedFieldDialogData, CalculatedFieldScriptTestDialogComponent, diff --git a/ui-ngx/src/app/modules/home/components/calculated-fields/components/debug-dialog/calculated-field-debug-dialog.component.ts b/ui-ngx/src/app/modules/home/components/calculated-fields/components/debug-dialog/calculated-field-debug-dialog.component.ts index 8618a11990..2b987e124a 100644 --- a/ui-ngx/src/app/modules/home/components/calculated-fields/components/debug-dialog/calculated-field-debug-dialog.component.ts +++ b/ui-ngx/src/app/modules/home/components/calculated-fields/components/debug-dialog/calculated-field-debug-dialog.component.ts @@ -22,7 +22,17 @@ import { Router } from '@angular/router'; import { DialogComponent } from '@shared/components/dialog.component'; import { CalculatedFieldEventBody, DebugEventType, EventType } from '@shared/models/event.models'; import { EventTableComponent } from '@home/components/event/event-table.component'; -import { CalculatedFieldDebugDialogData, CalculatedFieldType } from '@shared/models/calculated-field.models'; +import { + CalculatedField, + CalculatedFieldTestScriptFn, + CalculatedFieldType +} from '@shared/models/calculated-field.models'; + +export interface CalculatedFieldDebugDialogData { + tenantId: string; + value: CalculatedField; + getTestScriptDialogFn: CalculatedFieldTestScriptFn; +} @Component({ selector: 'tb-calculated-field-debug-dialog', diff --git a/ui-ngx/src/app/shared/models/calculated-field.models.ts b/ui-ngx/src/app/shared/models/calculated-field.models.ts index c124e39a32..9dface6a67 100644 --- a/ui-ngx/src/app/shared/models/calculated-field.models.ts +++ b/ui-ngx/src/app/shared/models/calculated-field.models.ts @@ -148,12 +148,6 @@ export interface CalculatedFieldArgumentValue extends CalculatedFieldArgument { export type CalculatedFieldTestScriptFn = (calculatedField: CalculatedField, argumentsObj?: Record, closeAllOnSave?: boolean) => Observable; -export interface CalculatedFieldDebugDialogData { - tenantId: string; - value: CalculatedField; - getTestScriptDialogFn: CalculatedFieldTestScriptFn; -} - export interface CalculatedFieldTestScriptInputParams { arguments: CalculatedFieldEventArguments; expression: string;