diff --git a/application/src/main/data/json/system/widget_bundles/charts.json b/application/src/main/data/json/system/widget_bundles/charts.json index 71e9fa7ace..9dcf90d45b 100644 --- a/application/src/main/data/json/system/widget_bundles/charts.json +++ b/application/src/main/data/json/system/widget_bundles/charts.json @@ -55,7 +55,7 @@ ], "templateHtml": "\n", "templateCss": "", - "controllerScript": "self.onInit = function() {\n var pieData = {\n labels: [],\n datasets: []\n };\n\n var dataset = {\n data: [],\n backgroundColor: [],\n borderColor: [],\n borderWidth: [],\n hoverBackgroundColor: []\n }\n \n var borderColor = self.ctx.settings.borderColor || '#fff';\n var borderWidth = angular.isDefined(self.ctx.settings.borderWidth) ? self.ctx.settings.borderWidth : 5;\n \n pieData.datasets.push(dataset);\n \n for (var i=0; i < self.ctx.data.length; i++) {\n var dataKey = self.ctx.data[i].dataKey;\n pieData.labels.push(dataKey.label);\n dataset.data.push(0);\n var hoverBackgroundColor = tinycolor(dataKey.color).lighten(15);\n dataset.backgroundColor.push(dataKey.color);\n dataset.borderColor.push(borderColor);\n dataset.borderWidth.push(borderWidth);\n dataset.hoverBackgroundColor.push(hoverBackgroundColor.toRgbString());\n }\n\n var options = {\n responsive: false,\n maintainAspectRatio: false,\n legend: {\n display: true,\n labels: {\n fontColor: '#666'\n }\n },\n tooltips: {\n callbacks: {\n label: function(tooltipItem, data) {\n var label = data.labels[tooltipItem.index];\n var value = data.datasets[tooltipItem.datasetIndex].data[tooltipItem.index];\n var content = label + ': ' + value;\n var units = self.ctx.settings.units ? self.ctx.settings.units : self.ctx.units;\n if (units) {\n content += ' ' + units;\n } \n return content;\n }\n }\n }\n };\n\n if (self.ctx.settings.legend) {\n options.legend.display = self.ctx.settings.legend.display !== false;\n options.legend.labels.fontColor = self.ctx.settings.legend.labelsFontColor || '#666';\n }\n\n var ctx = $('#pieChart', self.ctx.$container);\n self.ctx.chart = new Chart(ctx, {\n type: 'doughnut',\n data: pieData,\n options: options\n });\n \n self.onResize();\n}\n\nself.onDataUpdated = function() {\n for (var i = 0; i < self.ctx.data.length; i++) {\n var cellData = self.ctx.data[i];\n if (cellData.data.length > 0) {\n var tvPair = cellData.data[cellData.data.length - 1];\n var value = tvPair[1];\n self.ctx.chart.data.datasets[0].data[i] = parseFloat(value);\n }\n }\n self.ctx.chart.update();\n}\n\nself.onResize = function() {\n self.ctx.chart.resize();\n}\n\n", + "controllerScript": "self.onInit = function() {\n var pieData = {\n labels: [],\n datasets: []\n };\n\n var dataset = {\n data: [],\n backgroundColor: [],\n borderColor: [],\n borderWidth: [],\n hoverBackgroundColor: []\n }\n \n var borderColor = self.ctx.settings.borderColor || '#fff';\n var borderWidth = typeof self.ctx.settings.borderWidth !== 'undefined' ? self.ctx.settings.borderWidth : 5;\n \n pieData.datasets.push(dataset);\n \n for (var i=0; i < self.ctx.data.length; i++) {\n var dataKey = self.ctx.data[i].dataKey;\n pieData.labels.push(dataKey.label);\n dataset.data.push(0);\n var hoverBackgroundColor = tinycolor(dataKey.color).lighten(15);\n dataset.backgroundColor.push(dataKey.color);\n dataset.borderColor.push(borderColor);\n dataset.borderWidth.push(borderWidth);\n dataset.hoverBackgroundColor.push(hoverBackgroundColor.toRgbString());\n }\n\n var options = {\n responsive: false,\n maintainAspectRatio: false,\n legend: {\n display: true,\n labels: {\n fontColor: '#666'\n }\n },\n tooltips: {\n callbacks: {\n label: function(tooltipItem, data) {\n var label = data.labels[tooltipItem.index];\n var value = data.datasets[tooltipItem.datasetIndex].data[tooltipItem.index];\n var content = label + ': ' + value;\n var units = self.ctx.settings.units ? self.ctx.settings.units : self.ctx.units;\n if (units) {\n content += ' ' + units;\n } \n return content;\n }\n }\n }\n };\n\n if (self.ctx.settings.legend) {\n options.legend.display = self.ctx.settings.legend.display !== false;\n options.legend.labels.fontColor = self.ctx.settings.legend.labelsFontColor || '#666';\n }\n\n var ctx = $('#pieChart', self.ctx.$container);\n self.ctx.chart = new Chart(ctx, {\n type: 'doughnut',\n data: pieData,\n options: options\n });\n \n self.onResize();\n}\n\nself.onDataUpdated = function() {\n for (var i = 0; i < self.ctx.data.length; i++) {\n var cellData = self.ctx.data[i];\n if (cellData.data.length > 0) {\n var tvPair = cellData.data[cellData.data.length - 1];\n var value = tvPair[1];\n self.ctx.chart.data.datasets[0].data[i] = parseFloat(value);\n }\n }\n self.ctx.chart.update();\n}\n\nself.onResize = function() {\n self.ctx.chart.resize();\n}\n\n", "settingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"Settings\",\n \"properties\": {\n \"borderWidth\": {\n \"title\": \"Border width\",\n \"type\": \"number\",\n \"default\": 5\n },\n \"borderColor\": {\n \"title\": \"Border color\",\n \"type\": \"string\",\n \"default\": \"#fff\"\n },\n \"legend\": {\n \"title\": \"Legend settings\",\n \"type\": \"object\",\n \"properties\": {\n \"display\": {\n \"title\": \"Display legend\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"labelsFontColor\": {\n \"title\": \"Labels font color\",\n \"type\": \"string\",\n \"default\": \"#666\"\n }\n }\n }\n },\n \"required\": []\n },\n \"form\": [\n \"borderWidth\", \n {\n \"key\": \"borderColor\",\n \"type\": \"color\"\n }, \n {\n \"key\": \"legend\",\n \"items\": [\n \"legend.display\",\n {\n \"key\": \"legend.labelsFontColor\",\n \"type\": \"color\"\n }\n ]\n }\n ]\n}", "dataKeySettingsSchema": "{}\n", "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"First\",\"color\":\"#26a69a\",\"settings\":{},\"_hash\":0.15479322438769105,\"funcBody\":\"var value = (prevValue-50) + Math.random() * 2 - 1;\\nif (value < 0) {\\n\\tvalue = 0;\\n} else if (value > 100) {\\n\\tvalue = 100;\\n}\\nreturn value+50;\"},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Second\",\"color\":\"#f57c00\",\"settings\":{},\"_hash\":0.545701115289893,\"funcBody\":\"var value = (prevValue-20) + Math.random() * 2 - 1;\\nif (value < 0) {\\n\\tvalue = 0;\\n} else if (value > 100) {\\n\\tvalue = 100;\\n}\\nreturn value+20;\"},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Third\",\"color\":\"#afb42b\",\"settings\":{},\"_hash\":0.2592906835158064,\"funcBody\":\"var value = (prevValue-40) + Math.random() * 2 - 1;\\nif (value < 0) {\\n\\tvalue = 0;\\n} else if (value > 100) {\\n\\tvalue = 100;\\n}\\nreturn value+40;\"},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Fourth\",\"color\":\"#673ab7\",\"settings\":{},\"_hash\":0.12880275585455747,\"funcBody\":\"var value = (prevValue-50) + Math.random() * 2 - 1;\\nif (value < 0) {\\n\\tvalue = 0;\\n} else if (value > 100) {\\n\\tvalue = 100;\\n}\\nreturn value+50;\"}]}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":true,\"backgroundColor\":\"#fff\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"8px\",\"settings\":{\"borderWidth\":5,\"borderColor\":\"#fff\",\"legend\":{\"display\":true,\"labelsFontColor\":\"#666666\"}},\"title\":\"Doughnut - Chart.js\",\"dropShadow\":true,\"enableFullscreen\":true,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400}}" diff --git a/ui-ngx/src/app/core/http/widget.service.ts b/ui-ngx/src/app/core/http/widget.service.ts index 306f3e6daa..a036511883 100644 --- a/ui-ngx/src/app/core/http/widget.service.ts +++ b/ui-ngx/src/app/core/http/widget.service.ts @@ -21,7 +21,7 @@ import { HttpClient } from '@angular/common/http'; import { PageLink } from '@shared/models/page/page-link'; import { PageData } from '@shared/models/page/page-data'; import { WidgetsBundle } from '@shared/models/widgets-bundle.model'; -import { WidgetType, widgetType, WidgetTypeData, widgetTypesData } from '@shared/models/widget.models'; +import { Widget, WidgetType, widgetType, WidgetTypeData, widgetTypesData } from '@shared/models/widget.models'; import { UtilsService } from '@core/services/utils.service'; import { TranslateService } from '@ngx-translate/core'; import { ResourcesService } from '../services/resources.service'; @@ -119,6 +119,59 @@ export class WidgetService { defaultHttpOptions(ignoreLoading, ignoreErrors)); } + public loadBundleLibraryWidgets(bundleAlias: string, isSystem: boolean, + ignoreErrors: boolean = false, ignoreLoading: boolean = false): Observable> { + return this.getBundleWidgetTypes(bundleAlias, isSystem, ignoreErrors, ignoreLoading).pipe( + map((types) => { + types = types.sort((a, b) => { + let result = widgetType[b.descriptor.type].localeCompare(widgetType[a.descriptor.type]); + if (result === 0) { + result = b.createdTime - a.createdTime; + } + return result; + }); + const widgetTypes = new Array(); + let top = 0; + const lastTop = [0, 0, 0]; + let col = 0; + let column = 0; + types.forEach((type) => { + const widgetTypeInfo = toWidgetInfo(type); + const sizeX = 8; + const sizeY = Math.floor(widgetTypeInfo.sizeY); + const widget: Widget = { + typeId: type.id, + isSystemType: isSystem, + bundleAlias, + typeAlias: widgetTypeInfo.alias, + type: widgetTypeInfo.type, + title: widgetTypeInfo.widgetName, + sizeX, + sizeY, + row: top, + col, + config: JSON.parse(widgetTypeInfo.defaultConfig) + }; + + widget.config.title = widgetTypeInfo.widgetName; + + widgetTypes.push(widget); + top += sizeY; + if (top > lastTop[column] + 10) { + lastTop[column] = top; + column++; + if (column > 2) { + column = 0; + } + top = lastTop[column]; + col = column * 8; + } + }); + return widgetTypes; + }) + ); + } + public getWidgetType(bundleAlias: string, widgetTypeAlias: string, isSystem: boolean, ignoreErrors: boolean = false, ignoreLoading: boolean = false): Observable { return this.http.get(`/api/widgetType?isSystem=${isSystem}&bundleAlias=${bundleAlias}&alias=${widgetTypeAlias}`, diff --git a/ui-ngx/src/app/modules/home/components/import-export/import-export.models.ts b/ui-ngx/src/app/modules/home/components/import-export/import-export.models.ts index 24e152cb29..c9502eb380 100644 --- a/ui-ngx/src/app/modules/home/components/import-export/import-export.models.ts +++ b/ui-ngx/src/app/modules/home/components/import-export/import-export.models.ts @@ -14,10 +14,16 @@ /// limitations under the License. /// -import { Widget } from '@app/shared/models/widget.models'; +import { Widget, WidgetType } from '@app/shared/models/widget.models'; import { DashboardLayoutId } from '@shared/models/dashboard.models'; +import { WidgetsBundle } from '@shared/models/widgets-bundle.model'; export interface ImportWidgetResult { widget: Widget; layoutId: DashboardLayoutId; } + +export interface WidgetsBundleItem { + widgetsBundle: WidgetsBundle; + widgetTypes: WidgetType[]; +} 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 59905423f2..b8001cbc34 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 @@ -38,15 +38,18 @@ import { forkJoin, Observable, of } from 'rxjs'; import { catchError, map, mergeMap } from 'rxjs/operators'; import { DashboardUtilsService } from '@core/services/dashboard-utils.service'; import { EntityService } from '@core/http/entity.service'; -import { Widget, WidgetSize } from '@shared/models/widget.models'; +import { Widget, WidgetSize, WidgetType } from '@shared/models/widget.models'; import { EntityAliasesDialogComponent, EntityAliasesDialogData } from '@home/components/alias/entity-aliases-dialog.component'; import { ItemBufferService, WidgetItem } from '@core/services/item-buffer.service'; -import { ImportWidgetResult } from './import-export.models'; +import { ImportWidgetResult, WidgetsBundleItem } from './import-export.models'; import { EntityType } from '@shared/models/entity-type.models'; import { UtilsService } from '@core/services/utils.service'; +import { WidgetService } from '@core/http/widget.service'; +import { NULL_UUID } from '@shared/models/id/has-uuid'; +import { WidgetsBundle } from '@shared/models/widgets-bundle.model'; @Injectable() export class ImportExportService { @@ -57,6 +60,7 @@ export class ImportExportService { private translate: TranslateService, private dashboardService: DashboardService, private dashboardUtils: DashboardUtilsService, + private widgetService: WidgetService, private entityService: EntityService, private utils: UtilsService, private itembuffer: ItemBufferService, @@ -72,13 +76,7 @@ export class ImportExportService { this.exportToPc(this.prepareDashboardExport(dashboard), name + '.json'); }, (e) => { - let message = e; - if (!message) { - message = this.translate.instant('error.unknown-error'); - } - this.store.dispatch(new ActionNotificationShow( - {message: this.translate.instant('dashboard.export-failed-error', {error: message}), - type: 'error'})); + this.handleExportError(e, 'dashboard.export-failed-error'); } ); } @@ -223,6 +221,119 @@ export class ImportExportService { ); } + public exportWidgetType(widgetTypeId: string) { + this.widgetService.getWidgetTypeById(widgetTypeId).subscribe( + (widgetType) => { + if (isDefined(widgetType.bundleAlias)) { + delete widgetType.bundleAlias; + } + let name = widgetType.name; + name = name.toLowerCase().replace(/\W/g, '_'); + this.exportToPc(this.prepareExport(widgetType), name + '.json'); + }, + (e) => { + this.handleExportError(e, 'widget-type.export-failed-error'); + } + ); + } + + public importWidgetType(bundleAlias: string): Observable { + return this.openImportDialog('widget-type.import', 'widget-type.widget-type-file').pipe( + mergeMap((widgetType: WidgetType) => { + if (!this.validateImportedWidgetType(widgetType)) { + this.store.dispatch(new ActionNotificationShow( + {message: this.translate.instant('widget-type.invalid-widget-type-file-error'), + type: 'error'})); + throw new Error('Invalid widget type file'); + } else { + widgetType.bundleAlias = bundleAlias; + return this.widgetService.saveImportedWidgetType(widgetType); + } + }), + catchError((err) => { + return of(null); + }) + ); + } + + public exportWidgetsBundle(widgetsBundleId: string) { + this.widgetService.getWidgetsBundle(widgetsBundleId).subscribe( + (widgetsBundle) => { + const bundleAlias = widgetsBundle.alias; + const isSystem = widgetsBundle.tenantId.id === NULL_UUID; + this.widgetService.getBundleWidgetTypes(bundleAlias, isSystem).subscribe( + (widgetTypes) => { + const widgetsBundleItem: WidgetsBundleItem = { + widgetsBundle: this.prepareExport(widgetsBundle), + widgetTypes: [] + }; + for (const widgetType of widgetTypes) { + if (isDefined(widgetType.bundleAlias)) { + delete widgetType.bundleAlias; + } + widgetsBundleItem.widgetTypes.push(this.prepareExport(widgetType)); + } + let name = widgetsBundle.title; + name = name.toLowerCase().replace(/\W/g, '_'); + this.exportToPc(widgetsBundleItem, name + '.json'); + }, + (e) => { + this.handleExportError(e, 'widgets-bundle.export-failed-error'); + } + ); + }, + (e) => { + this.handleExportError(e, 'widgets-bundle.export-failed-error'); + } + ); + } + + public importWidgetsBundle(): Observable { + return this.openImportDialog('widgets-bundle.import', 'widgets-bundle.widgets-bundle-file').pipe( + mergeMap((widgetsBundleItem: WidgetsBundleItem) => { + if (!this.validateImportedWidgetsBundle(widgetsBundleItem)) { + this.store.dispatch(new ActionNotificationShow( + {message: this.translate.instant('widgets-bundle.invalid-widgets-bundle-file-error'), + type: 'error'})); + throw new Error('Invalid widgets bundle file'); + } else { + const widgetsBundle = widgetsBundleItem.widgetsBundle; + return this.widgetService.saveWidgetsBundle(widgetsBundle).pipe( + mergeMap((savedWidgetsBundle) => { + const bundleAlias = savedWidgetsBundle.alias; + const widgetTypes = widgetsBundleItem.widgetTypes; + if (widgetTypes.length) { + const saveWidgetTypesObservables: Array> = []; + for (const widgetType of widgetTypes) { + widgetType.bundleAlias = bundleAlias; + saveWidgetTypesObservables.push(this.widgetService.saveImportedWidgetType(widgetType)); + } + return forkJoin(saveWidgetTypesObservables).pipe( + map(() => savedWidgetsBundle) + ); + } else { + return of(savedWidgetsBundle); + } + } + )); + } + }), + catchError((err) => { + return of(null); + }) + ); + } + + private handleExportError(e: any, errorDetailsMessageId: string) { + let message = e; + if (!message) { + message = this.translate.instant('error.unknown-error'); + } + this.store.dispatch(new ActionNotificationShow( + {message: this.translate.instant(errorDetailsMessageId, {error: message}), + type: 'error'})); + } + private validateImportedDashboard(dashboard: Dashboard): boolean { if (isUndefined(dashboard.title) || isUndefined(dashboard.configuration)) { return false; @@ -246,6 +357,34 @@ export class ImportExportService { return true; } + private validateImportedWidgetType(widgetType: WidgetType): boolean { + if (isUndefined(widgetType.name) + || isUndefined(widgetType.descriptor)) { + return false; + } + return true; + } + + private validateImportedWidgetsBundle(widgetsBundleItem: WidgetsBundleItem): boolean { + if (isUndefined(widgetsBundleItem.widgetsBundle)) { + return false; + } + if (isUndefined(widgetsBundleItem.widgetTypes)) { + return false; + } + const widgetsBundle = widgetsBundleItem.widgetsBundle; + if (isUndefined(widgetsBundle.title)) { + return false; + } + const widgetTypes = widgetsBundleItem.widgetTypes; + for (const widgetType of widgetTypes) { + if (!this.validateImportedWidgetType(widgetType)) { + return false; + } + } + return true; + } + private saveImportedDashboard(dashboard: Dashboard): Observable { return this.dashboardService.saveDashboard(dashboard); } diff --git a/ui-ngx/src/app/modules/home/models/dashboard-component.models.ts b/ui-ngx/src/app/modules/home/models/dashboard-component.models.ts index a03cbd4ea3..a3c237b115 100644 --- a/ui-ngx/src/app/modules/home/models/dashboard-component.models.ts +++ b/ui-ngx/src/app/modules/home/models/dashboard-component.models.ts @@ -114,7 +114,7 @@ export class DashboardWidgets implements Iterable { updateRecords.push({ widget: added.item, widgetId: added.item.id, - widgetLayout: this.widgetLayouts[added.item.id], + widgetLayout: this.widgetLayouts ? this.widgetLayouts[added.item.id] : null, operation: 'add' }); }); diff --git a/ui-ngx/src/app/modules/home/pages/widget/widget-library-routing.module.ts b/ui-ngx/src/app/modules/home/pages/widget/widget-library-routing.module.ts index 96c9de20a4..6e0de4ae21 100644 --- a/ui-ngx/src/app/modules/home/pages/widget/widget-library-routing.module.ts +++ b/ui-ngx/src/app/modules/home/pages/widget/widget-library-routing.module.ts @@ -63,54 +63,10 @@ export class WidgetsTypesDataResolver implements Resolve { const widgetsBundle: WidgetsBundle = route.parent.data.widgetsBundle; const bundleAlias = widgetsBundle.alias; const isSystem = widgetsBundle.tenantId.id === NULL_UUID; - return this.widgetsService.getBundleWidgetTypes(bundleAlias, + return this.widgetsService.loadBundleLibraryWidgets(bundleAlias, isSystem).pipe( - map((types) => { - types = types.sort((a, b) => { - let result = widgetType[b.descriptor.type].localeCompare(widgetType[a.descriptor.type]); - if (result === 0) { - result = b.createdTime - a.createdTime; - } - return result; - }); - const widgetTypes = new Array(); - let top = 0; - const lastTop = [0, 0, 0]; - let col = 0; - let column = 0; - types.forEach((type) => { - const widgetTypeInfo = toWidgetInfo(type); - const sizeX = 8; - const sizeY = Math.floor(widgetTypeInfo.sizeY); - const widget: Widget = { - typeId: type.id, - isSystemType: isSystem, - bundleAlias, - typeAlias: widgetTypeInfo.alias, - type: widgetTypeInfo.type, - title: widgetTypeInfo.widgetName, - sizeX, - sizeY, - row: top, - col, - config: JSON.parse(widgetTypeInfo.defaultConfig) - }; - - widget.config.title = widgetTypeInfo.widgetName; - - widgetTypes.push(widget); - top += sizeY; - if (top > lastTop[column] + 10) { - lastTop[column] = top; - column++; - if (column > 2) { - column = 0; - } - top = lastTop[column]; - col = column * 8; - } - }); - return { widgets: widgetTypes }; + map((widgets) => { + return { widgets }; } )); } diff --git a/ui-ngx/src/app/modules/home/pages/widget/widget-library.component.ts b/ui-ngx/src/app/modules/home/pages/widget/widget-library.component.ts index 81ac1fb653..2d50ee8684 100644 --- a/ui-ngx/src/app/modules/home/pages/widget/widget-library.component.ts +++ b/ui-ngx/src/app/modules/home/pages/widget/widget-library.component.ts @@ -14,7 +14,7 @@ /// limitations under the License. /// -import { Component, OnInit, ViewChild } from '@angular/core'; +import { Component, OnDestroy, OnInit, ViewChild } from '@angular/core'; import { Store } from '@ngrx/store'; import { AppState } from '@core/core.state'; import { PageComponent } from '@shared/components/page.component'; @@ -24,7 +24,7 @@ import { WidgetsBundle } from '@shared/models/widgets-bundle.model'; import { ActivatedRoute, Router } from '@angular/router'; import { Authority } from '@shared/models/authority.enum'; import { NULL_UUID } from '@shared/models/id/has-uuid'; -import { Observable, of } from 'rxjs'; +import { Observable, of, Subscription } from 'rxjs'; import { Widget, widgetType } from '@app/shared/models/widget.models'; import { WidgetService } from '@core/http/widget.service'; import { map, mergeMap, share } from 'rxjs/operators'; @@ -42,6 +42,7 @@ import { DeviceCredentials } from '@shared/models/device.models'; import { MatDialog } from '@angular/material/dialog'; import { SelectWidgetTypeDialogComponent } from '@home/pages/widget/select-widget-type-dialog.component'; import { TranslateService } from '@ngx-translate/core'; +import { ImportExportService } from '@home/components/import-export/import-export.service'; @Component({ selector: 'tb-widget-library', @@ -94,11 +95,12 @@ export class WidgetLibraryComponent extends PageComponent implements OnInit { private router: Router, private widgetService: WidgetService, private dialogService: DialogService, + private importExport: ImportExportService, private dialog: MatDialog, private translate: TranslateService) { super(store); - this.authUser = getCurrentAuthUser(store); + this.authUser = getCurrentAuthUser(this.store); this.widgetsBundle = this.route.snapshot.data.widgetsBundle; this.widgetsData = this.route.snapshot.data.widgetsData; if (this.authUser.authority === Authority.TENANT_ADMIN) { @@ -119,7 +121,23 @@ export class WidgetLibraryComponent extends PageComponent implements OnInit { if ($event) { $event.stopPropagation(); } - this.dialogService.todo(); + this.importExport.importWidgetType(this.widgetsBundle.alias).subscribe( + (widgetTypeInstance) => { + if (widgetTypeInstance) { + this.reload(); + } + } + ); + } + + private reload() { + const bundleAlias = this.widgetsBundle.alias; + const isSystem = this.widgetsBundle.tenantId.id === NULL_UUID; + this.widgetService.loadBundleLibraryWidgets(bundleAlias, isSystem).subscribe( + (widgets) => { + this.widgetsData = {widgets}; + } + ); } openWidgetType($event: Event, widget?: Widget): void { @@ -147,14 +165,14 @@ export class WidgetLibraryComponent extends PageComponent implements OnInit { if ($event) { $event.stopPropagation(); } - this.dialogService.todo(); + this.importExport.exportWidgetType(widget.typeId.id); } - removeWidgetType($event: Event, widget: Widget): Observable { + removeWidgetType($event: Event, widget: Widget): void { if ($event) { $event.stopPropagation(); } - return this.dialogService.confirm( + this.dialogService.confirm( this.translate.instant('widget.remove-widget-type-title', {widgetName: widget.config.title}), this.translate.instant('widget.remove-widget-type-text'), this.translate.instant('action.no'), @@ -169,13 +187,13 @@ export class WidgetLibraryComponent extends PageComponent implements OnInit { }), map((result) => { if (result !== false) { - this.widgetsData.widgets.splice(this.widgetsData.widgets.indexOf(widget), 1); + this.reload(); return true; } else { return false; } } - )); + )).subscribe(); } } diff --git a/ui-ngx/src/app/modules/home/pages/widget/widgets-bundles-table-config.resolver.ts b/ui-ngx/src/app/modules/home/pages/widget/widgets-bundles-table-config.resolver.ts index 47f7128af9..12c9b044fe 100644 --- a/ui-ngx/src/app/modules/home/pages/widget/widgets-bundles-table-config.resolver.ts +++ b/ui-ngx/src/app/modules/home/pages/widget/widgets-bundles-table-config.resolver.ts @@ -36,6 +36,7 @@ import {AppState} from '@core/core.state'; import {getCurrentAuthUser} from '@app/core/auth/auth.selectors'; import {Authority} from '@shared/models/authority.enum'; import {DialogService} from '@core/services/dialog.service'; +import { ImportExportService } from '@home/components/import-export/import-export.service'; @Injectable() export class WidgetsBundlesTableConfigResolver implements Resolve> { @@ -46,6 +47,7 @@ export class WidgetsBundlesTableConfigResolver implements Resolve { + if (widgetsBundle) { + this.config.table.updateData(); + } + } + ); } openWidgetsBundle($event: Event, widgetsBundle: WidgetsBundle) { @@ -142,8 +146,7 @@ export class WidgetsBundlesTableConfigResolver implements Resolve): boolean { diff --git a/ui-ngx/src/scss/mixins.scss b/ui-ngx/src/scss/mixins.scss index 1cde9ee21a..3b31b0e10c 100644 --- a/ui-ngx/src/scss/mixins.scss +++ b/ui-ngx/src/scss/mixins.scss @@ -21,12 +21,12 @@ min-height: #{$size}px; font-size: #{$size}px; line-height: #{$size}px; - svg { +/* svg { width: 24px; height: 24px; transform: scale($size/24); transform-origin: top; - } + }*/ } @mixin tb-mat-icon-button-size($size) {