From 5976d5172969e0fb11f604686f75bb27a0a7a3eb Mon Sep 17 00:00:00 2001 From: Vladyslav_Prykhodko Date: Wed, 28 Apr 2021 14:48:17 +0300 Subject: [PATCH] UI: Add import/export tenant profile --- .../import-export/import-export.service.ts | 51 +++++++++++++++++-- .../tenant-profiles-table-config.resolver.ts | 48 ++++++++++++++++- .../assets/locale/locale.constant-en_US.json | 6 +++ 3 files changed, 99 insertions(+), 6 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/import-export/import-export.service.ts b/ui-ngx/src/app/modules/home/components/import-export/import-export.service.ts index 72b5e661e3..3bd63b046b 100644 --- a/ui-ngx/src/app/modules/home/components/import-export/import-export.service.ts +++ b/ui-ngx/src/app/modules/home/components/import-export/import-export.service.ts @@ -57,6 +57,8 @@ import { RuleChainService } from '@core/http/rule-chain.service'; import { FiltersInfo } from '@shared/models/query/query.models'; import { DeviceProfileService } from '@core/http/device-profile.service'; import { DeviceProfile } from '@shared/models/device.models'; +import { TenantProfile } from '@shared/models/tenant.model'; +import { TenantProfileService } from '@core/http/tenant-profile.service'; // @dynamic @Injectable() @@ -70,6 +72,7 @@ export class ImportExportService { private dashboardUtils: DashboardUtilsService, private widgetService: WidgetService, private deviceProfileService: DeviceProfileService, + private tenantProfileService: TenantProfileService, private entityService: EntityService, private ruleChainService: RuleChainService, private utils: UtilsService, @@ -434,7 +437,7 @@ export class ImportExportService { (deviceProfile) => { let name = deviceProfile.name; name = name.toLowerCase().replace(/\W/g, '_'); - this.exportToPc(this.prepareDeviceProfileExport(deviceProfile), name); + this.exportToPc(this.prepareProfileExport(deviceProfile), name); }, (e) => { this.handleExportError(e, 'device-profile.export-failed-error'); @@ -460,6 +463,37 @@ export class ImportExportService { ); } + public exportTenantProfile(tenantProfileId: string) { + this.tenantProfileService.getTenantProfile(tenantProfileId).subscribe( + (tenantProfile) => { + let name = tenantProfile.name; + name = name.toLowerCase().replace(/\W/g, '_'); + this.exportToPc(this.prepareProfileExport(tenantProfile), name); + }, + (e) => { + this.handleExportError(e, 'tenant-profile.export-failed-error'); + } + ); + } + + public importTenantProfile(): Observable { + return this.openImportDialog('tenant-profile.import', 'tenant-profile.tenant-profile-file').pipe( + mergeMap((tenantProfile: TenantProfile) => { + if (!this.validateImportedTenantProfile(tenantProfile)) { + this.store.dispatch(new ActionNotificationShow( + {message: this.translate.instant('tenant-profile.invalid-tenant-profile-file-error'), + type: 'error'})); + throw new Error('Invalid tenant profile file'); + } else { + return this.tenantProfileService.saveTenantProfile(tenantProfile); + } + }), + catchError(() => { + return of(null); + }) + ); + } + public exportJSZip(data: object, filename: string) { import('jszip').then((JSZip) => { const jsZip = new JSZip.default(); @@ -517,6 +551,13 @@ export class ImportExportService { return true; } + private validateImportedTenantProfile(tenantProfile: TenantProfile): boolean { + return isDefined(tenantProfile.name) + && isDefined(tenantProfile.profileData) + && isDefined(tenantProfile.isolatedTbCore) + && isDefined(tenantProfile.isolatedTbRuleEngine); + } + private sumObject(obj1: any, obj2: any): any { Object.keys(obj2).map((key) => { if (isObject(obj2[key])) { @@ -798,10 +839,10 @@ export class ImportExportService { return dashboard; } - private prepareDeviceProfileExport(deviceProfile: DeviceProfile): DeviceProfile { - deviceProfile = this.prepareExport(deviceProfile); - deviceProfile.default = false; - return deviceProfile; + private prepareProfileExport(profile: T): T { + profile = this.prepareExport(profile); + profile.default = false; + return profile; } private prepareExport(data: any): any { diff --git a/ui-ngx/src/app/modules/home/pages/tenant-profile/tenant-profiles-table-config.resolver.ts b/ui-ngx/src/app/modules/home/pages/tenant-profile/tenant-profiles-table-config.resolver.ts index 996058e753..6c280c096b 100644 --- a/ui-ngx/src/app/modules/home/pages/tenant-profile/tenant-profiles-table-config.resolver.ts +++ b/ui-ngx/src/app/modules/home/pages/tenant-profile/tenant-profiles-table-config.resolver.ts @@ -21,7 +21,8 @@ import { checkBoxCell, DateEntityTableColumn, EntityTableColumn, - EntityTableConfig + EntityTableConfig, + HeaderActionDescriptor } from '@home/models/entity/entities-table-config.models'; import { TranslateService } from '@ngx-translate/core'; import { DatePipe } from '@angular/common'; @@ -31,6 +32,7 @@ import { TenantProfileService } from '@core/http/tenant-profile.service'; import { TenantProfileComponent } from '../../components/profile/tenant-profile.component'; import { TenantProfileTabsComponent } from './tenant-profile-tabs.component'; import { DialogService } from '@core/services/dialog.service'; +import { ImportExportService } from '@home/components/import-export/import-export.service'; @Injectable() export class TenantProfilesTableConfigResolver implements Resolve> { @@ -38,6 +40,7 @@ export class TenantProfilesTableConfigResolver implements Resolve = new EntityTableConfig(); constructor(private tenantProfileService: TenantProfileService, + private importExport: ImportExportService, private translate: TranslateService, private datePipe: DatePipe, private dialogService: DialogService) { @@ -59,6 +62,12 @@ export class TenantProfilesTableConfigResolver implements Resolve true, + onAction: ($event, entity) => this.exportTenantProfile($event, entity) + }, { name: this.translate.instant('tenant-profile.set-default'), icon: 'flag', @@ -80,6 +89,7 @@ export class TenantProfilesTableConfigResolver implements Resolve this.onTenantProfileAction(action); this.config.deleteEnabled = (tenantProfile) => tenantProfile && !tenantProfile.default; this.config.entitySelectionEnabled = (tenantProfile) => tenantProfile && !tenantProfile.default; + this.config.addActionDescriptors = this.configureAddActions(); } resolve(): EntityTableConfig { @@ -88,6 +98,25 @@ export class TenantProfilesTableConfigResolver implements Resolve { + const actions: Array = []; + actions.push( + { + name: this.translate.instant('tenant-profile.create-tenant-profile'), + icon: 'insert_drive_file', + isEnabled: () => true, + onAction: ($event) => this.config.table.addEntity($event) + }, + { + name: this.translate.instant('tenant-profile.import'), + icon: 'file_upload', + isEnabled: () => true, + onAction: ($event) => this.importTenantProfile($event) + } + ); + return actions; + } + setDefaultTenantProfile($event: Event, tenantProfile: TenantProfile) { if ($event) { $event.stopPropagation(); @@ -110,6 +139,23 @@ export class TenantProfilesTableConfigResolver implements Resolve { + if (deviceProfile) { + this.config.table.updateData(); + } + } + ); + } + + exportTenantProfile($event: Event, tenantProfile: TenantProfile) { + if ($event) { + $event.stopPropagation(); + } + this.importExport.exportTenantProfile(tenantProfile.id.id); + } + onTenantProfileAction(action: EntityAction): boolean { switch (action.action) { case 'setDefault': diff --git a/ui-ngx/src/assets/locale/locale.constant-en_US.json b/ui-ngx/src/assets/locale/locale.constant-en_US.json index d59ee56236..c7de3c2a1c 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -2440,6 +2440,12 @@ "set-default-tenant-profile-text": "After the confirmation the tenant profile will be marked as default and will be used for new tenants with no profile specified.", "no-tenant-profiles-found": "No tenant profiles found.", "create-new-tenant-profile": "Create a new one!", + "create-tenant-profile": "Create new tenant profile", + "import": "Import tenant profile", + "export": "Export tenant profile", + "export-failed-error": "Unable to export tenant profile: {{error}}", + "tenant-profile-file": "Tenant profile file", + "invalid-tenant-profile-file-error": "Unable to import tenant profile: Invalid tenant profile data structure.", "maximum-devices": "Maximum number of devices (0 - unlimited)", "maximum-devices-required": "Maximum number of devices is required.", "maximum-devices-range": "Minimum number of devices can't be negative",