Commit 034af204f02aedbf5440ed4fe34b2ccddc88c746

Authored by Vladyslav_Prykhodko
1 parent 5d30243e

UI: Added key name autocomplete in alarms rules to device profile

Showing 20 changed files with 188 additions and 45 deletions
... ... @@ -69,4 +69,20 @@ export class DeviceProfileService {
69 69 return this.http.get<PageData<DeviceProfileInfo>>(url, defaultHttpOptionsFromConfig(config));
70 70 }
71 71
  72 + public getDeviceProfileDevicesAttributesKeys(deviceProfileId?: string, config?: RequestConfig): Observable<Array<string>> {
  73 + let url = `/api/deviceProfile/devices/keys/attributes`;
  74 + if (isDefinedAndNotNull(deviceProfileId)) {
  75 + url += `?deviceProfileId=${deviceProfileId}`;
  76 + }
  77 + return this.http.get<Array<string>>(url, defaultHttpOptionsFromConfig(config));
  78 + }
  79 +
  80 + public getDeviceProfileDevicesTimeseriesKeys(deviceProfileId?: string, config?: RequestConfig): Observable<Array<string>> {
  81 + let url = `/api/deviceProfile/devices/keys/timeseries`;
  82 + if (isDefinedAndNotNull(deviceProfileId)) {
  83 + url += `?deviceProfileId=${deviceProfileId}`;
  84 + }
  85 + return this.http.get<Array<string>>(url, defaultHttpOptionsFromConfig(config));
  86 + }
  87 +
72 88 }
... ...
... ... @@ -40,11 +40,19 @@
40 40 <mat-form-field fxFlex="60" class="mat-block">
41 41 <mat-label translate>filter.key-name</mat-label>
42 42 <input matInput required formControlName="key"
43   - [matAutocomplete]="auto"
44   - [matAutocompleteDisabled]="keyFilterFormGroup.get('key.type').value !== entityField">
45   - <mat-autocomplete autoActiveFirstOption #auto="matAutocomplete">
46   - <mat-option *ngFor="let option of filteredEntityFields | async" [value]="option">
47   - {{option}}
  43 + #keyNameInput
  44 + (focusin)="onFocus()"
  45 + [matAutocomplete]="keyName"
  46 + [matAutocompleteDisabled]="!showAutocomplete">
  47 + <button *ngIf="keyFilterFormGroup.get('key.key').value && showAutocomplete"
  48 + type="button"
  49 + matSuffix mat-button mat-icon-button aria-label="Clear"
  50 + (click)="clear()">
  51 + <mat-icon class="material-icons">close</mat-icon>
  52 + </button>
  53 + <mat-autocomplete autoActiveFirstOption #keyName="matAutocomplete">
  54 + <mat-option *ngFor="let keyName of filteredKeysName | async" [value]="keyName">
  55 + <span [innerHTML]="keyName | highlight:searchText"></span>
48 56 </mat-option>
49 57 </mat-autocomplete>
50 58 <mat-error *ngIf="keyFilterFormGroup.get('key.key').hasError('required')">
... ...
... ... @@ -14,7 +14,7 @@
14 14 /// limitations under the License.
15 15 ///
16 16
17   -import { Component, Inject, OnInit, SkipSelf } from '@angular/core';
  17 +import { Component, ElementRef, Inject, OnDestroy, OnInit, SkipSelf, ViewChild } from '@angular/core';
18 18 import { ErrorStateMatcher } from '@angular/material/core';
19 19 import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
20 20 import { Store } from '@ngrx/store';
... ... @@ -32,9 +32,12 @@ import {
32 32 } from '@shared/models/query/query.models';
33 33 import { DialogService } from '@core/services/dialog.service';
34 34 import { TranslateService } from '@ngx-translate/core';
35   -import { EntityField, entityFields } from '@shared/models/entity.models';
36   -import { Observable } from 'rxjs';
37   -import { filter, map, startWith } from 'rxjs/operators';
  35 +import { entityFields } from '@shared/models/entity.models';
  36 +import { Observable, of, Subject } from 'rxjs';
  37 +import { filter, map, mergeMap, publishReplay, refCount, startWith, takeUntil } from 'rxjs/operators';
  38 +import { isDefined } from '@core/utils';
  39 +import { EntityId } from '@shared/models/id/entity-id';
  40 +import { DeviceProfileService } from '@core/http/device-profile.service';
38 41
39 42 export interface KeyFilterDialogData {
40 43 keyFilter: KeyFilterInfo;
... ... @@ -43,6 +46,7 @@ export interface KeyFilterDialogData {
43 46 allowUserDynamicSource: boolean;
44 47 readonly: boolean;
45 48 telemetryKeysOnly: boolean;
  49 + entityId?: EntityId;
46 50 }
47 51
48 52 @Component({
... ... @@ -53,7 +57,13 @@ export interface KeyFilterDialogData {
53 57 })
54 58 export class KeyFilterDialogComponent extends
55 59 DialogComponent<KeyFilterDialogComponent, KeyFilterInfo>
56   - implements OnInit, ErrorStateMatcher {
  60 + implements OnInit, OnDestroy, ErrorStateMatcher {
  61 +
  62 + @ViewChild('keyNameInput', {static: true}) private keyNameInput: ElementRef;
  63 +
  64 + private dirty = false;
  65 + private entityKeysName: Observable<Array<string>>;
  66 + private destroy$ = new Subject();
57 67
58 68 keyFilterFormGroup: FormGroup;
59 69
... ... @@ -72,19 +82,18 @@ export class KeyFilterDialogComponent extends
72 82
73 83 submitted = false;
74 84
75   - entityFields: { [fieldName: string]: EntityField };
76   -
77   - entityFieldsList: string[];
  85 + showAutocomplete = false;
78 86
79   - readonly entityField = EntityKeyType.ENTITY_FIELD;
  87 + filteredKeysName: Observable<Array<string>>;
80 88
81   - filteredEntityFields: Observable<string[]>;
  89 + searchText = '';
82 90
83 91 constructor(protected store: Store<AppState>,
84 92 protected router: Router,
85 93 @Inject(MAT_DIALOG_DATA) public data: KeyFilterDialogData,
86 94 @SkipSelf() private errorStateMatcher: ErrorStateMatcher,
87 95 public dialogRef: MatDialogRef<KeyFilterDialogComponent, KeyFilterInfo>,
  96 + private deviceProfileService: DeviceProfileService,
88 97 private dialogs: DialogService,
89 98 private translate: TranslateService,
90 99 private fb: FormBuilder) {
... ... @@ -104,7 +113,9 @@ export class KeyFilterDialogComponent extends
104 113 );
105 114
106 115 if (!this.data.readonly) {
107   - this.keyFilterFormGroup.get('valueType').valueChanges.subscribe((valueType: EntityKeyValueType) => {
  116 + this.keyFilterFormGroup.get('valueType').valueChanges.pipe(
  117 + takeUntil(this.destroy$)
  118 + ).subscribe((valueType: EntityKeyValueType) => {
108 119 const prevValue: EntityKeyValueType = this.keyFilterFormGroup.value.valueType;
109 120 const predicates: KeyFilterPredicate[] = this.keyFilterFormGroup.get('predicates').value;
110 121 if (prevValue && prevValue !== valueType && predicates && predicates.length) {
... ... @@ -121,11 +132,26 @@ export class KeyFilterDialogComponent extends
121 132 }
122 133 });
123 134
  135 + this.keyFilterFormGroup.get('key.type').valueChanges.pipe(
  136 + startWith(this.data.keyFilter.key.type),
  137 + takeUntil(this.destroy$)
  138 + ).subscribe((type: EntityKeyType) => {
  139 + if (type === EntityKeyType.ENTITY_FIELD || isDefined(this.data.entityId)) {
  140 + this.entityKeysName = null;
  141 + this.dirty = false;
  142 + this.showAutocomplete = true;
  143 + } else {
  144 + this.showAutocomplete = false;
  145 + }
  146 + });
  147 +
124 148 this.keyFilterFormGroup.get('key.key').valueChanges.pipe(
125   - filter((keyName) => this.keyFilterFormGroup.get('key.type').value === this.entityField && this.entityFields.hasOwnProperty(keyName))
  149 + filter((keyName) =>
  150 + this.keyFilterFormGroup.get('key.type').value === EntityKeyType.ENTITY_FIELD && entityFields.hasOwnProperty(keyName)),
  151 + takeUntil(this.destroy$)
126 152 ).subscribe((keyName: string) => {
127 153 const prevValueType: EntityKeyValueType = this.keyFilterFormGroup.value.valueType;
128   - const newValueType = this.entityFields[keyName]?.time ? EntityKeyValueType.DATE_TIME : EntityKeyValueType.STRING;
  154 + const newValueType = entityFields[keyName]?.time ? EntityKeyValueType.DATE_TIME : EntityKeyValueType.STRING;
129 155 if (prevValueType !== newValueType) {
130 156 this.keyFilterFormGroup.get('valueType').patchValue(newValueType, {emitEvent: false});
131 157 }
... ... @@ -133,18 +159,20 @@ export class KeyFilterDialogComponent extends
133 159 } else {
134 160 this.keyFilterFormGroup.disable({emitEvent: false});
135 161 }
  162 + }
136 163
137   - this.entityFields = entityFields;
138   - this.entityFieldsList = Object.values(entityFields).map(entityField => entityField.keyName).sort();
  164 + ngOnInit() {
  165 + this.filteredKeysName = this.keyFilterFormGroup.get('key.key').valueChanges
  166 + .pipe(
  167 + map(value => value ? value : ''),
  168 + mergeMap(name => this.fetchEntityName(name))
  169 + );
139 170 }
140 171
141   - ngOnInit(): void {
142   - this.filteredEntityFields = this.keyFilterFormGroup.get('key.key').valueChanges.pipe(
143   - startWith(''),
144   - map(value => {
145   - return this.entityFieldsList.filter(option => option.startsWith(value));
146   - })
147   - );
  172 + ngOnDestroy() {
  173 + super.ngOnDestroy();
  174 + this.destroy$.next();
  175 + this.destroy$.complete();
148 176 }
149 177
150 178 isErrorState(control: FormControl | null, form: FormGroupDirective | NgForm | null): boolean {
... ... @@ -157,6 +185,21 @@ export class KeyFilterDialogComponent extends
157 185 this.dialogRef.close(null);
158 186 }
159 187
  188 + clear() {
  189 + this.keyFilterFormGroup.get('key.key').patchValue('', {emitEvent: true});
  190 + setTimeout(() => {
  191 + this.keyNameInput.nativeElement.blur();
  192 + this.keyNameInput.nativeElement.focus();
  193 + }, 0);
  194 + }
  195 +
  196 + onFocus() {
  197 + if (!this.dirty && this.showAutocomplete) {
  198 + this.keyFilterFormGroup.get('key.key').updateValueAndValidity({onlySelf: true, emitEvent: true});
  199 + this.dirty = true;
  200 + }
  201 + }
  202 +
160 203 save(): void {
161 204 this.submitted = true;
162 205 if (this.keyFilterFormGroup.valid) {
... ... @@ -164,4 +207,41 @@ export class KeyFilterDialogComponent extends
164 207 this.dialogRef.close(keyFilter);
165 208 }
166 209 }
  210 +
  211 + private fetchEntityName(searchText?: string): Observable<Array<string>> {
  212 + this.searchText = searchText;
  213 + return this.getEntityKeys().pipe(
  214 + map(keys => searchText ? keys.filter(key => key.toUpperCase().startsWith(searchText.toUpperCase())) : keys)
  215 + );
  216 + }
  217 +
  218 + private getEntityKeys(): Observable<Array<string>> {
  219 + if (!this.entityKeysName) {
  220 + let keyNameObservable: Observable<Array<string>>;
  221 + switch (this.keyFilterFormGroup.get('key.type').value) {
  222 + case EntityKeyType.ENTITY_FIELD:
  223 + keyNameObservable = of(Object.values(entityFields).map(entityField => entityField.keyName).sort());
  224 + break;
  225 + case EntityKeyType.ATTRIBUTE:
  226 + keyNameObservable = this.deviceProfileService.getDeviceProfileDevicesAttributesKeys(
  227 + this.data.entityId?.id,
  228 + {ignoreLoading: true}
  229 + );
  230 + break;
  231 + case EntityKeyType.TIME_SERIES:
  232 + keyNameObservable = this.deviceProfileService.getDeviceProfileDevicesTimeseriesKeys(
  233 + this.data.entityId?.id,
  234 + {ignoreLoading: true}
  235 + );
  236 + break;
  237 + default:
  238 + keyNameObservable = of([]);
  239 + }
  240 + this.entityKeysName = keyNameObservable.pipe(
  241 + publishReplay(1),
  242 + refCount()
  243 + );
  244 + }
  245 + return this.entityKeysName;
  246 + }
167 247 }
... ...
... ... @@ -19,7 +19,8 @@ import {
19 19 AbstractControl,
20 20 ControlValueAccessor,
21 21 FormArray,
22   - FormBuilder, FormControl,
  22 + FormBuilder,
  23 + FormControl,
23 24 FormGroup,
24 25 NG_VALUE_ACCESSOR,
25 26 Validators
... ... @@ -28,12 +29,13 @@ import { Observable, Subscription } from 'rxjs';
28 29 import {
29 30 EntityKeyType,
30 31 entityKeyTypeTranslationMap,
31   - KeyFilter,
32   - KeyFilterInfo, keyFilterInfosToKeyFilters
  32 + KeyFilterInfo,
  33 + keyFilterInfosToKeyFilters
33 34 } from '@shared/models/query/query.models';
34 35 import { MatDialog } from '@angular/material/dialog';
35 36 import { deepClone } from '@core/utils';
36 37 import { KeyFilterDialogComponent, KeyFilterDialogData } from '@home/components/filter/key-filter-dialog.component';
  38 +import { EntityId } from '@shared/models/id/entity-id';
37 39
38 40 @Component({
39 41 selector: 'tb-key-filter-list',
... ... @@ -57,6 +59,8 @@ export class KeyFilterListComponent implements ControlValueAccessor, OnInit {
57 59
58 60 @Input() telemetryKeysOnly = false;
59 61
  62 + @Input() entityId: EntityId;
  63 +
60 64 keyFilterListFormGroup: FormGroup;
61 65
62 66 entityKeyTypeTranslations = entityKeyTypeTranslationMap;
... ... @@ -170,7 +174,8 @@ export class KeyFilterListComponent implements ControlValueAccessor, OnInit {
170 174 readonly: this.disabled,
171 175 displayUserParameters: this.displayUserParameters,
172 176 allowUserDynamicSource: this.allowUserDynamicSource,
173   - telemetryKeysOnly: this.telemetryKeysOnly
  177 + telemetryKeysOnly: this.telemetryKeysOnly,
  178 + entityId: this.entityId
174 179 }
175 180 }).afterClosed();
176 181 }
... ...
... ... @@ -96,7 +96,8 @@
96 96 {count: alarmRulesFormGroup.get('alarms').value ?
97 97 alarmRulesFormGroup.get('alarms').value.length : 0} }}</ng-template>
98 98 <tb-device-profile-alarms
99   - formControlName="alarms">
  99 + formControlName="alarms"
  100 + [deviceProfileId]="null">
100 101 </tb-device-profile-alarms>
101 102 </form>
102 103 </mat-step>
... ...
... ... @@ -34,6 +34,7 @@
34 34 [displayUserParameters]="false"
35 35 [allowUserDynamicSource]="false"
36 36 [telemetryKeysOnly]="true"
  37 + [entityId]="entityId"
37 38 formControlName="keyFilters">
38 39 </tb-key-filter-list>
39 40 <section formGroupName="spec" class="row">
... ...
... ... @@ -22,15 +22,16 @@ import { AppState } from '@core/core.state';
22 22 import { FormBuilder, FormControl, FormGroup, FormGroupDirective, NgForm, Validators } from '@angular/forms';
23 23 import { Router } from '@angular/router';
24 24 import { DialogComponent } from '@app/shared/components/dialog.component';
25   -import { UtilsService } from '@core/services/utils.service';
26 25 import { TranslateService } from '@ngx-translate/core';
27   -import { KeyFilter, keyFilterInfosToKeyFilters, keyFiltersToKeyFilterInfos } from '@shared/models/query/query.models';
  26 +import { keyFilterInfosToKeyFilters, keyFiltersToKeyFilterInfos } from '@shared/models/query/query.models';
28 27 import { AlarmCondition, AlarmConditionType, AlarmConditionTypeTranslationMap } from '@shared/models/device.models';
29 28 import { TimeUnit, timeUnitTranslationMap } from '@shared/models/time/time.models';
  29 +import { EntityId } from '@shared/models/id/entity-id';
30 30
31 31 export interface AlarmRuleConditionDialogData {
32 32 readonly: boolean;
33 33 condition: AlarmCondition;
  34 + entityId?: EntityId;
34 35 }
35 36
36 37 @Component({
... ... @@ -50,6 +51,7 @@ export class AlarmRuleConditionDialogComponent extends DialogComponent<AlarmRule
50 51
51 52 readonly = this.data.readonly;
52 53 condition = this.data.condition;
  54 + entityId = this.data.entityId;
53 55
54 56 conditionFormGroup: FormGroup;
55 57
... ... @@ -61,7 +63,6 @@ export class AlarmRuleConditionDialogComponent extends DialogComponent<AlarmRule
61 63 @SkipSelf() private errorStateMatcher: ErrorStateMatcher,
62 64 public dialogRef: MatDialogRef<AlarmRuleConditionDialogComponent, AlarmCondition>,
63 65 private fb: FormBuilder,
64   - private utils: UtilsService,
65 66 public translate: TranslateService) {
66 67 super(store, router, dialogRef);
67 68
... ...
... ... @@ -33,6 +33,7 @@ import {
33 33 AlarmRuleConditionDialogData
34 34 } from '@home/components/profile/alarm/alarm-rule-condition-dialog.component';
35 35 import { TimeUnit } from '@shared/models/time/time.models';
  36 +import { EntityId } from '@shared/models/id/entity-id';
36 37
37 38 @Component({
38 39 selector: 'tb-alarm-rule-condition',
... ... @@ -56,6 +57,9 @@ export class AlarmRuleConditionComponent implements ControlValueAccessor, OnInit
56 57 @Input()
57 58 disabled: boolean;
58 59
  60 + @Input()
  61 + deviceProfileId: EntityId;
  62 +
59 63 alarmRuleConditionFormGroup: FormGroup;
60 64
61 65 specText = '';
... ... @@ -123,7 +127,8 @@ export class AlarmRuleConditionComponent implements ControlValueAccessor, OnInit
123 127 panelClass: ['tb-dialog', 'tb-fullscreen-dialog'],
124 128 data: {
125 129 readonly: this.disabled,
126   - condition: this.disabled ? this.modelValue : deepClone(this.modelValue)
  130 + condition: this.disabled ? this.modelValue : deepClone(this.modelValue),
  131 + entityId: this.deviceProfileId
127 132 }
128 133 }).afterClosed().subscribe((result) => {
129 134 if (result) {
... ...
... ... @@ -16,7 +16,7 @@
16 16
17 17 -->
18 18 <div fxLayout="column" [formGroup]="alarmRuleFormGroup">
19   - <tb-alarm-rule-condition formControlName="condition">
  19 + <tb-alarm-rule-condition formControlName="condition" [deviceProfileId]="deviceProfileId">
20 20 </tb-alarm-rule-condition>
21 21 <tb-alarm-schedule-info formControlName="schedule">
22 22 </tb-alarm-schedule-info>
... ...
... ... @@ -33,6 +33,7 @@ import {
33 33 EditAlarmDetailsDialogComponent,
34 34 EditAlarmDetailsDialogData
35 35 } from '@home/components/profile/alarm/edit-alarm-details-dialog.component';
  36 +import { EntityId } from '@shared/models/id/entity-id';
36 37
37 38 @Component({
38 39 selector: 'tb-alarm-rule',
... ... @@ -65,6 +66,9 @@ export class AlarmRuleComponent implements ControlValueAccessor, OnInit, Validat
65 66 this.requiredValue = coerceBooleanProperty(value);
66 67 }
67 68
  69 + @Input()
  70 + deviceProfileId: EntityId;
  71 +
68 72 private modelValue: AlarmRule;
69 73
70 74 alarmRuleFormGroup: FormGroup;
... ...
... ... @@ -35,7 +35,7 @@
35 35 </mat-error>
36 36 </mat-form-field>
37 37 <mat-divider vertical></mat-divider>
38   - <tb-alarm-rule formControlName="alarmRule" required fxFlex>
  38 + <tb-alarm-rule formControlName="alarmRule" [deviceProfileId]="deviceProfileId" required fxFlex>
39 39 </tb-alarm-rule>
40 40 </div>
41 41 <button *ngIf="!disabled"
... ...
... ... @@ -30,7 +30,8 @@ import {
30 30 import { AlarmRule, alarmRuleValidator } from '@shared/models/device.models';
31 31 import { MatDialog } from '@angular/material/dialog';
32 32 import { Subscription } from 'rxjs';
33   -import { AlarmSeverity, alarmSeverityTranslations } from '../../../../../shared/models/alarm.models';
  33 +import { AlarmSeverity, alarmSeverityTranslations } from '@shared/models/alarm.models';
  34 +import { EntityId } from '@shared/models/id/entity-id';
34 35
35 36 @Component({
36 37 selector: 'tb-create-alarm-rules',
... ... @@ -59,6 +60,9 @@ export class CreateAlarmRulesComponent implements ControlValueAccessor, OnInit,
59 60 @Input()
60 61 disabled: boolean;
61 62
  63 + @Input()
  64 + deviceProfileId: EntityId;
  65 +
62 66 createAlarmRulesFormGroup: FormGroup;
63 67
64 68 private usedSeverities: AlarmSeverity[] = [];
... ...
... ... @@ -80,14 +80,16 @@
80 80 </mat-expansion-panel>
81 81 <div fxFlex fxLayout="column">
82 82 <div translate class="tb-small" style="padding-bottom: 8px;">device-profile.create-alarm-rules</div>
83   - <tb-create-alarm-rules formControlName="createRules" style="padding-bottom: 16px;">
  83 + <tb-create-alarm-rules formControlName="createRules"
  84 + style="padding-bottom: 16px;"
  85 + [deviceProfileId]="deviceProfileId">
84 86 </tb-create-alarm-rules>
85 87 <div translate class="tb-small" style="padding-bottom: 8px;">device-profile.clear-alarm-rule</div>
86 88 <div fxLayout="row" fxLayoutGap="8px;" fxLayoutAlign="start center"
87 89 [fxShow]="alarmFormGroup.get('clearRule').value"
88 90 style="padding-bottom: 8px;">
89 91 <div class="clear-alarm-rule" fxFlex fxLayout="row">
90   - <tb-alarm-rule formControlName="clearRule" fxFlex>
  92 + <tb-alarm-rule formControlName="clearRule" fxFlex [deviceProfileId]="deviceProfileId">
91 93 </tb-alarm-rule>
92 94 </div>
93 95 <button *ngIf="!disabled"
... ...
... ... @@ -29,6 +29,7 @@ import { AlarmRule, DeviceProfileAlarm, deviceProfileAlarmValidator } from '@sha
29 29 import { MatDialog } from '@angular/material/dialog';
30 30 import { COMMA, ENTER, SEMICOLON } from '@angular/cdk/keycodes';
31 31 import { MatChipInputEvent } from '@angular/material/chips';
  32 +import { EntityId } from '@shared/models/id/entity-id';
32 33
33 34 @Component({
34 35 selector: 'tb-device-profile-alarm',
... ... @@ -60,6 +61,9 @@ export class DeviceProfileAlarmComponent implements ControlValueAccessor, OnInit
60 61 @Input()
61 62 expanded = false;
62 63
  64 + @Input()
  65 + deviceProfileId: EntityId;
  66 +
63 67 private modelValue: DeviceProfileAlarm;
64 68
65 69 alarmFormGroup: FormGroup;
... ...
... ... @@ -22,6 +22,7 @@
22 22 fxLayout="column" [ngStyle]="!isLast ? {paddingBottom: '8px'} : {}">
23 23 <tb-device-profile-alarm [formControl]="alarmControl"
24 24 [expanded]="$index === 0"
  25 + [deviceProfileId]="deviceProfileId"
25 26 (removeAlarm)="removeAlarm($index)">
26 27 </tb-device-profile-alarm>
27 28 </div>
... ...
... ... @@ -34,6 +34,7 @@ import { DeviceProfileAlarm, deviceProfileAlarmValidator } from '@shared/models/
34 34 import { guid } from '@core/utils';
35 35 import { Subscription } from 'rxjs';
36 36 import { MatDialog } from '@angular/material/dialog';
  37 +import { EntityId } from '@shared/models/id/entity-id';
37 38
38 39 @Component({
39 40 selector: 'tb-device-profile-alarms',
... ... @@ -68,6 +69,9 @@ export class DeviceProfileAlarmsComponent implements ControlValueAccessor, OnIni
68 69 @Input()
69 70 disabled: boolean;
70 71
  72 + @Input()
  73 + deviceProfileId: EntityId;
  74 +
71 75 private valueChangeSubscription: Subscription = null;
72 76
73 77 private propagateChange = (v: any) => { };
... ...
... ... @@ -116,7 +116,8 @@
116 116 </mat-panel-title>
117 117 </mat-expansion-panel-header>
118 118 <tb-device-profile-alarms
119   - formControlName="alarms">
  119 + formControlName="alarms"
  120 + [deviceProfileId]="deviceProfileId">
120 121 </tb-device-profile-alarms>
121 122 </mat-expansion-panel>
122 123 <mat-expansion-panel [expanded]="true">
... ...
... ... @@ -39,6 +39,7 @@ import {
39 39 import { EntityType } from '@shared/models/entity-type.models';
40 40 import { RuleChainId } from '@shared/models/id/rule-chain-id';
41 41 import { ServiceType } from '@shared/models/queue.models';
  42 +import { EntityId } from '@shared/models/id/entity-id';
42 43
43 44 @Component({
44 45 selector: 'tb-device-profile',
... ... @@ -66,6 +67,8 @@ export class DeviceProfileComponent extends EntityComponent<DeviceProfile> {
66 67
67 68 serviceType = ServiceType.TB_RULE_ENGINE;
68 69
  70 + deviceProfileId: EntityId;
  71 +
69 72 constructor(protected store: Store<AppState>,
70 73 protected translate: TranslateService,
71 74 @Optional() @Inject('entity') protected entityValue: DeviceProfile,
... ... @@ -83,6 +86,7 @@ export class DeviceProfileComponent extends EntityComponent<DeviceProfile> {
83 86 }
84 87
85 88 buildForm(entity: DeviceProfile): FormGroup {
  89 + this.deviceProfileId = entity?.id ? entity.id : null;
86 90 this.displayProfileConfiguration = entity && entity.type &&
87 91 deviceProfileTypeConfigurationInfoMap.get(entity.type).hasProfileConfiguration;
88 92 this.displayTransportConfiguration = entity && entity.transportType &&
... ... @@ -157,6 +161,7 @@ export class DeviceProfileComponent extends EntityComponent<DeviceProfile> {
157 161 }
158 162
159 163 updateForm(entity: DeviceProfile) {
  164 + this.deviceProfileId = entity.id;
160 165 this.displayProfileConfiguration = entity.type &&
161 166 deviceProfileTypeConfigurationInfoMap.get(entity.type).hasProfileConfiguration;
162 167 this.displayTransportConfiguration = entity.transportType &&
... ...
... ... @@ -76,7 +76,7 @@
76 76 [required]="!createProfile"
77 77 [transportType]="deviceWizardFormGroup.get('transportType').value"
78 78 formControlName="deviceProfileId"
79   - [ngClass]="{invisible: deviceWizardFormGroup.get('addProfileType').value !== 0}"
  79 + [ngClass]="{invisible: deviceWizardFormGroup.get('addProfileType').value !== 0}"
80 80 (deviceProfileChanged)="$event?.transportType ? deviceWizardFormGroup.get('transportType').patchValue($event?.transportType) : {}"
81 81 [addNewProfile]="false"
82 82 [selectDefaultProfile]="true"
... ... @@ -133,7 +133,8 @@
133 133 {count: alarmRulesFormGroup.get('alarms').value ?
134 134 alarmRulesFormGroup.get('alarms').value.length : 0} }}</ng-template>
135 135 <tb-device-profile-alarms
136   - formControlName="alarms">
  136 + formControlName="alarms"
  137 + [deviceProfileId]="null">
137 138 </tb-device-profile-alarms>
138 139 </form>
139 140 </mat-step>
... ...
... ... @@ -46,7 +46,7 @@
46 46 }}" #alarmRules="matTab">
47 47 <div class="mat-padding" [formGroup]="detailsForm">
48 48 <div formGroupName="profileData">
49   - <tb-device-profile-alarms formControlName="alarms"></tb-device-profile-alarms>
  49 + <tb-device-profile-alarms formControlName="alarms" [deviceProfileId]="entity.id"></tb-device-profile-alarms>
50 50 </div>
51 51 </div>
52 52 </mat-tab>
... ...