Commit 05f0619a2d9b6c8a5d036a7db3260a7319c299a8
1 parent
f1ca4c7c
Merge import device/asset functionality
Showing
11 changed files
with
99 additions
and
14 deletions
... | ... | @@ -805,14 +805,28 @@ export class EntityService { |
805 | 805 | case EntityType.DEVICE: |
806 | 806 | const device: Device = { |
807 | 807 | name: entityData.name, |
808 | - type: entityData.type | |
808 | + type: entityData.type, | |
809 | + label: entityData.label, | |
810 | + additionalInfo: { | |
811 | + description: entityData.description | |
812 | + } | |
809 | 813 | }; |
814 | + if (entityData.gateway !== null) { | |
815 | + device.additionalInfo = { | |
816 | + ...device.additionalInfo, | |
817 | + gateway: entityData.gateway | |
818 | + }; | |
819 | + } | |
810 | 820 | saveEntityObservable = this.deviceService.saveDevice(device, config); |
811 | 821 | break; |
812 | 822 | case EntityType.ASSET: |
813 | 823 | const asset: Asset = { |
814 | 824 | name: entityData.name, |
815 | - type: entityData.type | |
825 | + type: entityData.type, | |
826 | + label: entityData.label, | |
827 | + additionalInfo: { | |
828 | + description: entityData.description | |
829 | + } | |
816 | 830 | }; |
817 | 831 | saveEntityObservable = this.assetService.saveAsset(asset, config); |
818 | 832 | break; |
... | ... | @@ -839,7 +853,31 @@ export class EntityService { |
839 | 853 | } |
840 | 854 | return findEntityObservable.pipe( |
841 | 855 | mergeMap((entity) => { |
842 | - return this.saveEntityData(entity.id, entityData, config).pipe( | |
856 | + const tasks: Observable<any>[] = []; | |
857 | + const result: Device | Asset = entity as (Device | Asset); | |
858 | + const additionalInfo = result.additionalInfo || {}; | |
859 | + if(result.label !== entityData.label || | |
860 | + result.type !== entityData.type || | |
861 | + additionalInfo.description !== entityData.description || | |
862 | + (result.id.entityType === EntityType.DEVICE && (additionalInfo.gateway !== entityData.gateway)) ) { | |
863 | + result.label = entityData.label; | |
864 | + result.type = entityData.type; | |
865 | + result.additionalInfo = additionalInfo; | |
866 | + result.additionalInfo.description = entityData.description; | |
867 | + if (result.id.entityType === EntityType.DEVICE) { | |
868 | + result.additionalInfo.gateway = entityData.gateway; | |
869 | + } | |
870 | + switch (result.id.entityType) { | |
871 | + case EntityType.DEVICE: | |
872 | + tasks.push(this.deviceService.saveDevice(result, config)); | |
873 | + break; | |
874 | + case EntityType.ASSET: | |
875 | + tasks.push(this.assetService.saveAsset(result, config)); | |
876 | + break; | |
877 | + } | |
878 | + } | |
879 | + tasks.push(this.saveEntityData(entity.id, entityData, config)); | |
880 | + return forkJoin(tasks).pipe( | |
843 | 881 | map(() => { |
844 | 882 | return { update: { entity: 1 } } as ImportEntitiesResultInfo; |
845 | 883 | }), | ... | ... |
... | ... | @@ -168,7 +168,7 @@ export class ImportDialogCsvComponent extends DialogComponent<ImportDialogCsvCom |
168 | 168 | const isHeader: boolean = this.importParametersFormGroup.get('isHeader').value; |
169 | 169 | for (let i = 0; i < this.parseData.headers.length; i++) { |
170 | 170 | let columnParam: CsvColumnParam; |
171 | - if (isHeader && this.parseData.headers[i].search(/^(name|type)$/im) === 0) { | |
171 | + if (isHeader && this.parseData.headers[i].search(/^(name|type|label)$/im) === 0) { | |
172 | 172 | columnParam = { |
173 | 173 | type: ImportEntityColumnType[this.parseData.headers[i].toLowerCase()], |
174 | 174 | key: this.parseData.headers[i].toLowerCase(), |
... | ... | @@ -195,6 +195,9 @@ export class ImportDialogCsvComponent extends DialogComponent<ImportDialogCsvCom |
195 | 195 | const entityData: ImportEntityData = { |
196 | 196 | name: '', |
197 | 197 | type: '', |
198 | + description: '', | |
199 | + gateway: null, | |
200 | + label: '', | |
198 | 201 | accessToken: '', |
199 | 202 | attributes: { |
200 | 203 | server: [], |
... | ... | @@ -232,6 +235,15 @@ export class ImportDialogCsvComponent extends DialogComponent<ImportDialogCsvCom |
232 | 235 | case ImportEntityColumnType.type: |
233 | 236 | entityData.type = importData.rows[i][j]; |
234 | 237 | break; |
238 | + case ImportEntityColumnType.label: | |
239 | + entityData.label = importData.rows[i][j]; | |
240 | + break; | |
241 | + case ImportEntityColumnType.isGateway: | |
242 | + entityData.gateway = importData.rows[i][j]; | |
243 | + break; | |
244 | + case ImportEntityColumnType.description: | |
245 | + entityData.description = importData.rows[i][j]; | |
246 | + break; | |
235 | 247 | } |
236 | 248 | } |
237 | 249 | entitiesData.push(entityData); | ... | ... |
... | ... | @@ -44,12 +44,15 @@ export interface CsvToJsonResult { |
44 | 44 | export enum ImportEntityColumnType { |
45 | 45 | name = 'NAME', |
46 | 46 | type = 'TYPE', |
47 | + label = 'LABEL', | |
47 | 48 | clientAttribute = 'CLIENT_ATTRIBUTE', |
48 | 49 | sharedAttribute = 'SHARED_ATTRIBUTE', |
49 | 50 | serverAttribute = 'SERVER_ATTRIBUTE', |
50 | 51 | timeseries = 'TIMESERIES', |
51 | 52 | entityField = 'ENTITY_FIELD', |
52 | - accessToken = 'ACCESS_TOKEN' | |
53 | + accessToken = 'ACCESS_TOKEN', | |
54 | + isGateway = 'IS_GATEWAY', | |
55 | + description = 'DESCRIPTION' | |
53 | 56 | } |
54 | 57 | |
55 | 58 | export const importEntityObjectColumns = |
... | ... | @@ -59,12 +62,15 @@ export const importEntityColumnTypeTranslations = new Map<ImportEntityColumnType |
59 | 62 | [ |
60 | 63 | [ImportEntityColumnType.name, 'import.column-type.name'], |
61 | 64 | [ImportEntityColumnType.type, 'import.column-type.type'], |
65 | + [ImportEntityColumnType.label, 'import.column-type.label'], | |
62 | 66 | [ImportEntityColumnType.clientAttribute, 'import.column-type.client-attribute'], |
63 | 67 | [ImportEntityColumnType.sharedAttribute, 'import.column-type.shared-attribute'], |
64 | 68 | [ImportEntityColumnType.serverAttribute, 'import.column-type.server-attribute'], |
65 | 69 | [ImportEntityColumnType.timeseries, 'import.column-type.timeseries'], |
66 | 70 | [ImportEntityColumnType.entityField, 'import.column-type.entity-field'], |
67 | 71 | [ImportEntityColumnType.accessToken, 'import.column-type.access-token'], |
72 | + [ImportEntityColumnType.isGateway, 'import.column-type.isgateway'], | |
73 | + [ImportEntityColumnType.description, 'import.column-type.description'], | |
68 | 74 | ] |
69 | 75 | ); |
70 | 76 | |
... | ... | @@ -136,7 +142,7 @@ function convertStringToJSType(str: string): any { |
136 | 142 | return parseFloat(str.replace(',', '.')); |
137 | 143 | } |
138 | 144 | if (str.search(/^(true|false)$/im) === 0) { |
139 | - return str === 'true'; | |
145 | + return str.toLowerCase() === 'true'; | |
140 | 146 | } |
141 | 147 | if (str === '') { |
142 | 148 | return null; | ... | ... |
... | ... | @@ -42,9 +42,7 @@ |
42 | 42 | <mat-header-cell *matHeaderCellDef style="width: 30%"> {{ 'import.column-key' | translate }} </mat-header-cell> |
43 | 43 | <mat-cell *matCellDef="let column"> |
44 | 44 | <mat-form-field floatLabel="always" hideRequiredMarker |
45 | - *ngIf="column.type !== importEntityColumnType.name && | |
46 | - column.type !== importEntityColumnType.type && | |
47 | - column.type !== importEntityColumnType.accessToken"> | |
45 | + *ngIf="isColumnTypeDiffers(column.type)"> | |
48 | 46 | <mat-label></mat-label> |
49 | 47 | <input matInput required |
50 | 48 | [(ngModel)]="column.key" (ngModelChange)="columnsUpdated()" | ... | ... |
... | ... | @@ -72,6 +72,8 @@ export class TableColumnsAssignmentComponent implements OnInit, ControlValueAcce |
72 | 72 | this.columnTypes.push( |
73 | 73 | { value: ImportEntityColumnType.name }, |
74 | 74 | { value: ImportEntityColumnType.type }, |
75 | + { value: ImportEntityColumnType.label }, | |
76 | + { value: ImportEntityColumnType.description }, | |
75 | 77 | ); |
76 | 78 | switch (this.entityType) { |
77 | 79 | case EntityType.DEVICE: |
... | ... | @@ -79,7 +81,8 @@ export class TableColumnsAssignmentComponent implements OnInit, ControlValueAcce |
79 | 81 | { value: ImportEntityColumnType.sharedAttribute }, |
80 | 82 | { value: ImportEntityColumnType.serverAttribute }, |
81 | 83 | { value: ImportEntityColumnType.timeseries }, |
82 | - { value: ImportEntityColumnType.accessToken } | |
84 | + { value: ImportEntityColumnType.accessToken }, | |
85 | + { value: ImportEntityColumnType.isGateway } | |
83 | 86 | ); |
84 | 87 | break; |
85 | 88 | case EntityType.ASSET: |
... | ... | @@ -109,13 +112,20 @@ export class TableColumnsAssignmentComponent implements OnInit, ControlValueAcce |
109 | 112 | columnsUpdated() { |
110 | 113 | const isSelectName = this.columns.findIndex((column) => column.type === ImportEntityColumnType.name) > -1; |
111 | 114 | const isSelectType = this.columns.findIndex((column) => column.type === ImportEntityColumnType.type) > -1; |
115 | + const isSelectLabel = this.columns.findIndex((column) => column.type === ImportEntityColumnType.label) > -1; | |
112 | 116 | const isSelectCredentials = this.columns.findIndex((column) => column.type === ImportEntityColumnType.accessToken) > -1; |
117 | + const isSelectGateway = this.columns.findIndex((column) => column.type === ImportEntityColumnType.isGateway) > -1; | |
118 | + const isSelectDescription = this.columns.findIndex((column) => column.type === ImportEntityColumnType.description) > -1; | |
113 | 119 | const hasInvalidColumn = this.columns.findIndex((column) => !this.columnValid(column)) > -1; |
114 | 120 | |
115 | 121 | this.valid = isSelectName && isSelectType && !hasInvalidColumn; |
116 | 122 | |
117 | 123 | this.columnTypes.find((columnType) => columnType.value === ImportEntityColumnType.name).disabled = isSelectName; |
118 | 124 | this.columnTypes.find((columnType) => columnType.value === ImportEntityColumnType.type).disabled = isSelectType; |
125 | + this.columnTypes.find((columnType) => columnType.value === ImportEntityColumnType.label).disabled = isSelectLabel; | |
126 | + this.columnTypes.find((columnType) => columnType.value === ImportEntityColumnType.isGateway).disabled = isSelectGateway; | |
127 | + this.columnTypes.find((columnType) => columnType.value === ImportEntityColumnType.description).disabled = isSelectDescription; | |
128 | + | |
119 | 129 | const accessTokenColumnType = this.columnTypes.find((columnType) => columnType.value === ImportEntityColumnType.accessToken); |
120 | 130 | if (accessTokenColumnType) { |
121 | 131 | accessTokenColumnType.disabled = isSelectCredentials; |
... | ... | @@ -127,6 +137,15 @@ export class TableColumnsAssignmentComponent implements OnInit, ControlValueAcce |
127 | 137 | } |
128 | 138 | } |
129 | 139 | |
140 | + public isColumnTypeDiffers(columnType: ImportEntityColumnType): boolean { | |
141 | + return columnType !== ImportEntityColumnType.name && | |
142 | + columnType !== ImportEntityColumnType.type && | |
143 | + columnType !== ImportEntityColumnType.label && | |
144 | + columnType !== ImportEntityColumnType.accessToken && | |
145 | + columnType !== ImportEntityColumnType.isGateway && | |
146 | + columnType !== ImportEntityColumnType.description; | |
147 | + } | |
148 | + | |
130 | 149 | private columnValid(column: CsvColumnParam): boolean { |
131 | 150 | if (!importEntityObjectColumns.includes(column.type)) { |
132 | 151 | return column.key && column.key.trim().length > 0; | ... | ... |
... | ... | @@ -77,6 +77,10 @@ |
77 | 77 | [entityType]="entityType.ASSET" |
78 | 78 | > |
79 | 79 | </tb-entity-subtype-autocomplete> |
80 | + <mat-form-field class="mat-block"> | |
81 | + <mat-label translate>asset.label</mat-label> | |
82 | + <input matInput formControlName="label"> | |
83 | + </mat-form-field> | |
80 | 84 | <div formGroupName="additionalInfo"> |
81 | 85 | <mat-form-field class="mat-block"> |
82 | 86 | <mat-label translate>asset.description</mat-label> | ... | ... |
... | ... | @@ -64,6 +64,7 @@ export class AssetComponent extends EntityComponent<AssetInfo> { |
64 | 64 | { |
65 | 65 | name: [entity ? entity.name : '', [Validators.required]], |
66 | 66 | type: [entity ? entity.type : null, [Validators.required]], |
67 | + label: [entity ? entity.label : ''], | |
67 | 68 | additionalInfo: this.fb.group( |
68 | 69 | { |
69 | 70 | description: [entity && entity.additionalInfo ? entity.additionalInfo.description : ''], |
... | ... | @@ -76,6 +77,7 @@ export class AssetComponent extends EntityComponent<AssetInfo> { |
76 | 77 | updateForm(entity: AssetInfo) { |
77 | 78 | this.entityForm.patchValue({name: entity.name}); |
78 | 79 | this.entityForm.patchValue({type: entity.type}); |
80 | + this.entityForm.patchValue({label: entity.label}); | |
79 | 81 | this.entityForm.patchValue({additionalInfo: {description: entity.additionalInfo ? entity.additionalInfo.description : ''}}); |
80 | 82 | } |
81 | 83 | ... | ... |
... | ... | @@ -57,6 +57,7 @@ import { AssetTableHeaderComponent } from '@modules/home/pages/asset/asset-table |
57 | 57 | import { AssetId } from '@app/shared/models/id/asset-id'; |
58 | 58 | import { AssetTabsComponent } from '@home/pages/asset/asset-tabs.component'; |
59 | 59 | import { HomeDialogsService } from '@home/dialogs/home-dialogs.service'; |
60 | +import { DeviceInfo } from '@shared/models/device.models'; | |
60 | 61 | |
61 | 62 | @Injectable() |
62 | 63 | export class AssetsTableConfigResolver implements Resolve<EntityTableConfig<AssetInfo>> { |
... | ... | @@ -146,12 +147,13 @@ export class AssetsTableConfigResolver implements Resolve<EntityTableConfig<Asse |
146 | 147 | configureColumns(assetScope: string): Array<EntityTableColumn<AssetInfo>> { |
147 | 148 | const columns: Array<EntityTableColumn<AssetInfo>> = [ |
148 | 149 | new DateEntityTableColumn<AssetInfo>('createdTime', 'asset.created-time', this.datePipe, '150px'), |
149 | - new EntityTableColumn<AssetInfo>('name', 'asset.name', '33%'), | |
150 | - new EntityTableColumn<AssetInfo>('type', 'asset.asset-type', '33%'), | |
150 | + new EntityTableColumn<AssetInfo>('name', 'asset.name', '25%'), | |
151 | + new EntityTableColumn<AssetInfo>('type', 'asset.asset-type', '25%'), | |
152 | + new EntityTableColumn<DeviceInfo>('label', 'asset.label', '25%'), | |
151 | 153 | ]; |
152 | 154 | if (assetScope === 'tenant') { |
153 | 155 | columns.push( |
154 | - new EntityTableColumn<AssetInfo>('customerTitle', 'customer.customer', '33%'), | |
156 | + new EntityTableColumn<AssetInfo>('customerTitle', 'customer.customer', '25%'), | |
155 | 157 | new EntityTableColumn<AssetInfo>('customerIsPublic', 'asset.public', '60px', |
156 | 158 | entity => { |
157 | 159 | return checkBoxCell(entity.customerIsPublic); | ... | ... |