diff --git a/ui-ngx/src/app/core/api/alias-controller.ts b/ui-ngx/src/app/core/api/alias-controller.ts index d48bcb574b..de6863ee56 100644 --- a/ui-ngx/src/app/core/api/alias-controller.ts +++ b/ui-ngx/src/app/core/api/alias-controller.ts @@ -314,10 +314,14 @@ export class AliasController implements IAliasController { || newDatasource.type === DatasourceType.entityCount || newDatasource.type === DatasourceType.alarmCount) { if (newDatasource.filterId) { - newDatasource.keyFilters = this.getKeyFilters(newDatasource.filterId); const filterInfo = this.getFilterInfo(newDatasource.filterId); - if (filterInfo?.keyFiltersOperation) { - newDatasource.keyFiltersOperation = filterInfo.keyFiltersOperation; + if (filterInfo) { + newDatasource.keyFilters = filterInfoToKeyFilters(filterInfo); + if (filterInfo.keyFiltersOperation) { + newDatasource.keyFiltersOperation = filterInfo.keyFiltersOperation; + } + } else { + newDatasource.keyFilters = []; } } if (newDatasource.type === DatasourceType.alarmCount) { diff --git a/ui-ngx/src/app/core/api/entity-data-subscription.ts b/ui-ngx/src/app/core/api/entity-data-subscription.ts index e367ae8faa..6f7949d259 100644 --- a/ui-ngx/src/app/core/api/entity-data-subscription.ts +++ b/ui-ngx/src/app/core/api/entity-data-subscription.ts @@ -358,7 +358,6 @@ export class EntityDataSubscription { this.subscriber = new TelemetrySubscriber(this.telemetryService); this.dataCommand = new EntityDataCmd(); - let keyFilters = this.entityDataSubscriptionOptions.keyFilters; if (this.entityDataSubscriptionOptions.additionalKeyFilters) { if (keyFilters) { diff --git a/ui-ngx/src/app/modules/home/components/filter/filter-dialog.component.html b/ui-ngx/src/app/modules/home/components/filter/filter-dialog.component.html index 6865bfd9c3..0cd0ea729e 100644 --- a/ui-ngx/src/app/modules/home/components/filter/filter-dialog.component.html +++ b/ui-ngx/src/app/modules/home/components/filter/filter-dialog.component.html @@ -16,64 +16,61 @@ -->
- +

{{ (isAdd ? 'filter.add' : 'filter.edit') | translate }}

-
- - -
-
-
-
- - filter.name - - - {{ 'filter.name-required' | translate }} - - - {{ 'filter.duplicate-filter' | translate }} - - -
- - - -
-
-
-
filter.key-filters
- - {{ complexOperationTranslationMap.get(ComplexOperation.AND) | translate }} - {{ complexOperationTranslationMap.get(ComplexOperation.OR) | translate }} - -
- - -
-
+
+
+ + filter.name + + @if (filterFormGroup.controls.filter.hasError('required')) { + {{ 'filter.name-required' | translate }} + } + @if (filterFormGroup.controls.filter.hasError('duplicateFilterName')) { + {{ 'filter.duplicate-filter' | translate }} + } + + +
+ + + {{ complexOperationTranslationMap.get(ComplexOperation.AND) | translate | titlecase }} + + {{ complexOperationTranslationMap.get(ComplexOperation.OR) | translate | titlecase }} + + +
diff --git a/ui-ngx/src/app/modules/home/components/filter/filter-dialog.component.scss b/ui-ngx/src/app/modules/home/components/filter/filter-dialog.component.scss index 7b620f8c2f..2fd238043d 100644 --- a/ui-ngx/src/app/modules/home/components/filter/filter-dialog.component.scss +++ b/ui-ngx/src/app/modules/home/components/filter/filter-dialog.component.scss @@ -14,15 +14,4 @@ * limitations under the License. */ :host { - .tb-editable-switch { - padding-left: 10px; - - .editable-switch { - margin: 0; - } - - .editable-label { - margin: 5px 0; - } - } } diff --git a/ui-ngx/src/app/modules/home/components/filter/filter-dialog.component.ts b/ui-ngx/src/app/modules/home/components/filter/filter-dialog.component.ts index 334ce90931..6db4a76822 100644 --- a/ui-ngx/src/app/modules/home/components/filter/filter-dialog.component.ts +++ b/ui-ngx/src/app/modules/home/components/filter/filter-dialog.component.ts @@ -14,26 +14,23 @@ /// limitations under the License. /// -import { Component, Inject, OnInit, SkipSelf } from '@angular/core'; -import { ErrorStateMatcher } from '@angular/material/core'; +import { Component, Inject } from '@angular/core'; import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; import { Store } from '@ngrx/store'; import { AppState } from '@core/core.state'; -import { - UntypedFormBuilder, - UntypedFormControl, - UntypedFormGroup, - FormGroupDirective, - NgForm, - ValidatorFn, - Validators -} from '@angular/forms'; +import { FormBuilder, FormControl, FormGroup, ValidatorFn, Validators } from '@angular/forms'; import { Router } from '@angular/router'; import { DialogComponent } from '@app/shared/components/dialog.component'; import { UtilsService } from '@core/services/utils.service'; -import { TranslateService } from '@ngx-translate/core'; -import { ComplexOperation, complexOperationTranslationMap, Filter, Filters } from '@shared/models/query/query.models'; +import { + ComplexOperation, + complexOperationTranslationMap, + Filter, + FilterInfo, + Filters +} from '@shared/models/query/query.models'; import { getCurrentAuthState } from '@core/auth/auth.selectors'; +import { FormControlsFrom } from '@shared/models/tenant.model'; export interface FilterDialogData { isAdd: boolean; @@ -42,36 +39,30 @@ export interface FilterDialogData { } @Component({ - selector: 'tb-filter-dialog', - templateUrl: './filter-dialog.component.html', - providers: [{ provide: ErrorStateMatcher, useExisting: FilterDialogComponent }], - styleUrls: ['./filter-dialog.component.scss'], - standalone: false + selector: 'tb-filter-dialog', + templateUrl: './filter-dialog.component.html', + styleUrls: ['./filter-dialog.component.scss'], + standalone: false }) -export class FilterDialogComponent extends DialogComponent - implements OnInit, ErrorStateMatcher { +export class FilterDialogComponent extends DialogComponent { isAdd: boolean; - filters: Array; - - filter: Filter; - - filterFormGroup: UntypedFormGroup; - submitted = false; + filterFormGroup: FormGroup>; ComplexOperation = ComplexOperation; complexOperationTranslationMap = complexOperationTranslationMap; allowKeyFiltersOrConditions: boolean; + private readonly filter: Filter; + private filters: Array; + constructor(protected store: Store, protected router: Router, @Inject(MAT_DIALOG_DATA) public data: FilterDialogData, - @SkipSelf() private errorStateMatcher: ErrorStateMatcher, - public dialogRef: MatDialogRef, - private fb: UntypedFormBuilder, - private utils: UtilsService, - public translate: TranslateService) { + protected dialogRef: MatDialogRef, + private fb: FormBuilder, + private utils: UtilsService) { super(store, router, dialogRef); this.isAdd = data.isAdd; if (Array.isArray(data.filters)) { @@ -102,15 +93,15 @@ export class FilterDialogComponent extends DialogComponent { + return (c: FormControl) => { const newFilter = c.value.trim(); const found = this.filters.find((filter) => filter.filter === newFilter); if (found) { @@ -126,13 +117,11 @@ export class FilterDialogComponent extends DialogComponent FilterTextComponent), - multi: true - } - ], - standalone: false + selector: 'tb-filter-text', + templateUrl: './filter-text.component.html', + styleUrls: ['./filter-text.component.scss'], + providers: [ + { + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => FilterTextComponent), + multi: true + } + ], + standalone: false }) -export class FilterTextComponent implements ControlValueAccessor, OnInit, OnChanges { +export class FilterTextComponent implements ControlValueAccessor, OnChanges { - private requiredValue: boolean; - get required(): boolean { - return this.requiredValue; - } @Input() - set required(value: boolean) { - this.requiredValue = coerceBooleanProperty(value); - } + @coerceBoolean() + required = false; @Input() disabled: boolean; @@ -66,26 +60,20 @@ export class FilterTextComponent implements ControlValueAccessor, OnInit, OnChan public filterText: string; private currentValue: Array; - private propagateChange = (v: any) => { }; - constructor(private dialog: MatDialog, - private fb: UntypedFormBuilder, - private translate: TranslateService, + constructor(private translate: TranslateService, private datePipe: DatePipe) { } - registerOnChange(fn: any): void { - this.propagateChange = fn; - } - - registerOnTouched(fn: any): void { + registerOnChange(_fn: any): void { } - ngOnInit() { + registerOnTouched(_fn: any): void { } ngOnChanges(changes: SimpleChanges) { - if (changes.operation && !changes.operation.firstChange) { + if (changes.operation && !changes.operation.firstChange + && changes.operation.currentValue !== changes.operation.previousValue) { this.updateFilterText(this.currentValue); } } diff --git a/ui-ngx/src/app/modules/home/components/filter/key-filter-list.component.html b/ui-ngx/src/app/modules/home/components/filter/key-filter-list.component.html index a772c765fd..8bfd7792d5 100644 --- a/ui-ngx/src/app/modules/home/components/filter/key-filter-list.component.html +++ b/ui-ngx/src/app/modules/home/components/filter/key-filter-list.component.html @@ -15,78 +15,86 @@ limitations under the License. --> -
- - - - -
filter.key-filters
-
-
-
- -
- - -   -   -
-
- -
-
-
- {{ complexOperationTranslationMap.get(operation) | translate }} +
+
+
+
filter.key-filters
+ +
+ @if (keyFiltersFormArray.length) { +
+
+ +
+
filter.key-name
+
filter.key-type.key-type
+   +  
-
-
-
{{ keyFilterControl.value.key.key }}
-
{{ entityKeyTypeTranslations.get(keyFilterControl.value.key.type) | translate }}
- - +
+ +
+ @for (keyFilterControl of keyFiltersFormArray.controls; track keyFilterControl; let index = $index) { +
+
+ @if (index) { +
+ {{ complexOperationTranslationMap.get(operation) | translate }} +
+ } +
+
+
+
{{ keyFilterControl.value.key.key }}
+
{{ entityKeyTypeTranslations.get(keyFilterControl.value.key.type) | translate }}
+ + +
+
- -
+ }
- filter.no-key-filters -
-
- -
- - +
+ } @else { + filter.no-key-filters + } +
+ +
+
+
+ - -
filter.preview
-
+ {{ 'filter.preview' | translate }}
-
- -
+ + @if (keyFiltersFormArray.length) { + + } @else { + filter.no-filter-text + } +
- +
diff --git a/ui-ngx/src/app/modules/home/components/filter/key-filter-list.component.scss b/ui-ngx/src/app/modules/home/components/filter/key-filter-list.component.scss index 2d1bcc923a..9ef70c8845 100644 --- a/ui-ngx/src/app/modules/home/components/filter/key-filter-list.component.scss +++ b/ui-ngx/src/app/modules/home/components/filter/key-filter-list.component.scss @@ -13,30 +13,45 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +@import "../scss/constants"; + :host { - .key-filter-list { + .filter-title { + padding: 12px 0; + font-size: 14px; + font-weight: 500; + } + .no-data-found { + height: 50px; + font-size: 16px; + } + .filter-list { overflow: auto; max-height: 300px; - .no-data-found { - height: 50px; + + &-divider { + border-top: 1px solid rgba(0, 0, 0, 0.12); + } + + .filters-text { + font-size: 14px; } } .filters-operation { - margin-top: -18px; - color: #666; - font-weight: 500; - } - .tb-filter-preview { - padding: 8px; - border: 1px groove rgba(0, 0, 0, .25); - border-radius: 4px; - } -} - -:host ::ng-deep { - .tb-filter-preview { - .tb-filter-text { - max-height: 200px; + display: flex; + justify-content: center; + margin-top: -14px; + &-container { + background-color: white; + } + &-label { + font-size: 15px; + font-weight: 400; + color: $tb-primary-color; + padding: 0 8px; + border-radius: 4px; + border: 1px solid rgba($tb-primary-color, 0.32); + background-color: rgba($tb-primary-color, 0.04); } } } diff --git a/ui-ngx/src/app/modules/home/components/filter/key-filter-list.component.ts b/ui-ngx/src/app/modules/home/components/filter/key-filter-list.component.ts index 8951764a4b..73804faa7a 100644 --- a/ui-ngx/src/app/modules/home/components/filter/key-filter-list.component.ts +++ b/ui-ngx/src/app/modules/home/components/filter/key-filter-list.component.ts @@ -14,26 +14,26 @@ /// limitations under the License. /// -import { Component, forwardRef, Input, OnDestroy, OnInit } from '@angular/core'; +import { Component, DestroyRef, forwardRef, Input, OnInit } from '@angular/core'; import { - AbstractControl, ControlValueAccessor, - UntypedFormArray, - UntypedFormBuilder, - UntypedFormControl, - UntypedFormGroup, + FormArray, + FormBuilder, + FormControl, NG_VALIDATORS, NG_VALUE_ACCESSOR, ValidationErrors, Validator, Validators } from '@angular/forms'; -import { Observable, Subject } from 'rxjs'; +import { Observable } from 'rxjs'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { ComplexOperation, complexOperationTranslationMap, EntityKeyType, entityKeyTypeTranslationMap, + KeyFilter, KeyFilterInfo, keyFilterInfosToKeyFilters } from '@shared/models/query/query.models'; @@ -41,27 +41,26 @@ import { MatDialog } from '@angular/material/dialog'; import { deepClone } from '@core/utils'; import { KeyFilterDialogComponent, KeyFilterDialogData } from '@home/components/filter/key-filter-dialog.component'; import { EntityId } from '@shared/models/id/entity-id'; -import { takeUntil } from 'rxjs/operators'; @Component({ - selector: 'tb-key-filter-list', - templateUrl: './key-filter-list.component.html', - styleUrls: ['./key-filter-list.component.scss'], - providers: [ - { - provide: NG_VALUE_ACCESSOR, - useExisting: forwardRef(() => KeyFilterListComponent), - multi: true - }, - { - provide: NG_VALIDATORS, - useExisting: forwardRef(() => KeyFilterListComponent), - multi: true - } - ], - standalone: false + selector: 'tb-key-filter-list', + templateUrl: './key-filter-list.component.html', + styleUrls: ['./key-filter-list.component.scss'], + providers: [ + { + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => KeyFilterListComponent), + multi: true + }, + { + provide: NG_VALIDATORS, + useExisting: forwardRef(() => KeyFilterListComponent), + multi: true + } + ], + standalone: false }) -export class KeyFilterListComponent implements ControlValueAccessor, Validator, OnInit, OnDestroy { +export class KeyFilterListComponent implements ControlValueAccessor, Validator, OnInit { @Input() disabled: boolean; @@ -77,39 +76,28 @@ export class KeyFilterListComponent implements ControlValueAccessor, Validator, complexOperationTranslationMap = complexOperationTranslationMap; - keyFilterListFormGroup: UntypedFormGroup; - entityKeyTypeTranslations = entityKeyTypeTranslationMap; - keyFiltersControl: UntypedFormControl; + keyFiltersFormArray: FormArray>; + + keyFiltersControl: FormControl>; - private destroy$ = new Subject(); private propagateChange = null; - constructor(private fb: UntypedFormBuilder, - private dialog: MatDialog) { + constructor(private fb: FormBuilder, + private dialog: MatDialog, + private destroyRef: DestroyRef) { } ngOnInit(): void { - this.keyFilterListFormGroup = this.fb.group({ - keyFilters: this.fb.array([]) - }); + this.keyFiltersFormArray = this.fb.array>([]); this.keyFiltersControl = this.fb.control(null); - this.keyFilterListFormGroup.valueChanges.pipe( - takeUntil(this.destroy$) + this.keyFiltersFormArray.valueChanges.pipe( + takeUntilDestroyed(this.destroyRef) ).subscribe(() => this.updateModel()); } - ngOnDestroy() { - this.destroy$.next(); - this.destroy$.complete(); - } - - get keyFiltersFormArray(): UntypedFormArray { - return this.keyFilterListFormGroup.get('keyFilters') as UntypedFormArray; - } - registerOnChange(fn: any): void { this.propagateChange = fn; } @@ -120,61 +108,61 @@ export class KeyFilterListComponent implements ControlValueAccessor, Validator, setDisabledState?(isDisabled: boolean): void { this.disabled = isDisabled; if (this.disabled) { - this.keyFilterListFormGroup.disable({emitEvent: false}); + this.keyFiltersFormArray.disable({emitEvent: false}); this.keyFiltersControl.disable({emitEvent: false}); } else { - this.keyFilterListFormGroup.enable({emitEvent: false}); + this.keyFiltersFormArray.enable({emitEvent: false}); this.keyFiltersControl.enable({emitEvent: false}); } } validate(): ValidationErrors | null { - return this.keyFilterListFormGroup.valid && this.keyFiltersControl.valid ? null : { + return this.keyFiltersFormArray.valid && this.keyFiltersControl.valid ? null : { keyFilterList: {valid: false} }; } writeValue(keyFilters: Array): void { - if (keyFilters.length === this.keyFiltersFormArray.length) { + if (keyFilters?.length === this.keyFiltersFormArray.length) { this.keyFiltersFormArray.patchValue(keyFilters, {emitEvent: false}); } else { - const keyFilterControls: Array = []; + this.keyFiltersFormArray.clear({emitEvent: false}); if (keyFilters) { for (const keyFilter of keyFilters) { - keyFilterControls.push(this.fb.control(keyFilter, [Validators.required])); + this.keyFiltersFormArray.push( + this.fb.control(keyFilter, [Validators.required]), + {emitEvent: false} + ); } } - this.keyFilterListFormGroup.setControl('keyFilters', this.fb.array(keyFilterControls), {emitEvent: false}); if (this.disabled) { - this.keyFilterListFormGroup.disable({emitEvent: false}); + this.keyFiltersFormArray.disable({emitEvent: false}); } else { - this.keyFilterListFormGroup.enable({emitEvent: false}); + this.keyFiltersFormArray.enable({emitEvent: false}); } } const keyFiltersArray = keyFilterInfosToKeyFilters(keyFilters); this.keyFiltersControl.patchValue(keyFiltersArray, {emitEvent: false}); } - public removeKeyFilter(index: number) { - (this.keyFilterListFormGroup.get('keyFilters') as UntypedFormArray).removeAt(index); + removeKeyFilter(index: number) { + this.keyFiltersFormArray.removeAt(index); } - public addKeyFilter() { - const keyFiltersFormArray = this.keyFilterListFormGroup.get('keyFilters') as UntypedFormArray; + addKeyFilter() { this.openKeyFilterDialog(null).subscribe((result) => { if (result) { - keyFiltersFormArray.push(this.fb.control(result, [Validators.required])); + this.keyFiltersFormArray.push(this.fb.control(result, [Validators.required])); } }); } - public editKeyFilter(index: number) { - const keyFilter: KeyFilterInfo = - (this.keyFilterListFormGroup.get('keyFilters') as UntypedFormArray).at(index).value; + editKeyFilter(index: number) { + const keyFilter = this.keyFiltersFormArray.at(index).value; this.openKeyFilterDialog(keyFilter).subscribe( (result) => { if (result) { - (this.keyFilterListFormGroup.get('keyFilters') as UntypedFormArray).at(index).patchValue(result); + this.keyFiltersFormArray.at(index).patchValue(result); } } ); @@ -210,12 +198,8 @@ export class KeyFilterListComponent implements ControlValueAccessor, Validator, } private updateModel() { - const keyFilters: Array = this.keyFilterListFormGroup.getRawValue().keyFilters; - if (keyFilters.length) { - this.propagateChange(keyFilters); - } else { - this.propagateChange(null); - } + const keyFilters = this.keyFiltersFormArray.getRawValue(); + this.propagateChange(keyFilters.length ? keyFilters : null); const keyFiltersArray = keyFilterInfosToKeyFilters(keyFilters); this.keyFiltersControl.patchValue(keyFiltersArray, {emitEvent: false}); } diff --git a/ui-ngx/src/app/modules/home/components/filter/user-filter-dialog.component.html b/ui-ngx/src/app/modules/home/components/filter/user-filter-dialog.component.html index 8ca43427e9..f1836ae17e 100644 --- a/ui-ngx/src/app/modules/home/components/filter/user-filter-dialog.component.html +++ b/ui-ngx/src/app/modules/home/components/filter/user-filter-dialog.component.html @@ -15,64 +15,61 @@ limitations under the License. --> - - + +

{{ filter.filter | customTranslate }}

-
- -
-
-
-
- - - {{ userInputControl.get('label').value | customTranslate }} - - - - - - {{ userInputControl.get('label').value | customTranslate }} - -
- {{ userInputControl.get('unitSymbol').value }} + @for (userInputControl of userInputsFormArray.controls; track userInputControl) { + @switch (userInputControl.controls.valueType.value) { + @case (valueTypeEnum.STRING) { + + {{ userInputControl.controls.label.value | customTranslate }} + + + } + @case (valueTypeEnum.NUMERIC) { + + {{ userInputControl.controls.label.value | customTranslate }} + + @if (userInputControl.controls.unitSymbol.value) { +
+ {{ userInputControl.controls.unitSymbol.value }}
-
- - - - - - - - {{ userInputControl.get('label').value | customTranslate }} - - -
-
-
+ } + + } + @case (valueTypeEnum.DATE_TIME) { + + } + @case (valueTypeEnum.BOOLEAN) { + + + {{ userInputControl.controls.label.value | customTranslate }} + + + } + } + }
diff --git a/ui-ngx/src/app/modules/home/components/filter/user-filter-dialog.component.scss b/ui-ngx/src/app/modules/home/components/filter/user-filter-dialog.component.scss index d3b1d316ab..552c49b56a 100644 --- a/ui-ngx/src/app/modules/home/components/filter/user-filter-dialog.component.scss +++ b/ui-ngx/src/app/modules/home/components/filter/user-filter-dialog.component.scss @@ -14,14 +14,14 @@ * limitations under the License. */ :host ::ng-deep { - .user-filter-dialog { - .mat-mdc-form-field.mat-mdc-form-field-has-icon-suffix.mat-form-field-hide-placeholder { + .numeric-field { + &.mat-mdc-form-field-has-icon-suffix.mat-form-field-hide-placeholder { .mat-mdc-form-field-icon-suffix { place-self: center; } } - .mat-mdc-form-field.mat-mdc-form-field-has-icon-suffix { + &.mat-mdc-form-field-has-icon-suffix { .mat-mdc-form-field-icon-suffix { place-self: baseline; } diff --git a/ui-ngx/src/app/modules/home/components/filter/user-filter-dialog.component.ts b/ui-ngx/src/app/modules/home/components/filter/user-filter-dialog.component.ts index 6e068fdcf3..59231f8b80 100644 --- a/ui-ngx/src/app/modules/home/components/filter/user-filter-dialog.component.ts +++ b/ui-ngx/src/app/modules/home/components/filter/user-filter-dialog.component.ts @@ -14,12 +14,11 @@ /// limitations under the License. /// -import { Component, DestroyRef, Inject, SkipSelf } from '@angular/core'; -import { ErrorStateMatcher } from '@angular/material/core'; +import { Component, DestroyRef, Inject } from '@angular/core'; import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; import { Store } from '@ngrx/store'; import { AppState } from '@core/core.state'; -import { FormArray, FormBuilder, FormControl, FormGroup, FormGroupDirective, NgForm, Validators } from '@angular/forms'; +import { FormArray, FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms'; import { Router } from '@angular/router'; import { DialogComponent } from '@app/shared/components/dialog.component'; import { TranslateService } from '@ngx-translate/core'; @@ -39,29 +38,31 @@ export interface UserFilterDialogData { filter: Filter; } +interface UserInputForm { + label: FormControl; + valueType: FormControl; + unitSymbol: FormControl; + value: FormControl; +} + @Component({ selector: 'tb-user-filter-dialog', templateUrl: './user-filter-dialog.component.html', - providers: [{ provide: ErrorStateMatcher, useExisting: UserFilterDialogComponent }], styleUrls: ['./user-filter-dialog.component.scss'], standalone: false }) -export class UserFilterDialogComponent extends DialogComponent - implements ErrorStateMatcher { +export class UserFilterDialogComponent extends DialogComponent { filter: Filter; - userFilterFormGroup: FormGroup; + userInputsFormArray: FormArray>; valueTypeEnum = EntityKeyValueType; - submitted = false; - constructor(protected store: Store, protected router: Router, @Inject(MAT_DIALOG_DATA) public data: UserFilterDialogData, - @SkipSelf() private errorStateMatcher: ErrorStateMatcher, - public dialogRef: MatDialogRef, + protected dialogRef: MatDialogRef, private fb: FormBuilder, private translate: TranslateService, private destroyRef: DestroyRef, @@ -70,19 +71,13 @@ export class UserFilterDialogComponent extends DialogComponent = []; - for (const userInput of userInputs) { - userInputControls.push(this.createUserInputFormControl(userInput)); - } - - this.userFilterFormGroup = this.fb.group({ - userInputs: this.fb.array(userInputControls) - }); + const userInputControls = userInputs.map(input => this.createUserInputFormControl(input)); + this.userInputsFormArray = this.fb.array(userInputControls); } - private createUserInputFormControl(userInput: UserFilterInputInfo): FormGroup { + private createUserInputFormControl(userInput: UserFilterInputInfo): FormGroup { const predicateValue: FilterPredicateValue = (userInput.info.keyFilterPredicate as any).value; - let value = isDefinedAndNotNull(predicateValue.userValue) ? predicateValue.userValue : predicateValue.defaultValue; + let value: string | number | boolean = isDefinedAndNotNull(predicateValue.userValue) ? predicateValue.userValue : predicateValue.defaultValue; let unitSymbol = ''; let valueConvertor: TbUnitConverter; if (userInput.valueType === EntityKeyValueType.NUMERIC) { @@ -91,42 +86,31 @@ export class UserFilterDialogComponent extends DialogComponent({ + label: this.fb.control(userInput.label), + valueType: this.fb.control(userInput.valueType), + unitSymbol: this.fb.control(unitSymbol), + value: this.fb.control(value, userInput.valueType === EntityKeyValueType.NUMERIC || - userInput.valueType === EntityKeyValueType.DATE_TIME ? [Validators.required] : []] + userInput.valueType === EntityKeyValueType.DATE_TIME ? [Validators.required] : []) }); - userInputControl.get('value').valueChanges.pipe( + userInputControl.controls.value.valueChanges.pipe( takeUntilDestroyed(this.destroyRef) ).subscribe(userValue => { - let value = userValue; + let val = userValue; if (valueConvertor) { - value = valueConvertor(value as number); + val = valueConvertor(val as number); } - (userInput.info.keyFilterPredicate as any).value.userValue = value; + (userInput.info.keyFilterPredicate as any).value.userValue = val; }); return userInputControl; } - userInputsFormArray(): FormArray { - return this.userFilterFormGroup.get('userInputs') as FormArray; - } - - isErrorState(control: FormControl | null, form: FormGroupDirective | NgForm | null): boolean { - const originalErrorState = this.errorStateMatcher.isErrorState(control, form); - const customErrorState = !!(control && control.invalid && this.submitted); - return originalErrorState || customErrorState; - } - cancel(): void { this.dialogRef.close(null); } save(): void { - this.submitted = true; this.dialogRef.close(this.filter); } } diff --git a/ui-ngx/src/app/shared/components/time/datetime.component.ts b/ui-ngx/src/app/shared/components/time/datetime.component.ts index 6d89185702..8306b14872 100644 --- a/ui-ngx/src/app/shared/components/time/datetime.component.ts +++ b/ui-ngx/src/app/shared/components/time/datetime.component.ts @@ -40,7 +40,7 @@ export class DatetimeComponent implements OnInit, ControlValueAccessor { return this.requiredValue; } @Input() - set required(value: boolean) { + set required(value: unknown) { this.requiredValue = coerceBooleanProperty(value); } diff --git a/ui-ngx/src/app/shared/models/query/query.models.ts b/ui-ngx/src/app/shared/models/query/query.models.ts index 258f09a535..cd35c410dc 100644 --- a/ui-ngx/src/app/shared/models/query/query.models.ts +++ b/ui-ngx/src/app/shared/models/query/query.models.ts @@ -411,8 +411,7 @@ export interface FiltersInfo { export function keyFiltersToText(translate: TranslateService, datePipe: DatePipe, keyFilters: Array, operation: ComplexOperation = ComplexOperation.AND): string { const filtersText = keyFilters.map(keyFilter => - keyFilterToText(translate, datePipe, keyFilter, - keyFilters.length > 1 ? operation : undefined)); + keyFilterToText(translate, datePipe, keyFilter, operation)); let result: string; if (filtersText.length > 1) { const opText = translate.instant(complexOperationTranslationMap.get(operation));