UI: added getEntitySubtypesObservable method to entity service, code cleanup

This commit is contained in:
rusikv 2024-01-05 15:43:29 +02:00
parent b044c661d3
commit 7effa018ce
4 changed files with 73 additions and 112 deletions

View File

@ -1519,4 +1519,31 @@ export class EntityService {
} }
return entityObservable; return entityObservable;
} }
public getEntitySubtypesObservable(entityType: EntityType): Observable<Array<string>> {
let observable: Observable<Array<string>>;
switch (entityType) {
case EntityType.ASSET:
observable = this.assetProfileService.getAssetProfileNames(false, {ignoreLoading: true}).pipe(
map(subTypes => subTypes.map(subType => subType.name))
);
break;
case EntityType.DEVICE:
observable = this.deviceProfileService.getDeviceProfileNames(false,{ignoreLoading: true}).pipe(
map(subTypes => subTypes.map(subType => subType.name))
);
break;
case EntityType.EDGE:
observable = this.edgeService.getEdgeTypes({ignoreLoading: true}).pipe(
map(subTypes => subTypes.map(subType => subType.type))
);
break;
case EntityType.ENTITY_VIEW:
observable = this.entityViewService.getEntityViewTypes({ignoreLoading: true}).pipe(
map(subTypes => subTypes.map(subType => subType.type))
);
break;
}
return observable;
}
} }

View File

@ -16,29 +16,28 @@
import { AfterViewInit, Component, ElementRef, forwardRef, Input, OnDestroy, OnInit, ViewChild } from '@angular/core'; import { AfterViewInit, Component, ElementRef, forwardRef, Input, OnDestroy, OnInit, ViewChild } from '@angular/core';
import { ControlValueAccessor, UntypedFormBuilder, UntypedFormGroup, NG_VALUE_ACCESSOR, Validators } from '@angular/forms'; import { ControlValueAccessor, UntypedFormBuilder, UntypedFormGroup, NG_VALUE_ACCESSOR, Validators } from '@angular/forms';
import { Observable, of, Subscription, throwError } from 'rxjs'; import { Observable, of, ReplaySubject, Subscription, throwError } from 'rxjs';
import { import {
catchError, catchError,
debounceTime, debounceTime,
distinctUntilChanged, distinctUntilChanged,
map, map,
publishReplay,
refCount,
switchMap, switchMap,
tap tap,
share,
} from 'rxjs/operators'; } from 'rxjs/operators';
import { Store } from '@ngrx/store'; import { Store } from '@ngrx/store';
import { AppState } from '@app/core/core.state'; import { AppState } from '@app/core/core.state';
import { TranslateService } from '@ngx-translate/core'; import { TranslateService } from '@ngx-translate/core';
import { DeviceProfileService } from '@core/http/device-profile.service'; import { DeviceProfileService } from '@core/http/device-profile.service';
import { EntitySubtype, EntityType } from '@app/shared/models/entity-type.models'; import { EntityType } from '@app/shared/models/entity-type.models';
import { BroadcastService } from '@app/core/services/broadcast.service'; import { BroadcastService } from '@app/core/services/broadcast.service';
import { coerceBooleanProperty } from '@angular/cdk/coercion'; import { coerceBooleanProperty } from '@angular/cdk/coercion';
import { AssetProfileService } from '@core/http/asset-profile.service'; import { AssetProfileService } from '@core/http/asset-profile.service';
import { EntityViewService } from '@core/http/entity-view.service'; import { EntityViewService } from '@core/http/entity-view.service';
import { EdgeService } from '@core/http/edge.service'; import { EdgeService } from '@core/http/edge.service';
import { MatFormFieldAppearance } from '@angular/material/form-field'; import { MatFormFieldAppearance } from '@angular/material/form-field';
import { EntityInfoData } from '@shared/models/entity.models'; import { EntityService } from '@core/http/entity.service';
@Component({ @Component({
selector: 'tb-entity-subtype-autocomplete', selector: 'tb-entity-subtype-autocomplete',
@ -105,7 +104,8 @@ export class EntitySubTypeAutocompleteComponent implements ControlValueAccessor,
private assetProfileService: AssetProfileService, private assetProfileService: AssetProfileService,
private edgeService: EdgeService, private edgeService: EdgeService,
private entityViewService: EntityViewService, private entityViewService: EntityViewService,
private fb: UntypedFormBuilder) { private fb: UntypedFormBuilder,
private entityService: EntityService) {
this.subTypeFormGroup = this.fb.group({ this.subTypeFormGroup = this.fb.group({
subType: [null, Validators.maxLength(255)] subType: [null, Validators.maxLength(255)]
}); });
@ -230,35 +230,22 @@ export class EntitySubTypeAutocompleteComponent implements ControlValueAccessor,
getSubTypes(): Observable<Array<string>> { getSubTypes(): Observable<Array<string>> {
if (!this.subTypes) { if (!this.subTypes) {
let subTypesObservable: Observable<Array<EntitySubtype | EntityInfoData>>; const subTypesObservable = this.entityService.getEntitySubtypesObservable(this.entityType);
switch (this.entityType) {
case EntityType.ASSET:
subTypesObservable = this.assetProfileService.getAssetProfileNames(false, {ignoreLoading: true});
break;
case EntityType.DEVICE:
subTypesObservable = this.deviceProfileService.getDeviceProfileNames(false,{ignoreLoading: true});
break;
case EntityType.EDGE:
subTypesObservable = this.edgeService.getEdgeTypes({ignoreLoading: true});
break;
case EntityType.ENTITY_VIEW:
subTypesObservable = this.entityViewService.getEntityViewTypes({ignoreLoading: true});
break;
}
if (subTypesObservable) { if (subTypesObservable) {
const excludeSubTypesSet = new Set(this.excludeSubTypes); const excludeSubTypesSet = new Set(this.excludeSubTypes);
this.subTypes = subTypesObservable.pipe( this.subTypes = subTypesObservable.pipe(
catchError(() => of([] as Array<EntitySubtype | EntityInfoData>)), catchError(() => of([] as Array<string>)),
map(subTypes => { map(subTypes => {
const filteredSubTypes: Array<string> = []; const filteredSubTypes: Array<string> = [];
subTypes.forEach(subType => { subTypes.forEach(subType => !excludeSubTypesSet.has(subType) && filteredSubTypes.push(subType));
const typeName = this.isEntitySubType(subType) ? subType.type : subType.name;
return !excludeSubTypesSet.has(typeName) && filteredSubTypes.push(typeName);
});
return filteredSubTypes; return filteredSubTypes;
}), }),
publishReplay(1), share({
refCount() connector: () => new ReplaySubject(1),
resetOnError: false,
resetOnComplete: false,
resetOnRefCountZero: false,
})
); );
} else { } else {
return throwError(null); return throwError(null);
@ -267,10 +254,6 @@ export class EntitySubTypeAutocompleteComponent implements ControlValueAccessor,
return this.subTypes; return this.subTypes;
} }
private isEntitySubType(object: EntitySubtype | EntityInfoData): object is EntitySubtype {
return 'type' in object;
}
clear() { clear() {
this.subTypeFormGroup.get('subType').patchValue(null, {emitEvent: true}); this.subTypeFormGroup.get('subType').patchValue(null, {emitEvent: true});
setTimeout(() => { setTimeout(() => {

View File

@ -34,7 +34,7 @@ import { coerceArray, coerceBoolean } from '@shared/decorators/coercion';
import { PageLink } from '@shared/models/page/page-link'; import { PageLink } from '@shared/models/page/page-link';
import { PageData } from '@shared/models/page/page-data'; import { PageData } from '@shared/models/page/page-data';
import { UtilsService } from '@core/services/utils.service'; import { UtilsService } from '@core/services/utils.service';
import { EntityInfoData } from '@shared/models/entity.models'; import { EntityService } from '@core/http/entity.service';
@Component({ @Component({
selector: 'tb-entity-subtype-list', selector: 'tb-entity-subtype-list',
@ -132,7 +132,8 @@ export class EntitySubTypeListComponent implements ControlValueAccessor, OnInit,
private entityViewService: EntityViewService, private entityViewService: EntityViewService,
private alarmService: AlarmService, private alarmService: AlarmService,
private utils: UtilsService, private utils: UtilsService,
private fb: FormBuilder) { private fb: FormBuilder,
private entityService: EntityService) {
this.entitySubtypeListFormGroup = this.fb.group({ this.entitySubtypeListFormGroup = this.fb.group({
entitySubtypeList: [this.entitySubtypeList, this.required ? [Validators.required] : []], entitySubtypeList: [this.entitySubtypeList, this.required ? [Validators.required] : []],
entitySubtype: [null] entitySubtype: [null]
@ -327,24 +328,9 @@ export class EntitySubTypeListComponent implements ControlValueAccessor, OnInit,
} }
} }
if (!this.entitySubtypes) { if (!this.entitySubtypes) {
let subTypesObservable: Observable<Array<EntitySubtype | EntityInfoData>>; const subTypesObservable = this.entityService.getEntitySubtypesObservable(this.entityType);
switch (this.entityType) {
case EntityType.ASSET:
subTypesObservable = this.assetProfileService.getAssetProfileNames(false, {ignoreLoading: true});
break;
case EntityType.DEVICE:
subTypesObservable = this.deviceProfileService.getDeviceProfileNames(false,{ignoreLoading: true});
break;
case EntityType.EDGE:
subTypesObservable = this.edgeService.getEdgeTypes({ignoreLoading: true});
break;
case EntityType.ENTITY_VIEW:
subTypesObservable = this.entityViewService.getEntityViewTypes({ignoreLoading: true});
break;
}
if (subTypesObservable) { if (subTypesObservable) {
this.entitySubtypes = subTypesObservable.pipe( this.entitySubtypes = subTypesObservable.pipe(
map(subTypes => subTypes.map(subType => this.isEntitySubType(subType) ? subType.type : subType.name)),
share({ share({
connector: () => new ReplaySubject(1), connector: () => new ReplaySubject(1),
resetOnError: false, resetOnError: false,
@ -359,10 +345,6 @@ export class EntitySubTypeListComponent implements ControlValueAccessor, OnInit,
return this.entitySubtypes; return this.entitySubtypes;
} }
private isEntitySubType(object: EntitySubtype | EntityInfoData): object is EntitySubtype {
return 'type' in object;
}
onFocus() { onFocus() {
if (this.dirty) { if (this.dirty) {
this.entitySubtypeListFormGroup.get('entitySubtype').updateValueAndValidity({onlySelf: true, emitEvent: true}); this.entitySubtypeListFormGroup.get('entitySubtype').updateValueAndValidity({onlySelf: true, emitEvent: true});

View File

@ -17,18 +17,19 @@
import { AfterViewInit, Component, forwardRef, Input, OnDestroy, OnInit } from '@angular/core'; import { AfterViewInit, Component, forwardRef, Input, OnDestroy, OnInit } from '@angular/core';
import { ControlValueAccessor, UntypedFormBuilder, UntypedFormGroup, NG_VALUE_ACCESSOR } from '@angular/forms'; import { ControlValueAccessor, UntypedFormBuilder, UntypedFormGroup, NG_VALUE_ACCESSOR } from '@angular/forms';
import { Observable, Subject, Subscription, throwError } from 'rxjs'; import { Observable, Subject, Subscription, throwError } from 'rxjs';
import { map, mergeMap, publishReplay, refCount, startWith, tap } from 'rxjs/operators'; import { map, mergeMap, startWith, tap, share } from 'rxjs/operators';
import { Store } from '@ngrx/store'; import { Store } from '@ngrx/store';
import { AppState } from '@app/core/core.state'; import { AppState } from '@app/core/core.state';
import { TranslateService } from '@ngx-translate/core'; import { TranslateService } from '@ngx-translate/core';
import { DeviceProfileService } from '@core/http/device-profile.service'; import { DeviceProfileService } from '@core/http/device-profile.service';
import { EntitySubtype, EntityType } from '@app/shared/models/entity-type.models'; import { EntityType } from '@app/shared/models/entity-type.models';
import { BroadcastService } from '@app/core/services/broadcast.service'; import { BroadcastService } from '@app/core/services/broadcast.service';
import { AssetProfileService } from '@core/http/asset-profile.service'; import { AssetProfileService } from '@core/http/asset-profile.service';
import { EdgeService } from '@core/http/edge.service'; import { EdgeService } from '@core/http/edge.service';
import { EntityViewService } from '@core/http/entity-view.service'; import { EntityViewService } from '@core/http/entity-view.service';
import { SubscriptSizing } from '@angular/material/form-field'; import { SubscriptSizing } from '@angular/material/form-field';
import { EntityInfoData } from '@shared/models/entity.models'; import { isNotEmptyStr } from '@core/utils';
import { EntityService } from '@core/http/entity.service';
@Component({ @Component({
selector: 'tb-entity-subtype-select', selector: 'tb-entity-subtype-select',
@ -67,11 +68,11 @@ export class EntitySubTypeSelectComponent implements ControlValueAccessor, OnIni
entitySubtypeTitle: string; entitySubtypeTitle: string;
entitySubtypeRequiredText: string; entitySubtypeRequiredText: string;
subTypesOptions: Observable<Array<EntitySubtype | string | EntityInfoData>>; subTypesOptions: Observable<Array<string>>;
private subTypesOptionsSubject: Subject<string> = new Subject(); private subTypesOptionsSubject: Subject<string> = new Subject();
subTypes: Observable<Array<EntitySubtype | string | EntityInfoData>>; private subTypes: Observable<Array<string>>;
subTypesLoaded = false; subTypesLoaded = false;
@ -86,7 +87,8 @@ export class EntitySubTypeSelectComponent implements ControlValueAccessor, OnIni
private assetProfileService: AssetProfileService, private assetProfileService: AssetProfileService,
private edgeService: EdgeService, private edgeService: EdgeService,
private entityViewService: EntityViewService, private entityViewService: EntityViewService,
private fb: UntypedFormBuilder) { private fb: UntypedFormBuilder,
private entityService: EntityService) {
this.subTypeFormGroup = this.fb.group({ this.subTypeFormGroup = this.fb.group({
subType: [''] subType: ['']
}); });
@ -137,7 +139,7 @@ export class EntitySubTypeSelectComponent implements ControlValueAccessor, OnIni
} }
this.subTypesOptions = this.subTypesOptionsSubject.asObservable().pipe( this.subTypesOptions = this.subTypesOptionsSubject.asObservable().pipe(
startWith<string | EntitySubtype | EntityInfoData>(''), startWith<string>(''),
mergeMap(() => this.getSubTypes()) mergeMap(() => this.getSubTypes())
); );
@ -147,7 +149,7 @@ export class EntitySubTypeSelectComponent implements ControlValueAccessor, OnIni
if (!value || value === '') { if (!value || value === '') {
modelValue = ''; modelValue = '';
} else { } else {
modelValue = value.type; modelValue = value;
} }
this.updateView(modelValue); this.updateView(modelValue);
} }
@ -194,70 +196,41 @@ export class EntitySubTypeSelectComponent implements ControlValueAccessor, OnIni
} }
} }
displaySubTypeFn(subType?: EntitySubtype | string | EntityInfoData): string | undefined { displaySubTypeFn(subType?: string): string | undefined {
if (subType && typeof subType !== 'string') { if (isNotEmptyStr(subType)) {
const typeName = this.isEntitySubType(subType) ? subType.type : subType.name;
if (this.typeTranslatePrefix) { if (this.typeTranslatePrefix) {
return this.translate.instant(this.typeTranslatePrefix + '.' + typeName); return this.translate.instant(this.typeTranslatePrefix + '.' + subType);
} else { } else {
return typeName; return subType;
} }
} else { } else {
return this.translate.instant('entity.all-subtypes'); return this.translate.instant('entity.all-subtypes');
} }
} }
findSubTypes(searchText: string): Observable<Array<EntitySubtype | string | EntityInfoData>> { findSubTypes(searchText: string): Observable<Array<string>> {
return this.getSubTypes().pipe( return this.getSubTypes().pipe(
map(subTypes => subTypes.filter( subType => { map(subTypes => subTypes.filter( subType => subType === searchText))
if (typeof subType === 'string') {
return false;
} else {
return this.isEntitySubType(subType) ? subType.type : subType.name === searchText;
}
}))
); );
} }
getSubTypes(): Observable<Array<EntitySubtype | string | EntityInfoData>> { getSubTypes(): Observable<Array<string>> {
if (!this.subTypes) { if (!this.subTypes) {
switch (this.entityType) { const subTypesObservable = this.entityService.getEntitySubtypesObservable(this.entityType);
case EntityType.ASSET: if (subTypesObservable) {
this.subTypes = this.assetProfileService.getAssetProfileNames(false, {ignoreLoading: true}); this.subTypes = subTypesObservable.pipe(
break; map((subTypes) => {
case EntityType.DEVICE: this.subTypesLoaded = true;
this.subTypes = this.deviceProfileService.getDeviceProfileNames(false, {ignoreLoading: true}); subTypes.unshift('');
break; return subTypes;
case EntityType.EDGE:
this.subTypes = this.edgeService.getEdgeTypes({ignoreLoading: true});
break;
case EntityType.ENTITY_VIEW:
this.subTypes = this.entityViewService.getEntityViewTypes({ignoreLoading: true});
break;
}
if (this.subTypes) {
this.subTypes = this.subTypes.pipe(
map((allSubtypes) => {
allSubtypes.unshift('');
this.subTypesLoaded = true;
return allSubtypes;
}), }),
tap((subTypes) => { tap((subTypes) => {
const type: EntitySubtype | string = this.subTypeFormGroup.get('subType').value; const found = subTypes.find(subType => subType === this.subTypeFormGroup.get('subType').value);
const strType = typeof type === 'string' ? type : type.type;
const found = subTypes.find((subType) => {
if (typeof subType === 'string') {
return subType === type;
} else {
return this.isEntitySubType(subType) ? subType.type : subType.name === strType;
}
});
if (found) { if (found) {
this.subTypeFormGroup.get('subType').patchValue(found); this.subTypeFormGroup.get('subType').patchValue(found);
} }
}), }),
publishReplay(1), share()
refCount()
); );
} else { } else {
return throwError(null); return throwError(null);
@ -265,8 +238,4 @@ export class EntitySubTypeSelectComponent implements ControlValueAccessor, OnIni
} }
return this.subTypes; return this.subTypes;
} }
private isEntitySubType(object: EntitySubtype | EntityInfoData): object is EntitySubtype {
return 'type' in object;
}
} }