Merge import device/asset functionality

This commit is contained in:
Igor Kulikov 2020-02-20 16:35:11 +02:00
parent f1ca4c7cfd
commit 05f0619a2d
11 changed files with 99 additions and 14 deletions

View File

@ -805,14 +805,28 @@ export class EntityService {
case EntityType.DEVICE: case EntityType.DEVICE:
const device: Device = { const device: Device = {
name: entityData.name, name: entityData.name,
type: entityData.type type: entityData.type,
label: entityData.label,
additionalInfo: {
description: entityData.description
}
}; };
if (entityData.gateway !== null) {
device.additionalInfo = {
...device.additionalInfo,
gateway: entityData.gateway
};
}
saveEntityObservable = this.deviceService.saveDevice(device, config); saveEntityObservable = this.deviceService.saveDevice(device, config);
break; break;
case EntityType.ASSET: case EntityType.ASSET:
const asset: Asset = { const asset: Asset = {
name: entityData.name, name: entityData.name,
type: entityData.type type: entityData.type,
label: entityData.label,
additionalInfo: {
description: entityData.description
}
}; };
saveEntityObservable = this.assetService.saveAsset(asset, config); saveEntityObservable = this.assetService.saveAsset(asset, config);
break; break;
@ -839,7 +853,31 @@ export class EntityService {
} }
return findEntityObservable.pipe( return findEntityObservable.pipe(
mergeMap((entity) => { mergeMap((entity) => {
return this.saveEntityData(entity.id, entityData, config).pipe( const tasks: Observable<any>[] = [];
const result: Device | Asset = entity as (Device | Asset);
const additionalInfo = result.additionalInfo || {};
if(result.label !== entityData.label ||
result.type !== entityData.type ||
additionalInfo.description !== entityData.description ||
(result.id.entityType === EntityType.DEVICE && (additionalInfo.gateway !== entityData.gateway)) ) {
result.label = entityData.label;
result.type = entityData.type;
result.additionalInfo = additionalInfo;
result.additionalInfo.description = entityData.description;
if (result.id.entityType === EntityType.DEVICE) {
result.additionalInfo.gateway = entityData.gateway;
}
switch (result.id.entityType) {
case EntityType.DEVICE:
tasks.push(this.deviceService.saveDevice(result, config));
break;
case EntityType.ASSET:
tasks.push(this.assetService.saveAsset(result, config));
break;
}
}
tasks.push(this.saveEntityData(entity.id, entityData, config));
return forkJoin(tasks).pipe(
map(() => { map(() => {
return { update: { entity: 1 } } as ImportEntitiesResultInfo; return { update: { entity: 1 } } as ImportEntitiesResultInfo;
}), }),

View File

@ -168,7 +168,7 @@ 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)$/im) === 0) { if (isHeader && this.parseData.headers[i].search(/^(name|type|label)$/im) === 0) {
columnParam = { columnParam = {
type: ImportEntityColumnType[this.parseData.headers[i].toLowerCase()], type: ImportEntityColumnType[this.parseData.headers[i].toLowerCase()],
key: this.parseData.headers[i].toLowerCase(), key: this.parseData.headers[i].toLowerCase(),
@ -195,6 +195,9 @@ export class ImportDialogCsvComponent extends DialogComponent<ImportDialogCsvCom
const entityData: ImportEntityData = { const entityData: ImportEntityData = {
name: '', name: '',
type: '', type: '',
description: '',
gateway: null,
label: '',
accessToken: '', accessToken: '',
attributes: { attributes: {
server: [], server: [],
@ -232,6 +235,15 @@ export class ImportDialogCsvComponent extends DialogComponent<ImportDialogCsvCom
case ImportEntityColumnType.type: case ImportEntityColumnType.type:
entityData.type = importData.rows[i][j]; entityData.type = importData.rows[i][j];
break; break;
case ImportEntityColumnType.label:
entityData.label = importData.rows[i][j];
break;
case ImportEntityColumnType.isGateway:
entityData.gateway = importData.rows[i][j];
break;
case ImportEntityColumnType.description:
entityData.description = importData.rows[i][j];
break;
} }
} }
entitiesData.push(entityData); entitiesData.push(entityData);

View File

@ -44,12 +44,15 @@ export interface CsvToJsonResult {
export enum ImportEntityColumnType { export enum ImportEntityColumnType {
name = 'NAME', name = 'NAME',
type = 'TYPE', type = 'TYPE',
label = 'LABEL',
clientAttribute = 'CLIENT_ATTRIBUTE', clientAttribute = 'CLIENT_ATTRIBUTE',
sharedAttribute = 'SHARED_ATTRIBUTE', sharedAttribute = 'SHARED_ATTRIBUTE',
serverAttribute = 'SERVER_ATTRIBUTE', serverAttribute = 'SERVER_ATTRIBUTE',
timeseries = 'TIMESERIES', timeseries = 'TIMESERIES',
entityField = 'ENTITY_FIELD', entityField = 'ENTITY_FIELD',
accessToken = 'ACCESS_TOKEN' accessToken = 'ACCESS_TOKEN',
isGateway = 'IS_GATEWAY',
description = 'DESCRIPTION'
} }
export const importEntityObjectColumns = export const importEntityObjectColumns =
@ -59,12 +62,15 @@ export const importEntityColumnTypeTranslations = new Map<ImportEntityColumnType
[ [
[ImportEntityColumnType.name, 'import.column-type.name'], [ImportEntityColumnType.name, 'import.column-type.name'],
[ImportEntityColumnType.type, 'import.column-type.type'], [ImportEntityColumnType.type, 'import.column-type.type'],
[ImportEntityColumnType.label, 'import.column-type.label'],
[ImportEntityColumnType.clientAttribute, 'import.column-type.client-attribute'], [ImportEntityColumnType.clientAttribute, 'import.column-type.client-attribute'],
[ImportEntityColumnType.sharedAttribute, 'import.column-type.shared-attribute'], [ImportEntityColumnType.sharedAttribute, 'import.column-type.shared-attribute'],
[ImportEntityColumnType.serverAttribute, 'import.column-type.server-attribute'], [ImportEntityColumnType.serverAttribute, 'import.column-type.server-attribute'],
[ImportEntityColumnType.timeseries, 'import.column-type.timeseries'], [ImportEntityColumnType.timeseries, 'import.column-type.timeseries'],
[ImportEntityColumnType.entityField, 'import.column-type.entity-field'], [ImportEntityColumnType.entityField, 'import.column-type.entity-field'],
[ImportEntityColumnType.accessToken, 'import.column-type.access-token'], [ImportEntityColumnType.accessToken, 'import.column-type.access-token'],
[ImportEntityColumnType.isGateway, 'import.column-type.isgateway'],
[ImportEntityColumnType.description, 'import.column-type.description'],
] ]
); );
@ -136,7 +142,7 @@ function convertStringToJSType(str: string): any {
return parseFloat(str.replace(',', '.')); return parseFloat(str.replace(',', '.'));
} }
if (str.search(/^(true|false)$/im) === 0) { if (str.search(/^(true|false)$/im) === 0) {
return str === 'true'; return str.toLowerCase() === 'true';
} }
if (str === '') { if (str === '') {
return null; return null;

View File

@ -42,9 +42,7 @@
<mat-header-cell *matHeaderCellDef style="width: 30%"> {{ 'import.column-key' | translate }} </mat-header-cell> <mat-header-cell *matHeaderCellDef style="width: 30%"> {{ 'import.column-key' | translate }} </mat-header-cell>
<mat-cell *matCellDef="let column"> <mat-cell *matCellDef="let column">
<mat-form-field floatLabel="always" hideRequiredMarker <mat-form-field floatLabel="always" hideRequiredMarker
*ngIf="column.type !== importEntityColumnType.name && *ngIf="isColumnTypeDiffers(column.type)">
column.type !== importEntityColumnType.type &&
column.type !== importEntityColumnType.accessToken">
<mat-label></mat-label> <mat-label></mat-label>
<input matInput required <input matInput required
[(ngModel)]="column.key" (ngModelChange)="columnsUpdated()" [(ngModel)]="column.key" (ngModelChange)="columnsUpdated()"

View File

@ -72,6 +72,8 @@ export class TableColumnsAssignmentComponent implements OnInit, ControlValueAcce
this.columnTypes.push( this.columnTypes.push(
{ value: ImportEntityColumnType.name }, { value: ImportEntityColumnType.name },
{ value: ImportEntityColumnType.type }, { value: ImportEntityColumnType.type },
{ value: ImportEntityColumnType.label },
{ value: ImportEntityColumnType.description },
); );
switch (this.entityType) { switch (this.entityType) {
case EntityType.DEVICE: case EntityType.DEVICE:
@ -79,7 +81,8 @@ export class TableColumnsAssignmentComponent implements OnInit, ControlValueAcce
{ value: ImportEntityColumnType.sharedAttribute }, { value: ImportEntityColumnType.sharedAttribute },
{ value: ImportEntityColumnType.serverAttribute }, { value: ImportEntityColumnType.serverAttribute },
{ value: ImportEntityColumnType.timeseries }, { value: ImportEntityColumnType.timeseries },
{ value: ImportEntityColumnType.accessToken } { value: ImportEntityColumnType.accessToken },
{ value: ImportEntityColumnType.isGateway }
); );
break; break;
case EntityType.ASSET: case EntityType.ASSET:
@ -109,13 +112,20 @@ export class TableColumnsAssignmentComponent implements OnInit, ControlValueAcce
columnsUpdated() { columnsUpdated() {
const isSelectName = this.columns.findIndex((column) => column.type === ImportEntityColumnType.name) > -1; const isSelectName = this.columns.findIndex((column) => column.type === ImportEntityColumnType.name) > -1;
const isSelectType = this.columns.findIndex((column) => column.type === ImportEntityColumnType.type) > -1; const isSelectType = this.columns.findIndex((column) => column.type === ImportEntityColumnType.type) > -1;
const isSelectLabel = this.columns.findIndex((column) => column.type === ImportEntityColumnType.label) > -1;
const isSelectCredentials = this.columns.findIndex((column) => column.type === ImportEntityColumnType.accessToken) > -1; const isSelectCredentials = this.columns.findIndex((column) => column.type === ImportEntityColumnType.accessToken) > -1;
const isSelectGateway = this.columns.findIndex((column) => column.type === ImportEntityColumnType.isGateway) > -1;
const isSelectDescription = this.columns.findIndex((column) => column.type === ImportEntityColumnType.description) > -1;
const hasInvalidColumn = this.columns.findIndex((column) => !this.columnValid(column)) > -1; const hasInvalidColumn = this.columns.findIndex((column) => !this.columnValid(column)) > -1;
this.valid = isSelectName && isSelectType && !hasInvalidColumn; this.valid = isSelectName && isSelectType && !hasInvalidColumn;
this.columnTypes.find((columnType) => columnType.value === ImportEntityColumnType.name).disabled = isSelectName; this.columnTypes.find((columnType) => columnType.value === ImportEntityColumnType.name).disabled = isSelectName;
this.columnTypes.find((columnType) => columnType.value === ImportEntityColumnType.type).disabled = isSelectType; this.columnTypes.find((columnType) => columnType.value === ImportEntityColumnType.type).disabled = isSelectType;
this.columnTypes.find((columnType) => columnType.value === ImportEntityColumnType.label).disabled = isSelectLabel;
this.columnTypes.find((columnType) => columnType.value === ImportEntityColumnType.isGateway).disabled = isSelectGateway;
this.columnTypes.find((columnType) => columnType.value === ImportEntityColumnType.description).disabled = isSelectDescription;
const accessTokenColumnType = this.columnTypes.find((columnType) => columnType.value === ImportEntityColumnType.accessToken); const accessTokenColumnType = this.columnTypes.find((columnType) => columnType.value === ImportEntityColumnType.accessToken);
if (accessTokenColumnType) { if (accessTokenColumnType) {
accessTokenColumnType.disabled = isSelectCredentials; accessTokenColumnType.disabled = isSelectCredentials;
@ -127,6 +137,15 @@ export class TableColumnsAssignmentComponent implements OnInit, ControlValueAcce
} }
} }
public isColumnTypeDiffers(columnType: ImportEntityColumnType): boolean {
return columnType !== ImportEntityColumnType.name &&
columnType !== ImportEntityColumnType.type &&
columnType !== ImportEntityColumnType.label &&
columnType !== ImportEntityColumnType.accessToken &&
columnType !== ImportEntityColumnType.isGateway &&
columnType !== ImportEntityColumnType.description;
}
private columnValid(column: CsvColumnParam): boolean { private columnValid(column: CsvColumnParam): boolean {
if (!importEntityObjectColumns.includes(column.type)) { if (!importEntityObjectColumns.includes(column.type)) {
return column.key && column.key.trim().length > 0; return column.key && column.key.trim().length > 0;

View File

@ -77,6 +77,10 @@
[entityType]="entityType.ASSET" [entityType]="entityType.ASSET"
> >
</tb-entity-subtype-autocomplete> </tb-entity-subtype-autocomplete>
<mat-form-field class="mat-block">
<mat-label translate>asset.label</mat-label>
<input matInput formControlName="label">
</mat-form-field>
<div formGroupName="additionalInfo"> <div formGroupName="additionalInfo">
<mat-form-field class="mat-block"> <mat-form-field class="mat-block">
<mat-label translate>asset.description</mat-label> <mat-label translate>asset.description</mat-label>

View File

@ -64,6 +64,7 @@ export class AssetComponent extends EntityComponent<AssetInfo> {
{ {
name: [entity ? entity.name : '', [Validators.required]], name: [entity ? entity.name : '', [Validators.required]],
type: [entity ? entity.type : null, [Validators.required]], type: [entity ? entity.type : null, [Validators.required]],
label: [entity ? entity.label : ''],
additionalInfo: this.fb.group( additionalInfo: this.fb.group(
{ {
description: [entity && entity.additionalInfo ? entity.additionalInfo.description : ''], description: [entity && entity.additionalInfo ? entity.additionalInfo.description : ''],
@ -76,6 +77,7 @@ export class AssetComponent extends EntityComponent<AssetInfo> {
updateForm(entity: AssetInfo) { updateForm(entity: AssetInfo) {
this.entityForm.patchValue({name: entity.name}); this.entityForm.patchValue({name: entity.name});
this.entityForm.patchValue({type: entity.type}); this.entityForm.patchValue({type: entity.type});
this.entityForm.patchValue({label: entity.label});
this.entityForm.patchValue({additionalInfo: {description: entity.additionalInfo ? entity.additionalInfo.description : ''}}); this.entityForm.patchValue({additionalInfo: {description: entity.additionalInfo ? entity.additionalInfo.description : ''}});
} }

View File

@ -57,6 +57,7 @@ import { AssetTableHeaderComponent } from '@modules/home/pages/asset/asset-table
import { AssetId } from '@app/shared/models/id/asset-id'; import { AssetId } from '@app/shared/models/id/asset-id';
import { AssetTabsComponent } from '@home/pages/asset/asset-tabs.component'; import { AssetTabsComponent } from '@home/pages/asset/asset-tabs.component';
import { HomeDialogsService } from '@home/dialogs/home-dialogs.service'; import { HomeDialogsService } from '@home/dialogs/home-dialogs.service';
import { DeviceInfo } from '@shared/models/device.models';
@Injectable() @Injectable()
export class AssetsTableConfigResolver implements Resolve<EntityTableConfig<AssetInfo>> { export class AssetsTableConfigResolver implements Resolve<EntityTableConfig<AssetInfo>> {
@ -146,12 +147,13 @@ export class AssetsTableConfigResolver implements Resolve<EntityTableConfig<Asse
configureColumns(assetScope: string): Array<EntityTableColumn<AssetInfo>> { configureColumns(assetScope: string): Array<EntityTableColumn<AssetInfo>> {
const columns: Array<EntityTableColumn<AssetInfo>> = [ const columns: Array<EntityTableColumn<AssetInfo>> = [
new DateEntityTableColumn<AssetInfo>('createdTime', 'asset.created-time', this.datePipe, '150px'), new DateEntityTableColumn<AssetInfo>('createdTime', 'asset.created-time', this.datePipe, '150px'),
new EntityTableColumn<AssetInfo>('name', 'asset.name', '33%'), new EntityTableColumn<AssetInfo>('name', 'asset.name', '25%'),
new EntityTableColumn<AssetInfo>('type', 'asset.asset-type', '33%'), new EntityTableColumn<AssetInfo>('type', 'asset.asset-type', '25%'),
new EntityTableColumn<DeviceInfo>('label', 'asset.label', '25%'),
]; ];
if (assetScope === 'tenant') { if (assetScope === 'tenant') {
columns.push( columns.push(
new EntityTableColumn<AssetInfo>('customerTitle', 'customer.customer', '33%'), new EntityTableColumn<AssetInfo>('customerTitle', 'customer.customer', '25%'),
new EntityTableColumn<AssetInfo>('customerIsPublic', 'asset.public', '60px', new EntityTableColumn<AssetInfo>('customerIsPublic', 'asset.public', '60px',
entity => { entity => {
return checkBoxCell(entity.customerIsPublic); return checkBoxCell(entity.customerIsPublic);

View File

@ -26,6 +26,7 @@ export interface Asset extends BaseData<AssetId> {
customerId?: CustomerId; customerId?: CustomerId;
name: string; name: string;
type: string; type: string;
label: string;
additionalInfo?: any; additionalInfo?: any;
} }

View File

@ -26,7 +26,7 @@ export interface Device extends BaseData<DeviceId> {
customerId?: CustomerId; customerId?: CustomerId;
name: string; name: string;
type: string; type: string;
label?: string; label: string;
additionalInfo?: any; additionalInfo?: any;
} }

View File

@ -31,6 +31,9 @@ export interface EntityInfo {
export interface ImportEntityData { export interface ImportEntityData {
name: string; name: string;
type: string; type: string;
label: string;
gateway: boolean;
description: string;
accessToken: string; accessToken: string;
attributes: { attributes: {
server: AttributeData[], server: AttributeData[],