Commit 5976d5172969e0fb11f604686f75bb27a0a7a3eb
Committed by
Andrew Shvayka
1 parent
7edcc605
UI: Add import/export tenant profile
Showing
3 changed files
with
99 additions
and
6 deletions
... | ... | @@ -57,6 +57,8 @@ import { RuleChainService } from '@core/http/rule-chain.service'; |
57 | 57 | import { FiltersInfo } from '@shared/models/query/query.models'; |
58 | 58 | import { DeviceProfileService } from '@core/http/device-profile.service'; |
59 | 59 | import { DeviceProfile } from '@shared/models/device.models'; |
60 | +import { TenantProfile } from '@shared/models/tenant.model'; | |
61 | +import { TenantProfileService } from '@core/http/tenant-profile.service'; | |
60 | 62 | |
61 | 63 | // @dynamic |
62 | 64 | @Injectable() |
... | ... | @@ -70,6 +72,7 @@ export class ImportExportService { |
70 | 72 | private dashboardUtils: DashboardUtilsService, |
71 | 73 | private widgetService: WidgetService, |
72 | 74 | private deviceProfileService: DeviceProfileService, |
75 | + private tenantProfileService: TenantProfileService, | |
73 | 76 | private entityService: EntityService, |
74 | 77 | private ruleChainService: RuleChainService, |
75 | 78 | private utils: UtilsService, |
... | ... | @@ -434,7 +437,7 @@ export class ImportExportService { |
434 | 437 | (deviceProfile) => { |
435 | 438 | let name = deviceProfile.name; |
436 | 439 | name = name.toLowerCase().replace(/\W/g, '_'); |
437 | - this.exportToPc(this.prepareDeviceProfileExport(deviceProfile), name); | |
440 | + this.exportToPc(this.prepareProfileExport(deviceProfile), name); | |
438 | 441 | }, |
439 | 442 | (e) => { |
440 | 443 | this.handleExportError(e, 'device-profile.export-failed-error'); |
... | ... | @@ -460,6 +463,37 @@ export class ImportExportService { |
460 | 463 | ); |
461 | 464 | } |
462 | 465 | |
466 | + public exportTenantProfile(tenantProfileId: string) { | |
467 | + this.tenantProfileService.getTenantProfile(tenantProfileId).subscribe( | |
468 | + (tenantProfile) => { | |
469 | + let name = tenantProfile.name; | |
470 | + name = name.toLowerCase().replace(/\W/g, '_'); | |
471 | + this.exportToPc(this.prepareProfileExport(tenantProfile), name); | |
472 | + }, | |
473 | + (e) => { | |
474 | + this.handleExportError(e, 'tenant-profile.export-failed-error'); | |
475 | + } | |
476 | + ); | |
477 | + } | |
478 | + | |
479 | + public importTenantProfile(): Observable<TenantProfile> { | |
480 | + return this.openImportDialog('tenant-profile.import', 'tenant-profile.tenant-profile-file').pipe( | |
481 | + mergeMap((tenantProfile: TenantProfile) => { | |
482 | + if (!this.validateImportedTenantProfile(tenantProfile)) { | |
483 | + this.store.dispatch(new ActionNotificationShow( | |
484 | + {message: this.translate.instant('tenant-profile.invalid-tenant-profile-file-error'), | |
485 | + type: 'error'})); | |
486 | + throw new Error('Invalid tenant profile file'); | |
487 | + } else { | |
488 | + return this.tenantProfileService.saveTenantProfile(tenantProfile); | |
489 | + } | |
490 | + }), | |
491 | + catchError(() => { | |
492 | + return of(null); | |
493 | + }) | |
494 | + ); | |
495 | + } | |
496 | + | |
463 | 497 | public exportJSZip(data: object, filename: string) { |
464 | 498 | import('jszip').then((JSZip) => { |
465 | 499 | const jsZip = new JSZip.default(); |
... | ... | @@ -517,6 +551,13 @@ export class ImportExportService { |
517 | 551 | return true; |
518 | 552 | } |
519 | 553 | |
554 | + private validateImportedTenantProfile(tenantProfile: TenantProfile): boolean { | |
555 | + return isDefined(tenantProfile.name) | |
556 | + && isDefined(tenantProfile.profileData) | |
557 | + && isDefined(tenantProfile.isolatedTbCore) | |
558 | + && isDefined(tenantProfile.isolatedTbRuleEngine); | |
559 | + } | |
560 | + | |
520 | 561 | private sumObject(obj1: any, obj2: any): any { |
521 | 562 | Object.keys(obj2).map((key) => { |
522 | 563 | if (isObject(obj2[key])) { |
... | ... | @@ -798,10 +839,10 @@ export class ImportExportService { |
798 | 839 | return dashboard; |
799 | 840 | } |
800 | 841 | |
801 | - private prepareDeviceProfileExport(deviceProfile: DeviceProfile): DeviceProfile { | |
802 | - deviceProfile = this.prepareExport(deviceProfile); | |
803 | - deviceProfile.default = false; | |
804 | - return deviceProfile; | |
842 | + private prepareProfileExport<T extends DeviceProfile|TenantProfile>(profile: T): T { | |
843 | + profile = this.prepareExport(profile); | |
844 | + profile.default = false; | |
845 | + return profile; | |
805 | 846 | } |
806 | 847 | |
807 | 848 | private prepareExport(data: any): any { | ... | ... |
... | ... | @@ -21,7 +21,8 @@ import { |
21 | 21 | checkBoxCell, |
22 | 22 | DateEntityTableColumn, |
23 | 23 | EntityTableColumn, |
24 | - EntityTableConfig | |
24 | + EntityTableConfig, | |
25 | + HeaderActionDescriptor | |
25 | 26 | } from '@home/models/entity/entities-table-config.models'; |
26 | 27 | import { TranslateService } from '@ngx-translate/core'; |
27 | 28 | import { DatePipe } from '@angular/common'; |
... | ... | @@ -31,6 +32,7 @@ import { TenantProfileService } from '@core/http/tenant-profile.service'; |
31 | 32 | import { TenantProfileComponent } from '../../components/profile/tenant-profile.component'; |
32 | 33 | import { TenantProfileTabsComponent } from './tenant-profile-tabs.component'; |
33 | 34 | import { DialogService } from '@core/services/dialog.service'; |
35 | +import { ImportExportService } from '@home/components/import-export/import-export.service'; | |
34 | 36 | |
35 | 37 | @Injectable() |
36 | 38 | export class TenantProfilesTableConfigResolver implements Resolve<EntityTableConfig<TenantProfile>> { |
... | ... | @@ -38,6 +40,7 @@ export class TenantProfilesTableConfigResolver implements Resolve<EntityTableCon |
38 | 40 | private readonly config: EntityTableConfig<TenantProfile> = new EntityTableConfig<TenantProfile>(); |
39 | 41 | |
40 | 42 | constructor(private tenantProfileService: TenantProfileService, |
43 | + private importExport: ImportExportService, | |
41 | 44 | private translate: TranslateService, |
42 | 45 | private datePipe: DatePipe, |
43 | 46 | private dialogService: DialogService) { |
... | ... | @@ -60,6 +63,12 @@ export class TenantProfilesTableConfigResolver implements Resolve<EntityTableCon |
60 | 63 | |
61 | 64 | this.config.cellActionDescriptors.push( |
62 | 65 | { |
66 | + name: this.translate.instant('tenant-profile.export'), | |
67 | + icon: 'file_download', | |
68 | + isEnabled: () => true, | |
69 | + onAction: ($event, entity) => this.exportTenantProfile($event, entity) | |
70 | + }, | |
71 | + { | |
63 | 72 | name: this.translate.instant('tenant-profile.set-default'), |
64 | 73 | icon: 'flag', |
65 | 74 | isEnabled: (tenantProfile) => !tenantProfile.default, |
... | ... | @@ -80,6 +89,7 @@ export class TenantProfilesTableConfigResolver implements Resolve<EntityTableCon |
80 | 89 | this.config.onEntityAction = action => this.onTenantProfileAction(action); |
81 | 90 | this.config.deleteEnabled = (tenantProfile) => tenantProfile && !tenantProfile.default; |
82 | 91 | this.config.entitySelectionEnabled = (tenantProfile) => tenantProfile && !tenantProfile.default; |
92 | + this.config.addActionDescriptors = this.configureAddActions(); | |
83 | 93 | } |
84 | 94 | |
85 | 95 | resolve(): EntityTableConfig<TenantProfile> { |
... | ... | @@ -88,6 +98,25 @@ export class TenantProfilesTableConfigResolver implements Resolve<EntityTableCon |
88 | 98 | return this.config; |
89 | 99 | } |
90 | 100 | |
101 | + configureAddActions(): Array<HeaderActionDescriptor> { | |
102 | + const actions: Array<HeaderActionDescriptor> = []; | |
103 | + actions.push( | |
104 | + { | |
105 | + name: this.translate.instant('tenant-profile.create-tenant-profile'), | |
106 | + icon: 'insert_drive_file', | |
107 | + isEnabled: () => true, | |
108 | + onAction: ($event) => this.config.table.addEntity($event) | |
109 | + }, | |
110 | + { | |
111 | + name: this.translate.instant('tenant-profile.import'), | |
112 | + icon: 'file_upload', | |
113 | + isEnabled: () => true, | |
114 | + onAction: ($event) => this.importTenantProfile($event) | |
115 | + } | |
116 | + ); | |
117 | + return actions; | |
118 | + } | |
119 | + | |
91 | 120 | setDefaultTenantProfile($event: Event, tenantProfile: TenantProfile) { |
92 | 121 | if ($event) { |
93 | 122 | $event.stopPropagation(); |
... | ... | @@ -110,6 +139,23 @@ export class TenantProfilesTableConfigResolver implements Resolve<EntityTableCon |
110 | 139 | ); |
111 | 140 | } |
112 | 141 | |
142 | + importTenantProfile($event: Event) { | |
143 | + this.importExport.importTenantProfile().subscribe( | |
144 | + (deviceProfile) => { | |
145 | + if (deviceProfile) { | |
146 | + this.config.table.updateData(); | |
147 | + } | |
148 | + } | |
149 | + ); | |
150 | + } | |
151 | + | |
152 | + exportTenantProfile($event: Event, tenantProfile: TenantProfile) { | |
153 | + if ($event) { | |
154 | + $event.stopPropagation(); | |
155 | + } | |
156 | + this.importExport.exportTenantProfile(tenantProfile.id.id); | |
157 | + } | |
158 | + | |
113 | 159 | onTenantProfileAction(action: EntityAction<TenantProfile>): boolean { |
114 | 160 | switch (action.action) { |
115 | 161 | case 'setDefault': | ... | ... |
... | ... | @@ -2440,6 +2440,12 @@ |
2440 | 2440 | "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.", |
2441 | 2441 | "no-tenant-profiles-found": "No tenant profiles found.", |
2442 | 2442 | "create-new-tenant-profile": "Create a new one!", |
2443 | + "create-tenant-profile": "Create new tenant profile", | |
2444 | + "import": "Import tenant profile", | |
2445 | + "export": "Export tenant profile", | |
2446 | + "export-failed-error": "Unable to export tenant profile: {{error}}", | |
2447 | + "tenant-profile-file": "Tenant profile file", | |
2448 | + "invalid-tenant-profile-file-error": "Unable to import tenant profile: Invalid tenant profile data structure.", | |
2443 | 2449 | "maximum-devices": "Maximum number of devices (0 - unlimited)", |
2444 | 2450 | "maximum-devices-required": "Maximum number of devices is required.", |
2445 | 2451 | "maximum-devices-range": "Minimum number of devices can't be negative", | ... | ... |