|
|
@ -14,7 +14,7 @@ |
|
|
/// limitations under the License.
|
|
|
/// limitations under the License.
|
|
|
///
|
|
|
///
|
|
|
|
|
|
|
|
|
import { Component, Inject, OnInit, ViewChild } from '@angular/core'; |
|
|
import { AfterViewInit, Component, ElementRef, Inject, Renderer2, ViewChild } from '@angular/core'; |
|
|
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; |
|
|
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; |
|
|
import { Store } from '@ngrx/store'; |
|
|
import { Store } from '@ngrx/store'; |
|
|
import { AppState } from '@core/core.state'; |
|
|
import { AppState } from '@core/core.state'; |
|
|
@ -34,6 +34,12 @@ import { |
|
|
} from '@home/components/import-export/import-export.models'; |
|
|
} from '@home/components/import-export/import-export.models'; |
|
|
import { EdgeImportEntityData, ImportEntitiesResultInfo, ImportEntityData } from '@app/shared/models/entity.models'; |
|
|
import { EdgeImportEntityData, ImportEntitiesResultInfo, ImportEntityData } from '@app/shared/models/entity.models'; |
|
|
import { ImportExportService } from '@home/components/import-export/import-export.service'; |
|
|
import { ImportExportService } from '@home/components/import-export/import-export.service'; |
|
|
|
|
|
import { TableColumnsAssignmentComponent } from '@home/components/import-export/table-columns-assignment.component'; |
|
|
|
|
|
import { getDeviceCredentialMQTTDefault } from '@shared/models/device.models'; |
|
|
|
|
|
import { isDefinedAndNotNull } from '@core/utils'; |
|
|
|
|
|
import { getLwm2mSecurityConfigModelsDefault } from '@shared/models/lwm2m-security-config.models'; |
|
|
|
|
|
import { Ace } from 'ace-builds'; |
|
|
|
|
|
import { getAce } from '@shared/models/ace/ace.models'; |
|
|
|
|
|
|
|
|
export interface ImportDialogCsvData { |
|
|
export interface ImportDialogCsvData { |
|
|
entityType: EntityType; |
|
|
entityType: EntityType; |
|
|
@ -48,15 +54,21 @@ export interface ImportDialogCsvData { |
|
|
styleUrls: ['./import-dialog-csv.component.scss'] |
|
|
styleUrls: ['./import-dialog-csv.component.scss'] |
|
|
}) |
|
|
}) |
|
|
export class ImportDialogCsvComponent extends DialogComponent<ImportDialogCsvComponent, boolean> |
|
|
export class ImportDialogCsvComponent extends DialogComponent<ImportDialogCsvComponent, boolean> |
|
|
implements OnInit { |
|
|
implements AfterViewInit { |
|
|
|
|
|
|
|
|
@ViewChild('importStepper', {static: true}) importStepper: MatVerticalStepper; |
|
|
@ViewChild('importStepper', {static: true}) importStepper: MatVerticalStepper; |
|
|
|
|
|
|
|
|
|
|
|
@ViewChild('columnsAssignmentComponent', {static: true}) |
|
|
|
|
|
columnsAssignmentComponent: TableColumnsAssignmentComponent; |
|
|
|
|
|
|
|
|
|
|
|
@ViewChild('failureDetailsEditor') |
|
|
|
|
|
failureDetailsEditorElmRef: ElementRef; |
|
|
|
|
|
|
|
|
entityType: EntityType; |
|
|
entityType: EntityType; |
|
|
importTitle: string; |
|
|
importTitle: string; |
|
|
importFileLabel: string; |
|
|
importFileLabel: string; |
|
|
|
|
|
|
|
|
delimiters: {key: string, value: string}[] = [{ |
|
|
delimiters: { key: string, value: string }[] = [{ |
|
|
key: ',', |
|
|
key: ',', |
|
|
value: ',' |
|
|
value: ',' |
|
|
}, { |
|
|
}, { |
|
|
@ -80,6 +92,8 @@ export class ImportDialogCsvComponent extends DialogComponent<ImportDialogCsvCom |
|
|
progressCreate = 0; |
|
|
progressCreate = 0; |
|
|
statistical: ImportEntitiesResultInfo; |
|
|
statistical: ImportEntitiesResultInfo; |
|
|
|
|
|
|
|
|
|
|
|
private allowAssignColumn: ImportEntityColumnType[]; |
|
|
|
|
|
private initEditorComponent = false; |
|
|
private parseData: CsvToJsonResult; |
|
|
private parseData: CsvToJsonResult; |
|
|
|
|
|
|
|
|
constructor(protected store: Store<AppState>, |
|
|
constructor(protected store: Store<AppState>, |
|
|
@ -88,7 +102,8 @@ export class ImportDialogCsvComponent extends DialogComponent<ImportDialogCsvCom |
|
|
public dialogRef: MatDialogRef<ImportDialogCsvComponent, boolean>, |
|
|
public dialogRef: MatDialogRef<ImportDialogCsvComponent, boolean>, |
|
|
public translate: TranslateService, |
|
|
public translate: TranslateService, |
|
|
private importExport: ImportExportService, |
|
|
private importExport: ImportExportService, |
|
|
private fb: FormBuilder) { |
|
|
private fb: FormBuilder, |
|
|
|
|
|
private renderer: Renderer2) { |
|
|
super(store, router, dialogRef); |
|
|
super(store, router, dialogRef); |
|
|
this.entityType = data.entityType; |
|
|
this.entityType = data.entityType; |
|
|
this.importTitle = data.importTitle; |
|
|
this.importTitle = data.importTitle; |
|
|
@ -109,7 +124,12 @@ export class ImportDialogCsvComponent extends DialogComponent<ImportDialogCsvCom |
|
|
}); |
|
|
}); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
ngOnInit(): void { |
|
|
ngAfterViewInit() { |
|
|
|
|
|
let columns = this.columnsAssignmentComponent.columnTypes; |
|
|
|
|
|
if (this.entityType === EntityType.DEVICE) { |
|
|
|
|
|
columns = columns.concat(this.columnsAssignmentComponent.columnDeviceCredentials); |
|
|
|
|
|
} |
|
|
|
|
|
this.allowAssignColumn = columns.map(column => column.value); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
cancel(): void { |
|
|
cancel(): void { |
|
|
@ -157,8 +177,10 @@ export class ImportDialogCsvComponent extends DialogComponent<ImportDialogCsvCom |
|
|
return convertCSVToJson(importData, config, |
|
|
return convertCSVToJson(importData, config, |
|
|
(messageId, params) => { |
|
|
(messageId, params) => { |
|
|
this.store.dispatch(new ActionNotificationShow( |
|
|
this.store.dispatch(new ActionNotificationShow( |
|
|
{message: this.translate.instant(messageId, params), |
|
|
{ |
|
|
type: 'error'})); |
|
|
message: this.translate.instant(messageId, params), |
|
|
|
|
|
type: 'error' |
|
|
|
|
|
})); |
|
|
} |
|
|
} |
|
|
); |
|
|
); |
|
|
} |
|
|
} |
|
|
@ -168,9 +190,14 @@ export class ImportDialogCsvComponent extends DialogComponent<ImportDialogCsvCom |
|
|
const isHeader: boolean = this.importParametersFormGroup.get('isHeader').value; |
|
|
const isHeader: boolean = this.importParametersFormGroup.get('isHeader').value; |
|
|
for (let i = 0; i < this.parseData.headers.length; i++) { |
|
|
for (let i = 0; i < this.parseData.headers.length; i++) { |
|
|
let columnParam: CsvColumnParam; |
|
|
let columnParam: CsvColumnParam; |
|
|
if (isHeader && this.parseData.headers[i].search(/^(name|type|label)$/im) === 0) { |
|
|
let findEntityColumnType: ImportEntityColumnType; |
|
|
|
|
|
if (isHeader) { |
|
|
|
|
|
const headerColumnName = this.parseData.headers[i].toUpperCase(); |
|
|
|
|
|
findEntityColumnType = this.allowAssignColumn.find(column => column === headerColumnName); |
|
|
|
|
|
} |
|
|
|
|
|
if (isHeader && findEntityColumnType) { |
|
|
columnParam = { |
|
|
columnParam = { |
|
|
type: ImportEntityColumnType[this.parseData.headers[i].toLowerCase()], |
|
|
type: findEntityColumnType, |
|
|
key: this.parseData.headers[i].toLowerCase(), |
|
|
key: this.parseData.headers[i].toLowerCase(), |
|
|
sampleData: this.parseData.rows[0][i] |
|
|
sampleData: this.parseData.rows[0][i] |
|
|
}; |
|
|
}; |
|
|
@ -189,13 +216,19 @@ export class ImportDialogCsvComponent extends DialogComponent<ImportDialogCsvCom |
|
|
|
|
|
|
|
|
private addEntities() { |
|
|
private addEntities() { |
|
|
const importData = this.parseData; |
|
|
const importData = this.parseData; |
|
|
|
|
|
const isHeader: boolean = this.importParametersFormGroup.get('isHeader').value; |
|
|
const parameterColumns: CsvColumnParam[] = this.columnTypesFormGroup.get('columnsParam').value; |
|
|
const parameterColumns: CsvColumnParam[] = this.columnTypesFormGroup.get('columnsParam').value; |
|
|
const entitiesData: ImportEntityData[] = []; |
|
|
const entitiesData: ImportEntityData[] = []; |
|
|
let sentDataLength = 0; |
|
|
let sentDataLength = 0; |
|
|
|
|
|
const startLineNumber = isHeader ? 2 : 1; |
|
|
for (let row = 0; row < importData.rows.length; row++) { |
|
|
for (let row = 0; row < importData.rows.length; row++) { |
|
|
const entityData: ImportEntityData = this.constructDraftImportEntityData(); |
|
|
const entityData: ImportEntityData = this.constructDraftImportEntityData(); |
|
|
const i = row; |
|
|
const i = row; |
|
|
|
|
|
entityData.lineNumber = startLineNumber + i; |
|
|
for (let j = 0; j < parameterColumns.length; j++) { |
|
|
for (let j = 0; j < parameterColumns.length; j++) { |
|
|
|
|
|
if (!isDefinedAndNotNull(importData.rows[i][j]) || importData.rows[i][j] === '') { |
|
|
|
|
|
continue; |
|
|
|
|
|
} |
|
|
switch (parameterColumns[j].type) { |
|
|
switch (parameterColumns[j].type) { |
|
|
case ImportEntityColumnType.serverAttribute: |
|
|
case ImportEntityColumnType.serverAttribute: |
|
|
entityData.attributes.server.push({ |
|
|
entityData.attributes.server.push({ |
|
|
@ -215,9 +248,6 @@ export class ImportDialogCsvComponent extends DialogComponent<ImportDialogCsvCom |
|
|
value: importData.rows[i][j] |
|
|
value: importData.rows[i][j] |
|
|
}); |
|
|
}); |
|
|
break; |
|
|
break; |
|
|
case ImportEntityColumnType.accessToken: |
|
|
|
|
|
entityData.accessToken = importData.rows[i][j]; |
|
|
|
|
|
break; |
|
|
|
|
|
case ImportEntityColumnType.name: |
|
|
case ImportEntityColumnType.name: |
|
|
entityData.name = importData.rows[i][j]; |
|
|
entityData.name = importData.rows[i][j]; |
|
|
break; |
|
|
break; |
|
|
@ -233,6 +263,96 @@ export class ImportDialogCsvComponent extends DialogComponent<ImportDialogCsvCom |
|
|
case ImportEntityColumnType.description: |
|
|
case ImportEntityColumnType.description: |
|
|
entityData.description = importData.rows[i][j]; |
|
|
entityData.description = importData.rows[i][j]; |
|
|
break; |
|
|
break; |
|
|
|
|
|
case ImportEntityColumnType.accessToken: |
|
|
|
|
|
entityData.credential.accessToken = importData.rows[i][j]; |
|
|
|
|
|
break; |
|
|
|
|
|
case ImportEntityColumnType.x509: |
|
|
|
|
|
entityData.credential.x509 = importData.rows[i][j]; |
|
|
|
|
|
break; |
|
|
|
|
|
case ImportEntityColumnType.mqttClientId: |
|
|
|
|
|
if (!entityData.credential.mqtt) { |
|
|
|
|
|
entityData.credential.mqtt = getDeviceCredentialMQTTDefault(); |
|
|
|
|
|
} |
|
|
|
|
|
entityData.credential.mqtt.clientId = importData.rows[i][j]; |
|
|
|
|
|
break; |
|
|
|
|
|
case ImportEntityColumnType.mqttUserName: |
|
|
|
|
|
if (!entityData.credential.mqtt) { |
|
|
|
|
|
entityData.credential.mqtt = getDeviceCredentialMQTTDefault(); |
|
|
|
|
|
} |
|
|
|
|
|
entityData.credential.mqtt.userName = importData.rows[i][j]; |
|
|
|
|
|
break; |
|
|
|
|
|
case ImportEntityColumnType.mqttPassword: |
|
|
|
|
|
if (!entityData.credential.mqtt) { |
|
|
|
|
|
entityData.credential.mqtt = getDeviceCredentialMQTTDefault(); |
|
|
|
|
|
} |
|
|
|
|
|
entityData.credential.mqtt.password = importData.rows[i][j]; |
|
|
|
|
|
break; |
|
|
|
|
|
case ImportEntityColumnType.lwm2mClientEndpoint: |
|
|
|
|
|
if (!entityData.credential.lwm2m) { |
|
|
|
|
|
entityData.credential.lwm2m = getLwm2mSecurityConfigModelsDefault(); |
|
|
|
|
|
} |
|
|
|
|
|
entityData.credential.lwm2m.client.endpoint = importData.rows[i][j]; |
|
|
|
|
|
break; |
|
|
|
|
|
case ImportEntityColumnType.lwm2mClientSecurityConfigMode: |
|
|
|
|
|
if (!entityData.credential.lwm2m) { |
|
|
|
|
|
entityData.credential.lwm2m = getLwm2mSecurityConfigModelsDefault(); |
|
|
|
|
|
} |
|
|
|
|
|
entityData.credential.lwm2m.client.securityConfigClientMode = importData.rows[i][j]; |
|
|
|
|
|
break; |
|
|
|
|
|
case ImportEntityColumnType.lwm2mClientIdentity: |
|
|
|
|
|
if (!entityData.credential.lwm2m) { |
|
|
|
|
|
entityData.credential.lwm2m = getLwm2mSecurityConfigModelsDefault(); |
|
|
|
|
|
} |
|
|
|
|
|
entityData.credential.lwm2m.client.identity = importData.rows[i][j]; |
|
|
|
|
|
break; |
|
|
|
|
|
case ImportEntityColumnType.lwm2mClientKey: |
|
|
|
|
|
if (!entityData.credential.lwm2m) { |
|
|
|
|
|
entityData.credential.lwm2m = getLwm2mSecurityConfigModelsDefault(); |
|
|
|
|
|
} |
|
|
|
|
|
entityData.credential.lwm2m.client.key = importData.rows[i][j]; |
|
|
|
|
|
break; |
|
|
|
|
|
case ImportEntityColumnType.lwm2mClientCert: |
|
|
|
|
|
if (!entityData.credential.lwm2m) { |
|
|
|
|
|
entityData.credential.lwm2m = getLwm2mSecurityConfigModelsDefault(); |
|
|
|
|
|
} |
|
|
|
|
|
entityData.credential.lwm2m.client.cert = importData.rows[i][j]; |
|
|
|
|
|
break; |
|
|
|
|
|
case ImportEntityColumnType.lwm2mBootstrapServerSecurityMode: |
|
|
|
|
|
if (!entityData.credential.lwm2m) { |
|
|
|
|
|
entityData.credential.lwm2m = getLwm2mSecurityConfigModelsDefault(); |
|
|
|
|
|
} |
|
|
|
|
|
entityData.credential.lwm2m.bootstrap.bootstrapServer.securityMode = importData.rows[i][j]; |
|
|
|
|
|
break; |
|
|
|
|
|
case ImportEntityColumnType.lwm2mBootstrapServerClientPublicKeyOrId: |
|
|
|
|
|
if (!entityData.credential.lwm2m) { |
|
|
|
|
|
entityData.credential.lwm2m = getLwm2mSecurityConfigModelsDefault(); |
|
|
|
|
|
} |
|
|
|
|
|
entityData.credential.lwm2m.bootstrap.bootstrapServer.clientPublicKeyOrId = importData.rows[i][j]; |
|
|
|
|
|
break; |
|
|
|
|
|
case ImportEntityColumnType.lwm2mBootstrapServerClientSecretKey: |
|
|
|
|
|
if (!entityData.credential.lwm2m) { |
|
|
|
|
|
entityData.credential.lwm2m = getLwm2mSecurityConfigModelsDefault(); |
|
|
|
|
|
} |
|
|
|
|
|
entityData.credential.lwm2m.bootstrap.bootstrapServer.clientSecretKey = importData.rows[i][j]; |
|
|
|
|
|
break; |
|
|
|
|
|
case ImportEntityColumnType.lwm2mServerSecurityMode: |
|
|
|
|
|
if (!entityData.credential.lwm2m) { |
|
|
|
|
|
entityData.credential.lwm2m = getLwm2mSecurityConfigModelsDefault(); |
|
|
|
|
|
} |
|
|
|
|
|
entityData.credential.lwm2m.bootstrap.lwm2mServer.securityMode = importData.rows[i][j]; |
|
|
|
|
|
break; |
|
|
|
|
|
case ImportEntityColumnType.lwm2mServerClientPublicKeyOrId: |
|
|
|
|
|
if (!entityData.credential.lwm2m) { |
|
|
|
|
|
entityData.credential.lwm2m = getLwm2mSecurityConfigModelsDefault(); |
|
|
|
|
|
} |
|
|
|
|
|
entityData.credential.lwm2m.bootstrap.lwm2mServer.clientPublicKeyOrId = importData.rows[i][j]; |
|
|
|
|
|
break; |
|
|
|
|
|
case ImportEntityColumnType.lwm2mServerClientSecretKey: |
|
|
|
|
|
if (!entityData.credential.lwm2m) { |
|
|
|
|
|
entityData.credential.lwm2m = getLwm2mSecurityConfigModelsDefault(); |
|
|
|
|
|
} |
|
|
|
|
|
entityData.credential.lwm2m.bootstrap.lwm2mServer.clientSecretKey = importData.rows[i][j]; |
|
|
|
|
|
break; |
|
|
case ImportEntityColumnType.edgeLicenseKey: |
|
|
case ImportEntityColumnType.edgeLicenseKey: |
|
|
(entityData as EdgeImportEntityData).edgeLicenseKey = importData.rows[i][j]; |
|
|
(entityData as EdgeImportEntityData).edgeLicenseKey = importData.rows[i][j]; |
|
|
break; |
|
|
break; |
|
|
@ -268,16 +388,17 @@ export class ImportDialogCsvComponent extends DialogComponent<ImportDialogCsvCom |
|
|
|
|
|
|
|
|
private constructDraftImportEntityData(): ImportEntityData { |
|
|
private constructDraftImportEntityData(): ImportEntityData { |
|
|
const entityData: ImportEntityData = { |
|
|
const entityData: ImportEntityData = { |
|
|
|
|
|
lineNumber: 1, |
|
|
name: '', |
|
|
name: '', |
|
|
type: '', |
|
|
type: '', |
|
|
description: '', |
|
|
description: '', |
|
|
gateway: null, |
|
|
gateway: null, |
|
|
label: '', |
|
|
label: '', |
|
|
accessToken: '', |
|
|
|
|
|
attributes: { |
|
|
attributes: { |
|
|
server: [], |
|
|
server: [], |
|
|
shared: [] |
|
|
shared: [] |
|
|
}, |
|
|
}, |
|
|
|
|
|
credential: {}, |
|
|
timeseries: [] |
|
|
timeseries: [] |
|
|
}; |
|
|
}; |
|
|
if (this.entityType === EntityType.EDGE) { |
|
|
if (this.entityType === EntityType.EDGE) { |
|
|
@ -292,5 +413,49 @@ export class ImportDialogCsvComponent extends DialogComponent<ImportDialogCsvCom |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
initEditor() { |
|
|
|
|
|
if (!this.initEditorComponent) { |
|
|
|
|
|
this.createEditor(this.failureDetailsEditorElmRef, this.statistical.error.errors); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private createEditor(editorElementRef: ElementRef, content: string): void { |
|
|
|
|
|
const editorElement = editorElementRef.nativeElement; |
|
|
|
|
|
let editorOptions: Partial<Ace.EditorOptions> = { |
|
|
|
|
|
mode: 'ace/mode/java', |
|
|
|
|
|
theme: 'ace/theme/github', |
|
|
|
|
|
showGutter: false, |
|
|
|
|
|
showPrintMargin: false, |
|
|
|
|
|
readOnly: true |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
const advancedOptions = { |
|
|
|
|
|
enableSnippets: false, |
|
|
|
|
|
enableBasicAutocompletion: false, |
|
|
|
|
|
enableLiveAutocompletion: false |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
editorOptions = {...editorOptions, ...advancedOptions}; |
|
|
|
|
|
getAce().subscribe( |
|
|
|
|
|
(ace) => { |
|
|
|
|
|
const editor = ace.edit(editorElement, editorOptions); |
|
|
|
|
|
editor.session.setUseWrapMode(false); |
|
|
|
|
|
editor.setValue(content, -1); |
|
|
|
|
|
this.updateEditorSize(editorElement, content, editor); |
|
|
|
|
|
} |
|
|
|
|
|
); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private updateEditorSize(editorElement: any, content: string, editor: Ace.Editor) { |
|
|
|
|
|
let newHeight = 200; |
|
|
|
|
|
if (content && content.length > 0) { |
|
|
|
|
|
const lines = content.split('\n'); |
|
|
|
|
|
newHeight = 16 * lines.length + 24; |
|
|
|
|
|
} |
|
|
|
|
|
const minHeight = Math.min(200, newHeight); |
|
|
|
|
|
this.renderer.setStyle(editorElement, 'minHeight', minHeight.toString() + 'px'); |
|
|
|
|
|
this.renderer.setStyle(editorElement, 'height', newHeight.toString() + 'px'); |
|
|
|
|
|
editor.resize(); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
} |
|
|
} |
|
|
|