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) {