UI: Delete externalID when import/export entity and fixed lint promplem in export-import service

This commit is contained in:
Vladyslav_Prykhodko 2023-12-15 16:40:00 +02:00
parent 5946bde4c6
commit 786bf1597d
4 changed files with 88 additions and 97 deletions

View File

@ -79,6 +79,8 @@ import { ImageService } from '@core/http/image.service';
import { ImageExportData, ImageResourceInfo, ImageResourceType } from '@shared/models/resource.models'; import { ImageExportData, ImageResourceInfo, ImageResourceType } from '@shared/models/resource.models';
import { selectUserSettingsProperty } from '@core/auth/auth.selectors'; import { selectUserSettingsProperty } from '@core/auth/auth.selectors';
import { ActionPreferencesPutUserSettings } from '@core/auth/auth.actions'; import { ActionPreferencesPutUserSettings } from '@core/auth/auth.actions';
import { ExportableEntity } from '@shared/models/base-data';
import { EntityId } from '@shared/models/id/entity-id';
export type editMissingAliasesFunction = (widgets: Array<Widget>, isSingleWidget: boolean, export type editMissingAliasesFunction = (widgets: Array<Widget>, isSingleWidget: boolean,
customTitle: string, missingEntityAliases: EntityAliases) => Observable<EntityAliases>; customTitle: string, missingEntityAliases: EntityAliases) => Observable<EntityAliases>;
@ -140,16 +142,16 @@ export class ImportExportService {
} }
public exportDashboard(dashboardId: string) { public exportDashboard(dashboardId: string) {
this.dashboardService.exportDashboard(dashboardId).subscribe( this.dashboardService.exportDashboard(dashboardId).subscribe({
(dashboard) => { next: (dashboard) => {
let name = dashboard.title; let name = dashboard.title;
name = name.toLowerCase().replace(/\W/g, '_'); name = name.toLowerCase().replace(/\W/g, '_');
this.exportToPc(this.prepareDashboardExport(dashboard), name); this.exportToPc(this.prepareDashboardExport(dashboard), name);
}, },
(e) => { error: (e) => {
this.handleExportError(e, 'dashboard.export-failed-error'); this.handleExportError(e, 'dashboard.export-failed-error');
} }
); });
} }
public importDashboard(onEditMissingAliases: editMissingAliasesFunction): Observable<Dashboard> { public importDashboard(onEditMissingAliases: editMissingAliasesFunction): Observable<Dashboard> {
@ -161,6 +163,7 @@ export class ImportExportService {
type: 'error'})); type: 'error'}));
throw new Error('Invalid dashboard file'); throw new Error('Invalid dashboard file');
} else { } else {
dashboard = this.prepareImport(dashboard);
dashboard = this.dashboardUtils.validateAndUpdateDashboard(dashboard); dashboard = this.dashboardUtils.validateAndUpdateDashboard(dashboard);
let aliasIds = null; let aliasIds = null;
const entityAliases = dashboard.configuration.entityAliases; const entityAliases = dashboard.configuration.entityAliases;
@ -191,9 +194,7 @@ export class ImportExportService {
} }
} }
}), }),
catchError((err) => { catchError(() => of(null))
return of(null);
})
); );
} }
@ -217,7 +218,7 @@ export class ImportExportService {
type: 'error'})); type: 'error'}));
throw new Error('Invalid widget file'); throw new Error('Invalid widget file');
} else { } else {
let widget = widgetItem.widget; let widget = this.prepareImport(widgetItem.widget);
widget = this.dashboardUtils.validateAndUpdateWidget(widget); widget = this.dashboardUtils.validateAndUpdateWidget(widget);
widget.id = guid(); widget.id = guid();
const aliasesInfo = this.prepareAliasesInfo(widgetItem.aliasesInfo); const aliasesInfo = this.prepareAliasesInfo(widgetItem.aliasesInfo);
@ -262,7 +263,7 @@ export class ImportExportService {
mergeMap((updatedEntityAliases) => { mergeMap((updatedEntityAliases) => {
for (const id of Object.keys(updatedEntityAliases)) { for (const id of Object.keys(updatedEntityAliases)) {
const entityAlias = updatedEntityAliases[id]; const entityAlias = updatedEntityAliases[id];
let index; let index: number;
if (isDefined(datasourceAliasesMap[id])) { if (isDefined(datasourceAliasesMap[id])) {
index = datasourceAliasesMap[id]; index = datasourceAliasesMap[id];
datasourceAliases[index] = entityAlias; datasourceAliases[index] = entityAlias;
@ -292,23 +293,21 @@ export class ImportExportService {
} }
} }
}), }),
catchError((err) => { catchError(() => of(null))
return of(null);
})
); );
} }
public exportWidgetType(widgetTypeId: string) { public exportWidgetType(widgetTypeId: string) {
this.widgetService.exportWidgetType(widgetTypeId).subscribe( this.widgetService.exportWidgetType(widgetTypeId).subscribe({
(widgetTypeDetails) => { next: (widgetTypeDetails) => {
let name = widgetTypeDetails.name; let name = widgetTypeDetails.name;
name = name.toLowerCase().replace(/\W/g, '_'); name = name.toLowerCase().replace(/\W/g, '_');
this.exportToPc(this.prepareExport(widgetTypeDetails), name); this.exportToPc(this.prepareExport(widgetTypeDetails), name);
}, },
(e) => { error: (e) => {
this.handleExportError(e, 'widget-type.export-failed-error'); this.handleExportError(e, 'widget-type.export-failed-error');
} }
); });
} }
public exportWidgetTypes(widgetTypeIds: string[]): Observable<void> { public exportWidgetTypes(widgetTypeIds: string[]): Observable<void> {
@ -341,7 +340,7 @@ export class ImportExportService {
type: 'error'})); type: 'error'}));
throw new Error('Invalid widget file'); throw new Error('Invalid widget file');
} else { } else {
return this.widgetService.saveImportedWidgetTypeDetails(widgetTypeDetails); return this.widgetService.saveImportedWidgetTypeDetails(this.prepareImport(widgetTypeDetails));
} }
}), }),
catchError(() => of(null)) catchError(() => of(null))
@ -386,8 +385,8 @@ export class ImportExportService {
} }
private exportWidgetsBundleWithWidgetTypes(widgetsBundle: WidgetsBundle) { private exportWidgetsBundleWithWidgetTypes(widgetsBundle: WidgetsBundle) {
this.widgetService.exportBundleWidgetTypesDetails(widgetsBundle.id.id).subscribe( this.widgetService.exportBundleWidgetTypesDetails(widgetsBundle.id.id).subscribe({
(widgetTypesDetails) => { next: (widgetTypesDetails) => {
const widgetsBundleItem: WidgetsBundleItem = { const widgetsBundleItem: WidgetsBundleItem = {
widgetsBundle: this.prepareExport(widgetsBundle), widgetsBundle: this.prepareExport(widgetsBundle),
widgetTypes: [] widgetTypes: []
@ -399,15 +398,15 @@ export class ImportExportService {
name = name.toLowerCase().replace(/\W/g, '_'); name = name.toLowerCase().replace(/\W/g, '_');
this.exportToPc(widgetsBundleItem, name); this.exportToPc(widgetsBundleItem, name);
}, },
(e) => { error: (e) => {
this.handleExportError(e, 'widgets-bundle.export-failed-error'); this.handleExportError(e, 'widgets-bundle.export-failed-error');
} }
); });
} }
private exportWidgetsBundleWithWidgetTypeFqns(widgetsBundle: WidgetsBundle) { private exportWidgetsBundleWithWidgetTypeFqns(widgetsBundle: WidgetsBundle) {
this.widgetService.getBundleWidgetTypeFqns(widgetsBundle.id.id).subscribe( this.widgetService.getBundleWidgetTypeFqns(widgetsBundle.id.id).subscribe({
(widgetTypeFqns) => { next: (widgetTypeFqns) => {
const widgetsBundleItem: WidgetsBundleItem = { const widgetsBundleItem: WidgetsBundleItem = {
widgetsBundle: this.prepareExport(widgetsBundle), widgetsBundle: this.prepareExport(widgetsBundle),
widgetTypeFqns widgetTypeFqns
@ -416,10 +415,10 @@ export class ImportExportService {
name = name.toLowerCase().replace(/\W/g, '_'); name = name.toLowerCase().replace(/\W/g, '_');
this.exportToPc(widgetsBundleItem, name); this.exportToPc(widgetsBundleItem, name);
}, },
(e) => { error: (e) => {
this.handleExportError(e, 'widgets-bundle.export-failed-error'); this.handleExportError(e, 'widgets-bundle.export-failed-error');
} }
); });
} }
public importWidgetsBundle(): Observable<WidgetsBundle> { public importWidgetsBundle(): Observable<WidgetsBundle> {
@ -431,7 +430,7 @@ export class ImportExportService {
type: 'error'})); type: 'error'}));
throw new Error('Invalid widgets bundle file'); throw new Error('Invalid widgets bundle file');
} else { } else {
const widgetsBundle = widgetsBundleItem.widgetsBundle; const widgetsBundle = this.prepareImport(widgetsBundleItem.widgetsBundle);
return this.widgetService.saveWidgetsBundle(widgetsBundle).pipe( return this.widgetService.saveWidgetsBundle(widgetsBundle).pipe(
mergeMap((savedWidgetsBundle) => { mergeMap((savedWidgetsBundle) => {
if (widgetsBundleItem.widgetTypes?.length || widgetsBundleItem.widgetTypeFqns?.length) { if (widgetsBundleItem.widgetTypes?.length || widgetsBundleItem.widgetTypeFqns?.length) {
@ -456,7 +455,7 @@ export class ImportExportService {
} }
if (widgetTypeFqns.length) { if (widgetTypeFqns.length) {
return this.widgetService.updateWidgetsBundleWidgetFqns(savedWidgetsBundle.id.id, widgetTypeFqns).pipe( return this.widgetService.updateWidgetsBundleWidgetFqns(savedWidgetsBundle.id.id, widgetTypeFqns).pipe(
map((res) => savedWidgetsBundle) map(() => savedWidgetsBundle)
); );
} else { } else {
return of(savedWidgetsBundle); return of(savedWidgetsBundle);
@ -470,9 +469,7 @@ export class ImportExportService {
)); ));
} }
}), }),
catchError((err) => { catchError(() => of(null))
return of(null);
})
); );
} }
@ -504,10 +501,9 @@ export class ImportExportService {
let statisticalInfo: ImportEntitiesResultInfo = {}; let statisticalInfo: ImportEntitiesResultInfo = {};
const importEntitiesObservables: Observable<ImportEntitiesResultInfo>[] = []; const importEntitiesObservables: Observable<ImportEntitiesResultInfo>[] = [];
for (let i = 0; i < partSize; i++) { for (let i = 0; i < partSize; i++) {
let saveEntityPromise: Observable<ImportEntitiesResultInfo>; const saveEntityPromise = this.entityService.saveEntityParameters(entityType, entitiesData[i], updateData, config);
saveEntityPromise = this.entityService.saveEntityParameters(entityType, entitiesData[i], updateData, config);
const importEntityPromise = saveEntityPromise.pipe( const importEntityPromise = saveEntityPromise.pipe(
tap((res) => { tap(() => {
if (importEntityCompleted) { if (importEntityCompleted) {
importEntityCompleted(); importEntityCompleted();
} }
@ -523,9 +519,7 @@ export class ImportExportService {
entitiesData.splice(0, partSize); entitiesData.splice(0, partSize);
if (entitiesData.length) { if (entitiesData.length) {
return this.importEntities(entitiesData, entityType, updateData, importEntityCompleted, config).pipe( return this.importEntities(entitiesData, entityType, updateData, importEntityCompleted, config).pipe(
map((response) => { map((response) => this.sumObject(statisticalInfo, response))
return this.sumObject(statisticalInfo, response) as ImportEntitiesResultInfo;
})
); );
} else { } else {
return of(statisticalInfo); return of(statisticalInfo);
@ -536,26 +530,25 @@ export class ImportExportService {
public exportRuleChain(ruleChainId: string) { public exportRuleChain(ruleChainId: string) {
this.ruleChainService.getRuleChain(ruleChainId).pipe( this.ruleChainService.getRuleChain(ruleChainId).pipe(
mergeMap(ruleChain => { mergeMap(ruleChain => this.ruleChainService.getRuleChainMetadata(ruleChainId).pipe(
return this.ruleChainService.getRuleChainMetadata(ruleChainId).pipe( map((ruleChainMetaData) => {
map((ruleChainMetaData) => { const ruleChainExport: RuleChainImport = {
const ruleChainExport: RuleChainImport = { ruleChain: this.prepareRuleChain(ruleChain),
ruleChain: this.prepareRuleChain(ruleChain), metadata: this.prepareRuleChainMetaData(ruleChainMetaData)
metadata: this.prepareRuleChainMetaData(ruleChainMetaData) };
}; return ruleChainExport;
return ruleChainExport; })
}) ))
); ).subscribe({
}) next: (ruleChainExport) => {
).subscribe((ruleChainExport) => {
let name = ruleChainExport.ruleChain.name; let name = ruleChainExport.ruleChain.name;
name = name.toLowerCase().replace(/\W/g, '_'); name = name.toLowerCase().replace(/\W/g, '_');
this.exportToPc(ruleChainExport, name); this.exportToPc(ruleChainExport, name);
}, },
(e) => { error: (e) => {
this.handleExportError(e, 'rulechain.export-failed-error'); this.handleExportError(e, 'rulechain.export-failed-error');
} }
); });
} }
public importRuleChain(expectedRuleChainType: RuleChainType): Observable<RuleChainImport> { public importRuleChain(expectedRuleChainType: RuleChainType): Observable<RuleChainImport> {
@ -575,13 +568,12 @@ export class ImportExportService {
return this.processOldRuleChainConnections(ruleChainImport); return this.processOldRuleChainConnections(ruleChainImport);
} }
}), }),
catchError((err) => { catchError(() => of(null))
return of(null);
})
); );
} }
private processOldRuleChainConnections(ruleChainImport: RuleChainImport): Observable<RuleChainImport> { private processOldRuleChainConnections(ruleChainImport: RuleChainImport): Observable<RuleChainImport> {
ruleChainImport.ruleChain = this.prepareImport(ruleChainImport.ruleChain);
const metadata = ruleChainImport.metadata; const metadata = ruleChainImport.metadata;
if ((metadata as any).ruleChainConnections) { if ((metadata as any).ruleChainConnections) {
const ruleChainNameResolveObservables: Observable<void>[] = []; const ruleChainNameResolveObservables: Observable<void>[] = [];
@ -599,9 +591,7 @@ export class ImportExportService {
}; };
ruleChainNameResolveObservables.push(this.ruleChainService.getRuleChain(ruleChainNode.configuration.ruleChainId, ruleChainNameResolveObservables.push(this.ruleChainService.getRuleChain(ruleChainNode.configuration.ruleChainId,
{ignoreErrors: true, ignoreLoading: true}).pipe( {ignoreErrors: true, ignoreLoading: true}).pipe(
catchError(err => { catchError(() => of({name: 'Rule Chain Input'} as RuleChain)),
return of({name: 'Rule Chain Input'} as RuleChain);
}),
map((ruleChain => { map((ruleChain => {
ruleChainNode.name = ruleChain.name; ruleChainNode.name = ruleChain.name;
return null; return null;
@ -630,16 +620,16 @@ export class ImportExportService {
} }
public exportDeviceProfile(deviceProfileId: string) { public exportDeviceProfile(deviceProfileId: string) {
this.deviceProfileService.exportDeviceProfile(deviceProfileId).subscribe( this.deviceProfileService.exportDeviceProfile(deviceProfileId).subscribe({
(deviceProfile) => { next: (deviceProfile) => {
let name = deviceProfile.name; let name = deviceProfile.name;
name = name.toLowerCase().replace(/\W/g, '_'); name = name.toLowerCase().replace(/\W/g, '_');
this.exportToPc(this.prepareProfileExport(deviceProfile), name); this.exportToPc(this.prepareProfileExport(deviceProfile), name);
}, },
(e) => { error: (e) => {
this.handleExportError(e, 'device-profile.export-failed-error'); this.handleExportError(e, 'device-profile.export-failed-error');
} }
); });
} }
public importDeviceProfile(): Observable<DeviceProfile> { public importDeviceProfile(): Observable<DeviceProfile> {
@ -651,26 +641,24 @@ export class ImportExportService {
type: 'error'})); type: 'error'}));
throw new Error('Invalid device profile file'); throw new Error('Invalid device profile file');
} else { } else {
return this.deviceProfileService.saveDeviceProfile(deviceProfile); return this.deviceProfileService.saveDeviceProfile(this.prepareImport(deviceProfile));
} }
}), }),
catchError((err) => { catchError(() => of(null))
return of(null);
})
); );
} }
public exportAssetProfile(assetProfileId: string) { public exportAssetProfile(assetProfileId: string) {
this.assetProfileService.exportAssetProfile(assetProfileId).subscribe( this.assetProfileService.exportAssetProfile(assetProfileId).subscribe({
(assetProfile) => { next: (assetProfile) => {
let name = assetProfile.name; let name = assetProfile.name;
name = name.toLowerCase().replace(/\W/g, '_'); name = name.toLowerCase().replace(/\W/g, '_');
this.exportToPc(this.prepareProfileExport(assetProfile), name); this.exportToPc(this.prepareProfileExport(assetProfile), name);
}, },
(e) => { error: (e) => {
this.handleExportError(e, 'asset-profile.export-failed-error'); this.handleExportError(e, 'asset-profile.export-failed-error');
} }
); });
} }
public importAssetProfile(): Observable<AssetProfile> { public importAssetProfile(): Observable<AssetProfile> {
@ -682,26 +670,24 @@ export class ImportExportService {
type: 'error'})); type: 'error'}));
throw new Error('Invalid asset profile file'); throw new Error('Invalid asset profile file');
} else { } else {
return this.assetProfileService.saveAssetProfile(assetProfile); return this.assetProfileService.saveAssetProfile(this.prepareImport(assetProfile));
} }
}), }),
catchError((err) => { catchError(() => of(null))
return of(null);
})
); );
} }
public exportTenantProfile(tenantProfileId: string) { public exportTenantProfile(tenantProfileId: string) {
this.tenantProfileService.getTenantProfile(tenantProfileId).subscribe( this.tenantProfileService.getTenantProfile(tenantProfileId).subscribe({
(tenantProfile) => { next: (tenantProfile) => {
let name = tenantProfile.name; let name = tenantProfile.name;
name = name.toLowerCase().replace(/\W/g, '_'); name = name.toLowerCase().replace(/\W/g, '_');
this.exportToPc(this.prepareProfileExport(tenantProfile), name); this.exportToPc(this.prepareProfileExport(tenantProfile), name);
}, },
(e) => { error: (e) => {
this.handleExportError(e, 'tenant-profile.export-failed-error'); this.handleExportError(e, 'tenant-profile.export-failed-error');
} }
); });
} }
public importTenantProfile(): Observable<TenantProfile> { public importTenantProfile(): Observable<TenantProfile> {
@ -713,12 +699,10 @@ export class ImportExportService {
type: 'error'})); type: 'error'}));
throw new Error('Invalid tenant profile file'); throw new Error('Invalid tenant profile file');
} else { } else {
return this.tenantProfileService.saveTenantProfile(tenantProfile); return this.tenantProfileService.saveTenantProfile(this.prepareImport(tenantProfile));
} }
}), }),
catchError(() => { catchError(() => of(null))
return of(null);
})
); );
} }
@ -838,7 +822,7 @@ export class ImportExportService {
&& isDefined(tenantProfile.isolatedTbRuleEngine); && isDefined(tenantProfile.isolatedTbRuleEngine);
} }
private sumObject(obj1: any, obj2: any): any { private sumObject<T>(obj1: T, obj2: T): T {
Object.keys(obj2).map((key) => { Object.keys(obj2).map((key) => {
if (isObject(obj2[key])) { if (isObject(obj2[key])) {
obj1[key] = obj1[key] || {}; obj1[key] = obj1[key] || {};
@ -940,13 +924,11 @@ export class ImportExportService {
onFiltersUpdateFunction: () => void, onFiltersUpdateFunction: () => void,
originalColumns: number, originalSize: WidgetSize): Observable<ImportWidgetResult> { originalColumns: number, originalSize: WidgetSize): Observable<ImportWidgetResult> {
return targetLayoutFunction().pipe( return targetLayoutFunction().pipe(
mergeMap((targetLayout) => { mergeMap((targetLayout) => this.itembuffer.addWidgetToDashboard(dashboard, targetState, targetLayout,
return this.itembuffer.addWidgetToDashboard(dashboard, targetState, targetLayout,
widget, aliasesInfo, filtersInfo, onAliasesUpdateFunction, onFiltersUpdateFunction, widget, aliasesInfo, filtersInfo, onAliasesUpdateFunction, onFiltersUpdateFunction,
originalColumns, originalSize, -1, -1).pipe( originalColumns, originalSize, -1, -1).pipe(
map(() => ({widget, layoutId: targetLayout} as ImportWidgetResult)) map(() => ({widget, layoutId: targetLayout} as ImportWidgetResult))
); )
}
)); ));
} }
@ -1131,7 +1113,18 @@ export class ImportExportService {
if (isDefined(exportedData.customerId)) { if (isDefined(exportedData.customerId)) {
delete exportedData.customerId; delete exportedData.customerId;
} }
if (isDefined(exportedData.externalId)) {
delete exportedData.externalId;
}
return exportedData; return exportedData;
} }
private prepareImport<T extends ExportableEntity<EntityId>>(data: T): T{
const importedData = deepClone(data);
if (isDefined(importedData.externalId)) {
delete importedData.externalId;
}
return importedData;
}
} }

View File

@ -39,8 +39,6 @@ export function sortEntitiesByIds<I extends HasId, T extends BaseData<I>>(entiti
} }
export interface ExportableEntity<T extends EntityId> { export interface ExportableEntity<T extends EntityId> {
createdTime?: number;
id?: T;
externalId?: T; externalId?: T;
} }

View File

@ -17,7 +17,7 @@
import { ContactBased } from '@shared/models/contact-based.model'; import { ContactBased } from '@shared/models/contact-based.model';
import { TenantId } from './id/tenant-id'; import { TenantId } from './id/tenant-id';
import { TenantProfileId } from '@shared/models/id/tenant-profile-id'; import { TenantProfileId } from '@shared/models/id/tenant-profile-id';
import { BaseData } from '@shared/models/base-data'; import { BaseData, ExportableEntity } from '@shared/models/base-data';
import { QueueInfo } from '@shared/models/queue.models'; import { QueueInfo } from '@shared/models/queue.models';
export enum TenantProfileType { export enum TenantProfileType {
@ -145,7 +145,7 @@ export interface TenantProfileData {
queueConfiguration?: Array<QueueInfo>; queueConfiguration?: Array<QueueInfo>;
} }
export interface TenantProfile extends BaseData<TenantProfileId> { export interface TenantProfile extends BaseData<TenantProfileId>, ExportableEntity<TenantProfileId> {
name: string; name: string;
description?: string; description?: string;
default?: boolean; default?: boolean;

View File

@ -701,7 +701,7 @@ export interface BaseWidgetInfo {
type: widgetType; type: widgetType;
} }
export interface Widget extends BaseWidgetInfo { export interface Widget extends BaseWidgetInfo, ExportableEntity<WidgetTypeId> {
typeId?: WidgetTypeId; typeId?: WidgetTypeId;
sizeX: number; sizeX: number;
sizeY: number; sizeY: number;