Browse Source

UI: Fixed for alarm rule and calculated fields page

pull/14726/head
ArtemDzhereleiko 9 months ago
committed by Vladyslav Prykhodko
parent
commit
5bf087eec4
  1. 4
      ui-ngx/src/app/modules/home/components/alarm-rules/alarm-rule-dialog.component.html
  2. 17
      ui-ngx/src/app/modules/home/components/alarm-rules/alarm-rule-dialog.component.ts
  3. 3
      ui-ngx/src/app/modules/home/components/alarm-rules/alarm-rules.component.html
  4. 40
      ui-ngx/src/app/modules/home/components/alarm-rules/alarm-rules.component.ts
  5. 12
      ui-ngx/src/app/modules/home/components/alarm-rules/cf-alarm-rule-condition-dialog.component.ts
  6. 12
      ui-ngx/src/app/modules/home/components/alarm-rules/cf-alarm-rule-condition.component.html
  7. 47
      ui-ngx/src/app/modules/home/components/alarm-rules/cf-alarm-rule-condition.component.ts
  8. 26
      ui-ngx/src/app/modules/home/components/calculated-fields/calculated-field.component.ts
  9. 2
      ui-ngx/src/app/modules/home/components/calculated-fields/calculated-fields-table-config.ts
  10. 6
      ui-ngx/src/app/modules/home/components/calculated-fields/components/dialog/calculated-field-dialog.component.html
  11. 12
      ui-ngx/src/app/modules/home/components/calculated-fields/components/dialog/calculated-field-dialog.component.ts
  12. 1
      ui-ngx/src/app/modules/home/components/calculated-fields/components/geofencing-configuration/calculated-field-geofencing-zone-groups-panel.component.ts
  13. 14
      ui-ngx/src/app/modules/home/components/calculated-fields/components/geofencing-configuration/geofencing-configuration.component.ts
  14. 1
      ui-ngx/src/app/shared/components/entity/entity-select.component.html
  15. 9
      ui-ngx/src/app/shared/components/entity/entity-select.component.ts
  16. 4
      ui-ngx/src/app/shared/components/string-items-list.component.html
  17. 4
      ui-ngx/src/app/shared/components/string-items-list.component.ts
  18. 2
      ui-ngx/src/app/shared/models/calculated-field.models.ts
  19. 2
      ui-ngx/src/assets/locale/locale.constant-en_US.json

4
ui-ngx/src/app/modules/home/components/alarm-rules/alarm-rule-dialog.component.html

@ -59,6 +59,7 @@
</div>
@if (!data.entityId) {
<tb-entity-select formControlName="entityId"
#entitySelect
appearance="outline"
required
entityTypeLabel="{{ 'entity.entity-type' | translate }}"
@ -75,7 +76,7 @@
<tb-calculated-field-arguments-table formControlName="arguments"
[entityId]="data.entityId || fieldFormGroup.get('entityId').value"
[tenantId]="data.tenantId"
[ownerId]="data.ownerId"
[ownerId]="ownerId"
[watchKeyChange]="true"
[entityName]="entityName"/>
</div>
@ -134,6 +135,7 @@
placeholder="{{ 'alarm-rule.alarm-rule-relation-types-list' | translate }}"
hint="{{ 'alarm-rule.alarm-rule-relation-types-list-hint' | translate }}"
[predefinedValues]="predefinedTypeValues"
allowUserValue
formControlName="propagateRelationTypes">
</tb-string-items-list>
}

17
ui-ngx/src/app/modules/home/components/alarm-rules/alarm-rule-dialog.component.ts

@ -14,7 +14,7 @@
/// limitations under the License.
///
import { Component, DestroyRef, Inject, ViewEncapsulation } from '@angular/core';
import { Component, DestroyRef, Inject, ViewChild, ViewEncapsulation } from '@angular/core';
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
import { Store } from '@ngrx/store';
import { AppState } from '@core/core.state';
@ -43,6 +43,10 @@ import { RelationTypes } from "@shared/models/relation.models";
import { StringItemsOption } from "@shared/components/string-items-list.component";
import { BaseData } from "@shared/models/base-data";
import { CalculatedFieldFormService } from '@core/services/calculated-field-form.service';
import { EntitySelectComponent } from '@shared/components/entity/entity-select.component';
import { NULL_UUID } from '@shared/models/id/has-uuid';
import { AssetInfo } from '@shared/models/asset.models';
import { DeviceInfo } from '@shared/models/device.models';
export interface AlarmRuleDialogData {
value?: CalculatedField;
@ -64,6 +68,8 @@ export interface AlarmRuleDialogData {
})
export class AlarmRuleDialogComponent extends DialogComponent<AlarmRuleDialogComponent, CalculatedField> {
@ViewChild('entitySelect') entitySelect!: EntitySelectComponent;
fieldFormGroup: FormGroup ;
additionalDebugActionConfig = this.data.value?.id ? {
@ -80,6 +86,7 @@ export class AlarmRuleDialogComponent extends DialogComponent<AlarmRuleDialogCom
separatorKeysCodes = [ENTER, COMMA, SEMICOLON];
entityName = this.data.entityName;
ownerId = this.data.ownerId;
disabledClearRuleButton = false;
disabledArguments = false;
@ -173,6 +180,7 @@ export class AlarmRuleDialogComponent extends DialogComponent<AlarmRuleDialogCom
});
} else {
this.fieldFormGroup.get('name').markAsTouched();
this.entitySelect.entityAutocompleteMarkAsTouched();
}
}
@ -219,5 +227,12 @@ export class AlarmRuleDialogComponent extends DialogComponent<AlarmRuleDialogCom
changeEntity(entity: BaseData<EntityId>): void {
this.entityName = entity.name;
if (this.isAssignedToCustomer(entity as AssetInfo | DeviceInfo)) {
this.ownerId = (entity as AssetInfo | DeviceInfo).customerId;
}
}
private isAssignedToCustomer(entity: AssetInfo | DeviceInfo): boolean {
return entity && entity.customerId && entity.customerId.id !== NULL_UUID;
}
}

3
ui-ngx/src/app/modules/home/components/alarm-rules/alarm-rules.component.html

@ -68,7 +68,7 @@
required
entityTypeLabel="{{ 'entity.entity-type' | translate }}"
[filterAllowedEntityTypes]="false"
[allowedEntityTypes]="calculatedFieldsEntityTypeList"
[allowedEntityTypes]="alarmRuleEntityTypeList"
(entityChanged)="changeEntity($event)">
</tb-entity-select>
</div>
@ -137,6 +137,7 @@
placeholder="{{ 'alarm-rule.alarm-rule-relation-types-list' | translate }}"
hint="{{ 'alarm-rule.alarm-rule-relation-types-list-hint' | translate }}"
[predefinedValues]="predefinedTypeValues"
allowUserValue
formControlName="propagateRelationTypes">
</tb-string-items-list>
}

40
ui-ngx/src/app/modules/home/components/alarm-rules/alarm-rules.component.ts

@ -25,7 +25,6 @@ import {
CalculatedFieldArgument,
CalculatedFieldConfiguration,
CalculatedFieldInfo,
calculatedFieldsEntityTypeList,
CalculatedFieldType
} from '@shared/models/calculated-field.models';
import { EntityId } from '@shared/models/id/entity-id';
@ -39,8 +38,17 @@ import {
import { TenantId } from '@shared/models/id/tenant-id';
import { StringItemsOption } from '@shared/components/string-items-list.component';
import { RelationTypes } from '@shared/models/relation.models';
import { AlarmRule, AlarmRuleConditionType, AlarmRuleExpressionType } from '@shared/models/alarm-rule.models';
import {
AlarmRule,
AlarmRuleConditionType,
alarmRuleEntityTypeList,
AlarmRuleExpressionType
} from '@shared/models/alarm-rule.models';
import { CalculatedFieldFormService } from '@core/services/calculated-field-form.service';
import { AssetInfo } from '@shared/models/asset.models';
import { DeviceInfo } from '@shared/models/device.models';
import { NULL_UUID } from '@shared/models/id/has-uuid';
import { EntityService } from '@core/http/entity.service';
@Component({
selector: 'tb-alarm-rules',
@ -55,10 +63,10 @@ export class AlarmRulesComponent extends EntityComponent<CalculatedFieldsTableEn
@Input()
entityName: string;
readonly ownerId = new TenantId(getCurrentAuthUser(this.store).tenantId);
ownerId = new TenantId(getCurrentAuthUser(this.store).tenantId);
readonly tenantId = getCurrentAuthUser(this.store).tenantId;
readonly EntityType = EntityType;
readonly calculatedFieldsEntityTypeList = calculatedFieldsEntityTypeList;
readonly alarmRuleEntityTypeList = alarmRuleEntityTypeList;
readonly CalculatedFieldType = CalculatedFieldType;
private cfFormService = inject(CalculatedFieldFormService);
@ -69,7 +77,8 @@ export class AlarmRulesComponent extends EntityComponent<CalculatedFieldsTableEn
@Inject('entity') protected entityValue: CalculatedFieldInfo,
@Inject('entitiesTableConfig') protected entitiesTableConfigValue: CalculatedFieldsTableConfig,
protected fb: FormBuilder,
protected cd: ChangeDetectorRef) {
protected cd: ChangeDetectorRef,
private entityService: EntityService) {
super(store, fb, entityValue, entitiesTableConfigValue, cd);
}
@ -111,9 +120,7 @@ export class AlarmRulesComponent extends EntityComponent<CalculatedFieldsTableEn
updateForm(entity: CalculatedFieldInfo) {
const { configuration = {} as CalculatedFieldConfiguration, type = CalculatedFieldType.ALARM, debugSettings = { failuresEnabled: true, allEnabled: true }, entityId = this.entityId, ...value } = entity ?? {};
setTimeout(() => {
this.entityForm.patchValue({ configuration, debugSettings, entityId, ...value }, {emitEvent: false});
});
this.entityForm.patchValue({ configuration, debugSettings, entityId, ...value }, {emitEvent: false});
if (!entityId) {
this.entityForm.get('configuration').disable({emitEvent: false});
}
@ -134,6 +141,7 @@ export class AlarmRulesComponent extends EntityComponent<CalculatedFieldsTableEn
if (this.isEditValue) {
this.entityForm.enable({emitEvent: false});
this.entityForm.get('entityId').disable({emitEvent: false});
this.getOwnerId(this.entityId);
} else {
this.entityForm.disable({emitEvent: false});
}
@ -172,4 +180,20 @@ export class AlarmRulesComponent extends EntityComponent<CalculatedFieldsTableEn
this.configFormGroup.patchValue({clearRule: clearAlarmRule});
}
getOwnerId(entityId: EntityId) {
if (entityId?.entityType === EntityType.DEVICE || entityId?.entityType === EntityType.ASSET) {
this.entityService.getEntity(entityId.entityType, entityId.id, { ignoreLoading: true, ignoreErrors: true }).subscribe(
(entity: AssetInfo | DeviceInfo) => {
if (this.isAssignedToCustomer(entity)) {
this.ownerId = entity.customerId;
}
}
);
}
}
private isAssignedToCustomer(entity: AssetInfo | DeviceInfo): boolean {
return entity && entity.customerId && entity.customerId.id !== NULL_UUID;
}
}

12
ui-ngx/src/app/modules/home/components/alarm-rules/cf-alarm-rule-condition-dialog.component.ts

@ -184,11 +184,13 @@ export class CfAlarmRuleConditionDialogComponent extends DialogComponent<CfAlarm
takeUntilDestroyed()
).subscribe((mode) => {
this.updateStaticValueValidator(AlarmRuleConditionType.DURATION, mode);
this.updateSpecText(this.conditionFormGroup.get('type').value);
});
this.repeatingDynamicModeControl.valueChanges.pipe(
takeUntilDestroyed()
).subscribe((mode) => {
this.updateStaticValueValidator(AlarmRuleConditionType.REPEATING, mode);
this.updateSpecText(this.conditionFormGroup.get('type').value);
});
this.updateValidators(this.conditionFormGroup.get('type').value ?? AlarmRuleConditionType.SIMPLE);
@ -289,20 +291,20 @@ export class CfAlarmRuleConditionDialogComponent extends DialogComponent<CfAlarm
duringText = this.translate.instant('timewindow.days', {days: value.staticValue});
break;
}
if (value.dynamicValueArgument) {
if (this.durationDynamicModeControl.value) {
this.specText = this.translate.instant('alarm-rule.condition-during-dynamic', {
attribute: `${value.dynamicValueArgument}`
attribute: `${value.dynamicValueArgument ?? ''}`
}) + ' ' + this.translate.instant(this.timeUnitTranslations.get(this.conditionFormGroup.get('unit').value)).toLowerCase();
} else {
this.specText = this.translate.instant('alarm-rule.condition-during', {
during: duringText
during: duringText.trim()
});
}
break;
case AlarmRuleConditionType.REPEATING:
if (count.dynamicValueArgument) {
if (this.repeatingDynamicModeControl.value) {
this.specText = this.translate.instant('alarm-rule.condition-repeat-times-dynamic', {
attribute: `${count.dynamicValueArgument}`
attribute: `${count.dynamicValueArgument ?? ''}`
});
} else {
this.specText = this.translate.instant('alarm-rule.condition-repeat-times',

12
ui-ngx/src/app/modules/home/components/alarm-rules/cf-alarm-rule-condition.component.html

@ -18,10 +18,9 @@
<div class="tb-alarm-rule-condition flex min-w-0 flex-col gap-4" [formGroup]="alarmRuleConditionFormGroup">
<div class="tb-form-row column-xs">
<div class="min-w-40 xs:min-w-fit">{{ 'alarm-rule.condition' | translate }}</div>
<button [disabled]="disabled"
type="button"
<button type="button"
class="tb-alarm-rule-condition-button"
mat-stroked-button [color]="conditionSet() && this.filtersArgumentsValid ? 'primary' : 'warn'"
mat-stroked-button [color]="conditionSet() || this.filtersArgumentsValid ? 'primary' : 'warn'"
(click)="openFilterDialog($event)">
<div class="flex items-center justify-between gap-2">
<tb-alarm-rule-filter-text [alarmRuleExpression]="alarmRuleConditionFormGroup.get('expression').value"
@ -35,15 +34,14 @@
</tb-alarm-rule-filter-text>
<mat-icon [color]="disabled ? '' : (conditionSet() && this.filtersArgumentsValid ? 'primary' : 'warn')"
class="tb-mat-20 tb-alarm-rule-schedule-edit-icon">
{{ conditionSet() ? 'edit' : 'add' }}
{{ disabled ? 'visibility' : (conditionSet() ? 'edit' : 'add') }}
</mat-icon>
</div>
</button>
</div>
<div class="tb-form-row column-xs">
<div class="min-w-40 xs:min-w-fit">{{ 'alarm-rule.schedule-title' | translate }}</div>
<button [disabled]="disabled"
[color]="schedulerArgumentsValid ? 'primary' : 'warn'"
<button [color]="schedulerArgumentsValid ? 'primary' : 'warn'"
type="button"
class="tb-alarm-rule-condition-button"
mat-stroked-button
@ -52,7 +50,7 @@
<span class="tb-alarm-rule-condition-label" tbTruncateWithTooltip [innerHTML]="scheduleText"></span>
<mat-icon [color]="disabled ? '' : (schedulerArgumentsValid ? 'primary' : 'warn')"
class="tb-mat-20 tb-alarm-rule-schedule-edit-icon">
edit
{{ disabled ? 'visibility' : 'edit' }}
</mat-icon>
</div>
</button>

47
ui-ngx/src/app/modules/home/components/alarm-rules/cf-alarm-rule-condition.component.ts

@ -137,23 +137,27 @@ export class CfAlarmRuleConditionComponent implements ControlValueAccessor, Vali
writeValue(value: AlarmRuleCondition): void {
this.modelValue = value;
this.updateConditionInfo();
if (value && !this.disabled) {
if (this.validate(this.alarmRuleConditionFormGroup)) {
this.onValidatorChange();
}
}
this.recalculateArgumentValidity();
}
ngOnChanges(changes: SimpleChanges) {
if (changes.arguments) {
if (changes.arguments && !changes.arguments.firstChange && this.modelValue && !this.disabled) {
if (this.validate(this.alarmRuleConditionFormGroup)) {
this.onValidatorChange();
}
if (changes.arguments && !changes.arguments.firstChange) {
this.recalculateArgumentValidity();
}
}
}
private recalculateArgumentValidity(): void {
if (!this.modelValue || !this.arguments) {
this.filtersArgumentsValid = true;
this.schedulerArgumentsValid = true;
return;
}
this.filtersArgumentsValid = this.areFilterAndPredicateArgumentsValid(this.modelValue, this.arguments);
this.schedulerArgumentsValid = this.isScheduleArgumentValid(this.modelValue, Object.keys(this.arguments));
}
private isScheduleArgumentValid(obj: any, validArguments: string[]): boolean {
const arg = obj?.schedule?.dynamicValueArgument;
return !arg || validArguments.includes(arg);
@ -177,21 +181,14 @@ export class CfAlarmRuleConditionComponent implements ControlValueAccessor, Vali
return true;
}
public conditionSet() {
return this.modelValue && (this.modelValue.expression?.expression || this.modelValue.expression?.filters);
public conditionSet(): boolean {
return !!this.modelValue && !!(this.modelValue.expression?.expression || this.modelValue.expression?.filters);
}
public validate(control: AbstractControl): ValidationErrors | null {
this.filtersArgumentsValid = this.areFilterAndPredicateArgumentsValid(this.modelValue, this.arguments);
this.schedulerArgumentsValid = this.isScheduleArgumentValid(this.modelValue, Object.keys(this.arguments));
this.onValidatorChange = () => {
control.updateValueAndValidity({ emitEvent: !this.disabled });
};
return this.conditionSet() && this.filtersArgumentsValid && this.schedulerArgumentsValid ? null : {
alarmRuleCondition: {
valid: false,
}
};
const hasCondition = this.conditionSet();
const argsValid = this.filtersArgumentsValid && this.schedulerArgumentsValid;
return (hasCondition && argsValid) ? null : { alarmRuleCondition: { valid: false } };
}
public openFilterDialog($event: Event) {
@ -212,7 +209,6 @@ export class CfAlarmRuleConditionComponent implements ControlValueAccessor, Vali
if (result) {
this.modelValue = {...this.modelValue, ...result};
this.updateModel();
this.cd.detectChanges();
}
});
}
@ -278,10 +274,10 @@ export class CfAlarmRuleConditionComponent implements ControlValueAccessor, Vali
private updateModel() {
this.updateConditionInfo();
this.recalculateArgumentValidity();
this.propagateChange(this.modelValue);
if (this.modelValue) {
this.onValidatorChange();
}
this.onValidatorChange();
this.cd.detectChanges();
}
public openScheduleDialog($event: Event) {
@ -301,7 +297,6 @@ export class CfAlarmRuleConditionComponent implements ControlValueAccessor, Vali
if (result) {
this.modelValue.schedule = result;
this.updateModel();
this.cd.detectChanges();
}
});
}

26
ui-ngx/src/app/modules/home/components/calculated-fields/calculated-field.component.ts

@ -39,6 +39,10 @@ import {
} from '@home/components/calculated-fields/calculated-fields-table-config';
import { TenantId } from '@shared/models/id/tenant-id';
import { CalculatedFieldFormService } from '@core/services/calculated-field-form.service';
import { AssetInfo } from '@shared/models/asset.models';
import { DeviceInfo } from '@shared/models/device.models';
import { NULL_UUID } from '@shared/models/id/has-uuid';
import { EntityService } from '@core/http/entity.service';
@Component({
selector: 'tb-calculated-field',
@ -55,7 +59,7 @@ export class CalculatedFieldComponent extends EntityComponent<CalculatedFieldsTa
disabledConfiguration = false;
readonly ownerId = new TenantId(getCurrentAuthUser(this.store).tenantId);
ownerId = new TenantId(getCurrentAuthUser(this.store).tenantId);
readonly tenantId = getCurrentAuthUser(this.store).tenantId;
readonly EntityType = EntityType;
readonly calculatedFieldsEntityTypeList = calculatedFieldsEntityTypeList;
@ -71,7 +75,8 @@ export class CalculatedFieldComponent extends EntityComponent<CalculatedFieldsTa
@Inject('entity') protected entityValue: CalculatedFieldInfo,
@Inject('entitiesTableConfig') protected entitiesTableConfigValue: CalculatedFieldsTableConfig,
protected fb: FormBuilder,
protected cd: ChangeDetectorRef) {
protected cd: ChangeDetectorRef,
private entityService: EntityService) {
super(store, fb, entityValue, entitiesTableConfigValue, cd);
}
@ -137,9 +142,26 @@ export class CalculatedFieldComponent extends EntityComponent<CalculatedFieldsTa
if (this.isEditValue) {
this.entityForm.enable({emitEvent: false});
this.entityForm.get('entityId').disable({emitEvent: false});
this.getOwnerId(this.entityId);
} else {
this.entityForm.disable({emitEvent: false});
}
}
}
getOwnerId(entityId: EntityId) {
if (entityId?.entityType === EntityType.DEVICE || entityId?.entityType === EntityType.ASSET) {
this.entityService.getEntity(entityId.entityType, entityId.id, { ignoreLoading: true, ignoreErrors: true }).subscribe(
(entity: AssetInfo | DeviceInfo) => {
if (this.isAssignedToCustomer(entity)) {
this.ownerId = entity.customerId;
}
}
);
}
}
private isAssignedToCustomer(entity: AssetInfo | DeviceInfo): boolean {
return entity && entity.customerId && entity.customerId.id !== NULL_UUID;
}
}

2
ui-ngx/src/app/modules/home/components/calculated-fields/calculated-fields-table-config.ts

@ -333,7 +333,7 @@ export class CalculatedFieldsTableConfig extends EntityTableConfig<CalculatedFie
.pipe(
filter(Boolean),
switchMap(calculatedField => {
if (calculatedField.type === CalculatedFieldType.ALARM) {
if (calculatedField.type === CalculatedFieldType.ALARM || !CalculatedFieldType[calculatedField.type]) {
this.store.dispatch(new ActionNotificationShow({
message: this.translate.instant('calculated-fields.hint.import-invalid-calculated-field-type'),
type: 'error',

6
ui-ngx/src/app/modules/home/components/calculated-fields/components/dialog/calculated-field-dialog.component.html

@ -94,7 +94,7 @@
[class.tb-form-panel-disabled]="disabledConfiguration"
[entityId]="entityId"
[entityName]="entityName"
[ownerId]="data.ownerId"
[ownerId]="ownerId"
[tenantId]="data.tenantId"
></tb-geofencing-configuration>
}
@ -104,7 +104,7 @@
[entityId]="entityId"
[entityName]="entityName"
[tenantId]="data.tenantId"
[ownerId]="data.ownerId"
[ownerId]="ownerId"
[testScript]="onTestScript.bind(this)"
></tb-propagation-configuration>
}
@ -130,7 +130,7 @@
[class.tb-form-panel-disabled]="disabledConfiguration"
[entityId]="entityId"
[entityName]="entityName"
[ownerId]="data.ownerId"
[ownerId]="ownerId"
[tenantId]="data.tenantId"
[isScript]="fieldFormGroup.get('type').value === CalculatedFieldType.SCRIPT"
[testScript]="onTestScript.bind(this)"

12
ui-ngx/src/app/modules/home/components/calculated-fields/components/dialog/calculated-field-dialog.component.ts

@ -39,6 +39,9 @@ import { deepTrim } from '@core/utils';
import { BaseData } from '@shared/models/base-data';
import { CalculatedFieldFormService } from '@core/services/calculated-field-form.service';
import { FormGroup } from '@angular/forms';
import { AssetInfo } from '@shared/models/asset.models';
import { DeviceInfo } from '@shared/models/device.models';
import { NULL_UUID } from '@shared/models/id/has-uuid';
export interface CalculatedFieldDialogData {
value?: CalculatedField;
@ -69,6 +72,7 @@ export class CalculatedFieldDialogComponent extends DialogComponent<CalculatedFi
} : null;
entityName = this.data.entityName;
ownerId = this.data.ownerId;
disabledConfiguration = false;
isLoading = false;
@ -104,6 +108,7 @@ export class CalculatedFieldDialogComponent extends DialogComponent<CalculatedFi
this.fieldFormGroup.get('configuration').disable({emitEvent: false});
} else {
this.fieldFormGroup.get('configuration').enable({emitEvent: false});
this.fieldFormGroup.get('configuration').updateValueAndValidity({emitEvent: false});
}
});
}
@ -147,6 +152,9 @@ export class CalculatedFieldDialogComponent extends DialogComponent<CalculatedFi
changeEntity(entity: BaseData<EntityId>): void {
this.entityName = entity.name;
if (this.isAssignedToCustomer(entity as AssetInfo | DeviceInfo)) {
this.ownerId = (entity as AssetInfo | DeviceInfo).customerId;
}
}
get entityId(): EntityId {
@ -163,4 +171,8 @@ export class CalculatedFieldDialogComponent extends DialogComponent<CalculatedFi
this.disabledConfiguration = true;
}
}
private isAssignedToCustomer(entity: AssetInfo | DeviceInfo): boolean {
return entity && entity.customerId && entity.customerId.id !== NULL_UUID;
}
}

1
ui-ngx/src/app/modules/home/components/calculated-fields/components/geofencing-configuration/calculated-field-geofencing-zone-groups-panel.component.ts

@ -303,6 +303,7 @@ export class CalculatedFieldGeofencingZoneGroupsPanelComponent implements OnInit
removeKey(index: number) {
this.levelsFormArray().removeAt(index);
this.levelsFormArray().markAsDirty();
}
addKey() {

14
ui-ngx/src/app/modules/home/components/calculated-fields/components/geofencing-configuration/geofencing-configuration.component.ts

@ -14,7 +14,7 @@
/// limitations under the License.
///
import { Component, forwardRef, Input, OnInit } from '@angular/core';
import { Component, forwardRef, Input, OnChanges, SimpleChanges } from '@angular/core';
import {
ControlValueAccessor,
FormBuilder,
@ -58,7 +58,7 @@ import { EntityId } from '@shared/models/id/entity-id';
}
],
})
export class GeofencingConfigurationComponent implements ControlValueAccessor, Validator, OnInit {
export class GeofencingConfigurationComponent implements ControlValueAccessor, Validator, OnChanges {
@Input({required: true})
entityId: EntityId;
@ -113,8 +113,14 @@ export class GeofencingConfigurationComponent implements ControlValueAccessor, V
})
}
ngOnInit() {
this.currentEntityFilter = getCalculatedFieldCurrentEntityFilter(this.entityName, this.entityId);
ngOnChanges(changes: SimpleChanges) {
if (changes.entityName || changes.entityId) {
const entityNameChanges = changes.entityName;
const entityIdChanges = changes.entityId;
if ((entityNameChanges?.currentValue !== entityNameChanges?.previousValue) || (entityIdChanges?.currentValue !== entityIdChanges?.previousValue)) {
this.currentEntityFilter = getCalculatedFieldCurrentEntityFilter(this.entityName, this.entityId);
}
}
}
validate(): ValidationErrors | null {

1
ui-ngx/src/app/shared/components/entity/entity-select.component.html

@ -30,6 +30,7 @@
formControlName="entityType">
</tb-entity-type-select>
<tb-entity-autocomplete
#entityAutocompleteComponent
*ngIf="modelValue.entityType && !entityTypeNullUUID.has(modelValue.entityType)"
class="flex-1"
[appearance]="appearance"

9
ui-ngx/src/app/shared/components/entity/entity-select.component.ts

@ -14,7 +14,7 @@
/// limitations under the License.
///
import { Component, DestroyRef, EventEmitter, forwardRef, Input, OnInit, Output } from '@angular/core';
import { Component, DestroyRef, EventEmitter, forwardRef, Input, OnInit, Output, ViewChild } from '@angular/core';
import { ControlValueAccessor, NG_VALUE_ACCESSOR, UntypedFormBuilder, UntypedFormGroup } from '@angular/forms';
import { Store } from '@ngrx/store';
import { AppState } from '@core/core.state';
@ -27,6 +27,7 @@ import { coerceBoolean } from '@shared/decorators/coercion';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
import { MatFormFieldAppearance } from '@angular/material/form-field';
import { BaseData } from '@shared/models/base-data';
import { EntityAutocompleteComponent } from '@shared/components/entity/entity-autocomplete.component';
@Component({
selector: 'tb-entity-select',
@ -40,6 +41,8 @@ import { BaseData } from '@shared/models/base-data';
})
export class EntitySelectComponent implements ControlValueAccessor, OnInit {
@ViewChild('entityAutocompleteComponent') entityAutocompleteComponent!: EntityAutocompleteComponent;
entitySelectFormGroup: UntypedFormGroup;
modelValue: EntityId = {entityType: null, id: null};
@ -204,4 +207,8 @@ export class EntitySelectComponent implements ControlValueAccessor, OnInit {
changeEntity(entity: BaseData<EntityId>): void {
this.entityChanged.emit(entity);
}
entityAutocompleteMarkAsTouched() {
this.entityAutocompleteComponent.markAsTouched();
}
}

4
ui-ngx/src/app/shared/components/string-items-list.component.html

@ -52,7 +52,9 @@
@for (value of filteredValues | async; track value.value) {
<mat-option [value]="value"><span [innerHTML]="value.name | highlight:searchText"></span></mat-option>
} @empty {
<mat-option [value]="null">{{ 'common.not-found' | translate }}</mat-option>
@if (!allowUserValue) {
<mat-option [value]="null">{{ 'common.not-found' | translate }}</mat-option>
}
}
</mat-autocomplete>
<mat-hint [hidden]="!hint">

4
ui-ngx/src/app/shared/components/string-items-list.component.ts

@ -210,8 +210,8 @@ export class StringItemsListComponent implements ControlValueAccessor, OnInit {
addOnBlur(event: FocusEvent) {
const target: HTMLElement = event.relatedTarget as HTMLElement;
if (target && target.tagName !== 'MAT-OPTION') {
this.addItem(this.stringItemInput.nativeElement.value ?? '')
if ((target && target.tagName !== 'MAT-OPTION') || this.allowUserValue) {
this.addItem(this.stringItemInput.nativeElement.value ?? '');
}
this.onTouched();
}

2
ui-ngx/src/app/shared/models/calculated-field.models.ts

@ -525,7 +525,7 @@ export const ArgumentEntityTypeParamsMap =new Map<ArgumentEntityType, ArgumentEn
])
export const getCalculatedFieldCurrentEntityFilter = (entityName: string, entityId: EntityId) => {
switch (entityId.entityType) {
switch (entityId?.entityType) {
case EntityType.ASSET_PROFILE:
return {
assetTypes: [entityName],

2
ui-ngx/src/assets/locale/locale.constant-en_US.json

@ -1434,7 +1434,7 @@
"condition-during": "During {{during}}",
"condition-during-dynamic": "During \"{{ attribute }}\"",
"condition-repeat-times": "Repeats { count, plural, =1 {1 time} other {# times} }",
"condition-repeat-times-dynamic": "Repeats \"{{ attribute }}\"",
"condition-repeat-times-dynamic": "Repeats \"{{ attribute }}\" times",
"filter-preview": "Filter preview",
"condition-settings": "Condition settings",
"static": "Static",

Loading…
Cancel
Save