diff --git a/ui-ngx/src/app/core/http/asset-profile.service.ts b/ui-ngx/src/app/core/http/asset-profile.service.ts index 029e1afe5c..5ffc3f1e24 100644 --- a/ui-ngx/src/app/core/http/asset-profile.service.ts +++ b/ui-ngx/src/app/core/http/asset-profile.service.ts @@ -21,6 +21,8 @@ import { defaultHttpOptionsFromConfig, RequestConfig } from './http-utils'; import { Observable } from 'rxjs'; import { PageData } from '@shared/models/page/page-data'; import { AssetProfile, AssetProfileInfo } from '@shared/models/asset.models'; +import { EntityInfoData } from '@shared/models/entity.models'; +import { isDefinedAndNotNull } from '@core/utils'; @Injectable({ providedIn: 'root' @@ -68,4 +70,12 @@ export class AssetProfileService { return this.http.get>(`/api/assetProfileInfos${pageLink.toQuery()}`, defaultHttpOptionsFromConfig(config)); } + public getAssetProfileNames(activeOnly: boolean = false, config?: RequestConfig): Observable> { + let url = '/api/assetProfile/names'; + if (isDefinedAndNotNull(activeOnly)) { + url += `?activeOnly=${activeOnly}`; + } + return this.http.get>(url, defaultHttpOptionsFromConfig(config)); + } + } diff --git a/ui-ngx/src/app/core/http/device-profile.service.ts b/ui-ngx/src/app/core/http/device-profile.service.ts index fd7753a6ab..73f4e14845 100644 --- a/ui-ngx/src/app/core/http/device-profile.service.ts +++ b/ui-ngx/src/app/core/http/device-profile.service.ts @@ -31,6 +31,7 @@ import { SortOrder } from '@shared/models/page/sort-order'; import { OtaPackageService } from '@core/http/ota-package.service'; import { map, mergeMap, tap } from 'rxjs/operators'; import { Lwm2mSecurityType } from '@shared/models/lwm2m-security-config.models'; +import { EntityInfoData } from '@shared/models/entity.models'; @Injectable({ providedIn: 'root' @@ -169,4 +170,12 @@ export class DeviceProfileService { return this.http.get>(url, defaultHttpOptionsFromConfig(config)); } + public getDeviceProfileNames(activeOnly: boolean = false, config?: RequestConfig): Observable> { + let url = '/api/deviceProfile/names'; + if (isDefinedAndNotNull(activeOnly)) { + url += `?activeOnly=${activeOnly}`; + } + return this.http.get>(url, defaultHttpOptionsFromConfig(config)); + } + } diff --git a/ui-ngx/src/app/shared/components/entity/entity-subtype-autocomplete.component.ts b/ui-ngx/src/app/shared/components/entity/entity-subtype-autocomplete.component.ts index 3c28d9ceaa..d9c6bf0a6c 100644 --- a/ui-ngx/src/app/shared/components/entity/entity-subtype-autocomplete.component.ts +++ b/ui-ngx/src/app/shared/components/entity/entity-subtype-autocomplete.component.ts @@ -30,14 +30,15 @@ import { import { Store } from '@ngrx/store'; import { AppState } from '@app/core/core.state'; import { TranslateService } from '@ngx-translate/core'; -import { DeviceService } from '@core/http/device.service'; +import { DeviceProfileService } from '@core/http/device-profile.service'; import { EntitySubtype, EntityType } from '@app/shared/models/entity-type.models'; import { BroadcastService } from '@app/core/services/broadcast.service'; import { coerceBooleanProperty } from '@angular/cdk/coercion'; -import { AssetService } from '@core/http/asset.service'; +import { AssetProfileService } from '@core/http/asset-profile.service'; import { EntityViewService } from '@core/http/entity-view.service'; import { EdgeService } from '@core/http/edge.service'; import { MatFormFieldAppearance } from '@angular/material/form-field'; +import { EntityInfoData } from '@shared/models/entity.models'; @Component({ selector: 'tb-entity-subtype-autocomplete', @@ -100,8 +101,8 @@ export class EntitySubTypeAutocompleteComponent implements ControlValueAccessor, constructor(private store: Store, private broadcast: BroadcastService, public translate: TranslateService, - private deviceService: DeviceService, - private assetService: AssetService, + private deviceProfileService: DeviceProfileService, + private assetProfileService: AssetProfileService, private edgeService: EdgeService, private entityViewService: EntityViewService, private fb: UntypedFormBuilder) { @@ -229,13 +230,13 @@ export class EntitySubTypeAutocompleteComponent implements ControlValueAccessor, getSubTypes(): Observable> { if (!this.subTypes) { - let subTypesObservable: Observable>; + let subTypesObservable: Observable>; switch (this.entityType) { case EntityType.ASSET: - subTypesObservable = this.assetService.getAssetTypes({ignoreLoading: true}); + subTypesObservable = this.assetProfileService.getAssetProfileNames(false, {ignoreLoading: true}); break; case EntityType.DEVICE: - subTypesObservable = this.deviceService.getDeviceTypes({ignoreLoading: true}); + subTypesObservable = this.deviceProfileService.getDeviceProfileNames(false,{ignoreLoading: true}); break; case EntityType.EDGE: subTypesObservable = this.edgeService.getEdgeTypes({ignoreLoading: true}); @@ -247,10 +248,13 @@ export class EntitySubTypeAutocompleteComponent implements ControlValueAccessor, if (subTypesObservable) { const excludeSubTypesSet = new Set(this.excludeSubTypes); this.subTypes = subTypesObservable.pipe( - catchError(() => of([] as Array)), + catchError(() => of([] as Array)), map(subTypes => { const filteredSubTypes: Array = []; - subTypes.forEach(subType => !excludeSubTypesSet.has(subType.type) && filteredSubTypes.push(subType.type)); + subTypes.forEach(subType => { + const typeName = this.isEntitySubType(subType) ? subType.type : subType.name; + return !excludeSubTypesSet.has(typeName) && filteredSubTypes.push(typeName); + }); return filteredSubTypes; }), publishReplay(1), @@ -263,6 +267,10 @@ export class EntitySubTypeAutocompleteComponent implements ControlValueAccessor, return this.subTypes; } + private isEntitySubType(object: EntitySubtype | EntityInfoData): object is EntitySubtype { + return 'type' in object; + } + clear() { this.subTypeFormGroup.get('subType').patchValue(null, {emitEvent: true}); setTimeout(() => { diff --git a/ui-ngx/src/app/shared/components/entity/entity-subtype-list.component.ts b/ui-ngx/src/app/shared/components/entity/entity-subtype-list.component.ts index 89900fb065..fe843e77fc 100644 --- a/ui-ngx/src/app/shared/components/entity/entity-subtype-list.component.ts +++ b/ui-ngx/src/app/shared/components/entity/entity-subtype-list.component.ts @@ -22,8 +22,8 @@ import { TranslateService } from '@ngx-translate/core'; import { EntitySubtype, EntityType } from '@shared/models/entity-type.models'; import { MatAutocomplete, MatAutocompleteSelectedEvent } from '@angular/material/autocomplete'; import { MatChipGrid, MatChipInputEvent } from '@angular/material/chips'; -import { AssetService } from '@core/http/asset.service'; -import { DeviceService } from '@core/http/device.service'; +import { AssetProfileService } from '@core/http/asset-profile.service'; +import { DeviceProfileService } from '@core/http/device-profile.service'; import { EdgeService } from '@core/http/edge.service'; import { EntityViewService } from '@core/http/entity-view.service'; import { BroadcastService } from '@core/services/broadcast.service'; @@ -34,6 +34,7 @@ import { coerceArray, coerceBoolean } from '@shared/decorators/coercion'; import { PageLink } from '@shared/models/page/page-link'; import { PageData } from '@shared/models/page/page-data'; import { UtilsService } from '@core/services/utils.service'; +import { EntityInfoData } from '@shared/models/entity.models'; @Component({ selector: 'tb-entity-subtype-list', @@ -125,8 +126,8 @@ export class EntitySubTypeListComponent implements ControlValueAccessor, OnInit, constructor(private broadcast: BroadcastService, public translate: TranslateService, - private assetService: AssetService, - private deviceService: DeviceService, + private assetProfileService: AssetProfileService, + private deviceProfileService: DeviceProfileService, private edgeService: EdgeService, private entityViewService: EntityViewService, private alarmService: AlarmService, @@ -326,13 +327,13 @@ export class EntitySubTypeListComponent implements ControlValueAccessor, OnInit, } } if (!this.entitySubtypes) { - let subTypesObservable: Observable>; + let subTypesObservable: Observable>; switch (this.entityType) { case EntityType.ASSET: - subTypesObservable = this.assetService.getAssetTypes({ignoreLoading: true}); + subTypesObservable = this.assetProfileService.getAssetProfileNames(false, {ignoreLoading: true}); break; case EntityType.DEVICE: - subTypesObservable = this.deviceService.getDeviceTypes({ignoreLoading: true}); + subTypesObservable = this.deviceProfileService.getDeviceProfileNames(false,{ignoreLoading: true}); break; case EntityType.EDGE: subTypesObservable = this.edgeService.getEdgeTypes({ignoreLoading: true}); @@ -343,7 +344,7 @@ export class EntitySubTypeListComponent implements ControlValueAccessor, OnInit, } if (subTypesObservable) { this.entitySubtypes = subTypesObservable.pipe( - map(subTypes => subTypes.map(subType => subType.type)), + map(subTypes => subTypes.map(subType => this.isEntitySubType(subType) ? subType.type : subType.name)), share({ connector: () => new ReplaySubject(1), resetOnError: false, @@ -358,6 +359,10 @@ export class EntitySubTypeListComponent implements ControlValueAccessor, OnInit, return this.entitySubtypes; } + private isEntitySubType(object: EntitySubtype | EntityInfoData): object is EntitySubtype { + return 'type' in object; + } + onFocus() { if (this.dirty) { this.entitySubtypeListFormGroup.get('entitySubtype').updateValueAndValidity({onlySelf: true, emitEvent: true}); diff --git a/ui-ngx/src/app/shared/components/entity/entity-subtype-select.component.ts b/ui-ngx/src/app/shared/components/entity/entity-subtype-select.component.ts index e999f06762..eb2230860d 100644 --- a/ui-ngx/src/app/shared/components/entity/entity-subtype-select.component.ts +++ b/ui-ngx/src/app/shared/components/entity/entity-subtype-select.component.ts @@ -21,13 +21,14 @@ import { map, mergeMap, publishReplay, refCount, startWith, tap } from 'rxjs/ope import { Store } from '@ngrx/store'; import { AppState } from '@app/core/core.state'; import { TranslateService } from '@ngx-translate/core'; -import { DeviceService } from '@core/http/device.service'; +import { DeviceProfileService } from '@core/http/device-profile.service'; import { EntitySubtype, EntityType } from '@app/shared/models/entity-type.models'; import { BroadcastService } from '@app/core/services/broadcast.service'; -import { AssetService } from '@core/http/asset.service'; +import { AssetProfileService } from '@core/http/asset-profile.service'; import { EdgeService } from '@core/http/edge.service'; import { EntityViewService } from '@core/http/entity-view.service'; import { SubscriptSizing } from '@angular/material/form-field'; +import { EntityInfoData } from '@shared/models/entity.models'; @Component({ selector: 'tb-entity-subtype-select', @@ -66,11 +67,11 @@ export class EntitySubTypeSelectComponent implements ControlValueAccessor, OnIni entitySubtypeTitle: string; entitySubtypeRequiredText: string; - subTypesOptions: Observable>; + subTypesOptions: Observable>; private subTypesOptionsSubject: Subject = new Subject(); - subTypes: Observable>; + subTypes: Observable>; subTypesLoaded = false; @@ -81,8 +82,8 @@ export class EntitySubTypeSelectComponent implements ControlValueAccessor, OnIni constructor(private store: Store, private broadcast: BroadcastService, public translate: TranslateService, - private deviceService: DeviceService, - private assetService: AssetService, + private deviceProfileService: DeviceProfileService, + private assetProfileService: AssetProfileService, private edgeService: EdgeService, private entityViewService: EntityViewService, private fb: UntypedFormBuilder) { @@ -136,7 +137,7 @@ export class EntitySubTypeSelectComponent implements ControlValueAccessor, OnIni } this.subTypesOptions = this.subTypesOptionsSubject.asObservable().pipe( - startWith(''), + startWith(''), mergeMap(() => this.getSubTypes()) ); @@ -193,34 +194,39 @@ export class EntitySubTypeSelectComponent implements ControlValueAccessor, OnIni } } - displaySubTypeFn(subType?: EntitySubtype | string): string | undefined { + displaySubTypeFn(subType?: EntitySubtype | string | EntityInfoData): string | undefined { if (subType && typeof subType !== 'string') { + const typeName = this.isEntitySubType(subType) ? subType.type : subType.name; if (this.typeTranslatePrefix) { - return this.translate.instant(this.typeTranslatePrefix + '.' + subType.type); + return this.translate.instant(this.typeTranslatePrefix + '.' + typeName); } else { - return subType.type; + return typeName; } } else { return this.translate.instant('entity.all-subtypes'); } } - findSubTypes(searchText?: string): Observable> { + findSubTypes(searchText: string): Observable> { return this.getSubTypes().pipe( map(subTypes => subTypes.filter( subType => { - return searchText ? (typeof subType === 'string' ? false : subType.type === searchText) : false; + if (typeof subType === 'string') { + return false; + } else { + return this.isEntitySubType(subType) ? subType.type : subType.name === searchText; + } })) ); } - getSubTypes(): Observable> { + getSubTypes(): Observable> { if (!this.subTypes) { switch (this.entityType) { case EntityType.ASSET: - this.subTypes = this.assetService.getAssetTypes({ignoreLoading: true}); + this.subTypes = this.assetProfileService.getAssetProfileNames(false, {ignoreLoading: true}); break; case EntityType.DEVICE: - this.subTypes = this.deviceService.getDeviceTypes({ignoreLoading: true}); + this.subTypes = this.deviceProfileService.getDeviceProfileNames(false, {ignoreLoading: true}); break; case EntityType.EDGE: this.subTypes = this.edgeService.getEdgeTypes({ignoreLoading: true}); @@ -243,7 +249,7 @@ export class EntitySubTypeSelectComponent implements ControlValueAccessor, OnIni if (typeof subType === 'string') { return subType === type; } else { - return subType.type === strType; + return this.isEntitySubType(subType) ? subType.type : subType.name === strType; } }); if (found) { @@ -259,4 +265,8 @@ export class EntitySubTypeSelectComponent implements ControlValueAccessor, OnIni } return this.subTypes; } + + private isEntitySubType(object: EntitySubtype | EntityInfoData): object is EntitySubtype { + return 'type' in object; + } }