diff --git a/application/src/main/data/json/system/widget_types/gateway_configuration.json b/application/src/main/data/json/system/widget_types/gateway_configuration.json
index 985426ef94..a19ffc23c3 100644
--- a/application/src/main/data/json/system/widget_types/gateway_configuration.json
+++ b/application/src/main/data/json/system/widget_types/gateway_configuration.json
@@ -8,7 +8,15 @@
"type": "static",
"sizeX": 8,
"sizeY": 6.5,
- "resources": [],
+ "resources": [
+ {
+ "url": {
+ "entityType": "TB_RESOURCE",
+ "id": "71347080-80b6-11ef-a567-0114914c70f8"
+ },
+ "isModule": true
+ }
+ ],
"templateHtml": "\n\n",
"templateCss": "",
"controllerScript": "self.onInit = function() {\n}\n",
diff --git a/application/src/main/data/json/system/widget_types/gateway_configuration__single_device_.json b/application/src/main/data/json/system/widget_types/gateway_configuration__single_device_.json
index a7b3291666..26c804a1a8 100644
--- a/application/src/main/data/json/system/widget_types/gateway_configuration__single_device_.json
+++ b/application/src/main/data/json/system/widget_types/gateway_configuration__single_device_.json
@@ -8,7 +8,15 @@
"type": "latest",
"sizeX": 7.5,
"sizeY": 9,
- "resources": [],
+ "resources": [
+ {
+ "url": {
+ "entityType": "TB_RESOURCE",
+ "id": "71347080-80b6-11ef-a567-0114914c70f8"
+ },
+ "isModule": true
+ }
+ ],
"templateHtml": "\n",
"templateCss": "#container {\n overflow: auto;\n}\n\n.tbDatasource-container {\n margin: 5px;\n padding: 8px;\n}\n\n.tbDatasource-title {\n font-size: 1.200rem;\n font-weight: 500;\n padding-bottom: 10px;\n}\n\n.tbDatasource-table {\n width: 100%;\n box-shadow: 0 0 10px #ccc;\n border-collapse: collapse;\n white-space: nowrap;\n font-size: 1.000rem;\n color: #757575;\n}\n\n.tbDatasource-table td {\n position: relative;\n border-top: 1px solid rgba(0, 0, 0, 0.12);\n border-bottom: 1px solid rgba(0, 0, 0, 0.12);\n padding: 0px 18px;\n box-sizing: border-box;\n}",
"controllerScript": "self.onInit = function() {\n}\n\n\nself.onDestroy = function() {\n}\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\t\t\t\n dataKeysOptional: true,\n singleEntity: true\n };\n}\n\n",
diff --git a/application/src/main/data/json/system/widget_types/gateway_connectors.json b/application/src/main/data/json/system/widget_types/gateway_connectors.json
index 43f95194b8..6323c32b3c 100644
--- a/application/src/main/data/json/system/widget_types/gateway_connectors.json
+++ b/application/src/main/data/json/system/widget_types/gateway_connectors.json
@@ -8,7 +8,15 @@
"type": "latest",
"sizeX": 11,
"sizeY": 8,
- "resources": [],
+ "resources": [
+ {
+ "url": {
+ "entityType": "TB_RESOURCE",
+ "id": "71347080-80b6-11ef-a567-0114914c70f8"
+ },
+ "isModule": true
+ }
+ ],
"templateHtml": "",
"templateCss": "",
"controllerScript": "self.onInit = function() {\n if (self.ctx.datasources && self.ctx.datasources.length) {\n self.ctx.$scope.entityId = self.ctx.datasources[0].entity.id;\n }\n};\n\nself.onDataUpdated = function() {\n self.ctx.$scope.gatewayConnectors?.onDataUpdated();\n};\n\nself.typeParameters = function() {\n return {\n dataKeysOptional: true,\n singleEntity: true\n };\n}",
diff --git a/application/src/main/data/json/system/widget_types/gateway_custom_statistics.json b/application/src/main/data/json/system/widget_types/gateway_custom_statistics.json
index 7090490ea6..1eaa061d11 100644
--- a/application/src/main/data/json/system/widget_types/gateway_custom_statistics.json
+++ b/application/src/main/data/json/system/widget_types/gateway_custom_statistics.json
@@ -8,7 +8,15 @@
"type": "timeseries",
"sizeX": 8,
"sizeY": 5,
- "resources": [],
+ "resources": [
+ {
+ "url": {
+ "entityType": "TB_RESOURCE",
+ "id": "71347080-80b6-11ef-a567-0114914c70f8"
+ },
+ "isModule": true
+ }
+ ],
"templateHtml": "",
"templateCss": ".legend {\n font-size: 13px;\n line-height: 10px;\n}\n\n.legend table { \n border-spacing: 0px;\n border-collapse: separate;\n}\n\n.mouse-events .flot-overlay {\n cursor: crosshair; \n}\n\n",
"controllerScript": "self.onInit = function() { \n};\n\nself.onDataUpdated = function() {\n};\n\nself.onLatestDataUpdated = function() {\n};\n\nself.onResize = function() {\n};\n\nself.onEditModeChanged = function() {\n};\n\nself.onDestroy = function() {\n};\n\nself.typeParameters = function() {\n return {\n hasAdditionalLatestDataKeys: false,\n dataKeysOptional: true\n };\n}\n",
diff --git a/application/src/main/data/json/system/widget_types/gateway_general_chart_statistics.json b/application/src/main/data/json/system/widget_types/gateway_general_chart_statistics.json
index 7e1974d5b7..37a16fa7ba 100644
--- a/application/src/main/data/json/system/widget_types/gateway_general_chart_statistics.json
+++ b/application/src/main/data/json/system/widget_types/gateway_general_chart_statistics.json
@@ -8,7 +8,15 @@
"type": "timeseries",
"sizeX": 8,
"sizeY": 5,
- "resources": [],
+ "resources": [
+ {
+ "url": {
+ "entityType": "TB_RESOURCE",
+ "id": "71347080-80b6-11ef-a567-0114914c70f8"
+ },
+ "isModule": true
+ }
+ ],
"templateHtml": "",
"templateCss": ".legend {\n font-size: 13px;\n line-height: 10px;\n}\n\n.legend table { \n border-spacing: 0px;\n border-collapse: separate;\n}\n\n.mouse-events .flot-overlay {\n cursor: crosshair; \n}\n\n",
"controllerScript": "self.onInit = function() { \n};\n\nself.onDataUpdated = function() {\n};\n\nself.onLatestDataUpdated = function() {\n};\n\nself.onResize = function() {\n};\n\nself.onEditModeChanged = function() {\n};\n\nself.onDestroy = function() {\n};\n\nself.typeParameters = function() {\n return {\n hasAdditionalLatestDataKeys: false\n };\n}\n",
diff --git a/application/src/main/data/json/system/widget_types/gateway_general_configuration.json b/application/src/main/data/json/system/widget_types/gateway_general_configuration.json
index e2129c0271..e260746bec 100644
--- a/application/src/main/data/json/system/widget_types/gateway_general_configuration.json
+++ b/application/src/main/data/json/system/widget_types/gateway_general_configuration.json
@@ -8,7 +8,15 @@
"type": "latest",
"sizeX": 11,
"sizeY": 8,
- "resources": [],
+ "resources": [
+ {
+ "url": {
+ "entityType": "TB_RESOURCE",
+ "id": "71347080-80b6-11ef-a567-0114914c70f8"
+ },
+ "isModule": true
+ }
+ ],
"templateHtml": "",
"templateCss": "",
"controllerScript": "self.onInit = function() {\n if (self.ctx.datasources && self.ctx.datasources.length) {\n self.ctx.$scope.entityId = self.ctx.datasources[0].entity.id;\n }\n};\n\nself.typeParameters = function() {\n return {\n dataKeysOptional: true,\n singleEntity: true\n };\n}",
diff --git a/application/src/main/data/json/system/widget_types/gateway_logs.json b/application/src/main/data/json/system/widget_types/gateway_logs.json
index 45b380e544..2d408a5ea6 100644
--- a/application/src/main/data/json/system/widget_types/gateway_logs.json
+++ b/application/src/main/data/json/system/widget_types/gateway_logs.json
@@ -8,7 +8,15 @@
"type": "timeseries",
"sizeX": 7.5,
"sizeY": 3,
- "resources": [],
+ "resources": [
+ {
+ "url": {
+ "entityType": "TB_RESOURCE",
+ "id": "71347080-80b6-11ef-a567-0114914c70f8"
+ },
+ "isModule": true
+ }
+ ],
"templateHtml": "\n \n",
"templateCss": "#container {\n overflow: auto;\n}\n\n.tbDatasource-container {\n margin: 5px;\n padding: 8px;\n}\n\n.tbDatasource-title {\n font-size: 1.200rem;\n font-weight: 500;\n padding-bottom: 10px;\n}\n\n.tbDatasource-table {\n width: 100%;\n box-shadow: 0 0 10px #ccc;\n border-collapse: collapse;\n white-space: nowrap;\n font-size: 1.000rem;\n color: #757575;\n}\n\n.tbDatasource-table td {\n position: relative;\n border-top: 1px solid rgba(0, 0, 0, 0.12);\n border-bottom: 1px solid rgba(0, 0, 0, 0.12);\n padding: 0px 18px;\n box-sizing: border-box;\n}",
"controllerScript": "self.onInit = function() {\n};\n\nself.typeParameters = function() {\n return {\n dataKeysOptional: true,\n singleEntity: true\n };\n}",
diff --git a/application/src/main/data/json/system/widget_types/service_rpc.json b/application/src/main/data/json/system/widget_types/service_rpc.json
index 23cc13adf0..7e1276a486 100644
--- a/application/src/main/data/json/system/widget_types/service_rpc.json
+++ b/application/src/main/data/json/system/widget_types/service_rpc.json
@@ -8,7 +8,15 @@
"type": "rpc",
"sizeX": 8.5,
"sizeY": 5.5,
- "resources": [],
+ "resources": [
+ {
+ "url": {
+ "entityType": "TB_RESOURCE",
+ "id": "71347080-80b6-11ef-a567-0114914c70f8"
+ },
+ "isModule": true
+ }
+ ],
"templateHtml": "",
"templateCss": ".error {\n font-size: 14px !important;\n color: maroon;/*rgb(250,250,250);*/\n background-color: transparent;\n padding: 6px;\n}\n\n.error span {\n margin: auto;\n}\n\n.gpio-panel {\n padding-top: 10px;\n white-space: nowrap;\n}\n\n.gpio-panel section[fxflex] {\n min-width: 0px;\n}\n\n\n.switch-panel {\n margin: 0;\n height: 32px;\n width: 66px;\n min-width: 66px;\n}\n\n.switch-panel mat-slide-toggle {\n margin: 0;\n width: 36px;\n min-width: 36px;\n}\n\n.switch-panel.col-0 mat-slide-toggle {\n margin-left: 8px;\n margin-right: 4px;\n}\n\n.switch-panel.col-1 mat-slide-toggle {\n margin-left: 4px;\n margin-right: 8px;\n}\n\n.gpio-row {\n height: 32px;\n}\n\n.pin {\n margin-top: auto;\n margin-bottom: auto;\n color: white;\n font-size: 12px;\n width: 16px;\n min-width: 16px;\n}\n\n.switch-panel.col-0 .pin {\n margin-left: auto;\n padding-left: 2px;\n text-align: right;\n}\n\n.switch-panel.col-1 .pin {\n margin-right: auto;\n \n text-align: left;\n}\n\n.gpio-left-label {\n margin-right: 8px;\n}\n\n.gpio-right-label {\n margin-left: 8px;\n}",
"controllerScript": "\nself.onInit = function() {\n};",
diff --git a/application/src/main/data/json/tenant/dashboards/gateways.json b/application/src/main/data/json/tenant/dashboards/gateways.json
index 668b92b7b2..5d910493ab 100644
--- a/application/src/main/data/json/tenant/dashboards/gateways.json
+++ b/application/src/main/data/json/tenant/dashboards/gateways.json
@@ -1919,7 +1919,15 @@
"customHtml": "
\n
\n {{ 'gateway.launch-command' | translate }}
\n \n \n \n \n
\n
\n \n
\n
\n",
"customCss": ".container {\n display: grid;\n grid-template-rows: min-content minmax(auto, 1fr) min-content;\n height: 100%;\n max-height: 100vh;\n width: 600px;\n max-width: 100%;\n}",
"customFunction": "let $injector = widgetContext.$scope.$injector;\nlet customDialog = $injector.get(widgetContext.servicesMap.get('customDialog'));\n\nopenCommands();\n\nfunction openCommands() {\n customDialog.customDialog(htmlTemplate, CommandsDialogController, {panelClass: \"test\"}).subscribe();\n}\n\nfunction CommandsDialogController(instance) {\n let vm = instance;\n \n vm.entityId = entityId.id;\n\n vm.cancel = function() {\n vm.dialogRef.close(null);\n };\n}\n",
- "customResources": [],
+ "customResources": [
+ {
+ "url": {
+ "entityType": "TB_RESOURCE",
+ "id": "71347080-80b6-11ef-a567-0114914c70f8"
+ },
+ "isModule": true
+ }
+ ],
"openInSeparateDialog": false,
"openInPopover": false,
"id": "337c767b-3217-d3d3-b955-7b0bd0858a1d"
diff --git a/ui-ngx/src/app/modules/common/modules-map.ts b/ui-ngx/src/app/modules/common/modules-map.ts
index 512719c513..82401a4d6e 100644
--- a/ui-ngx/src/app/modules/common/modules-map.ts
+++ b/ui-ngx/src/app/modules/common/modules-map.ts
@@ -196,6 +196,9 @@ import * as HintTooltipIconComponent from '@shared/components/hint-tooltip-icon.
import * as ScrollGridComponent from '@shared/components/grid/scroll-grid.component';
import * as GalleryImageInputComponent from '@shared/components/image/gallery-image-input.component';
import * as MultipleGalleryImageInputComponent from '@shared/components/image/multiple-gallery-image-input.component';
+import * as TbPopoverService from '@shared/components/popover.service';
+
+import * as AttributeDatasource from '@home/models/datasource/attribute-datasource';
import * as CssUnitSelectComponent from '@home/components/widget/lib/settings/common/css-unit-select.component';
import * as WidgetActionsPanelComponent from '@home/components/widget/config/basic/common/widget-actions-panel.component';
@@ -247,6 +250,7 @@ import * as CustomActionPrettyEditorComponent from '@home/components/widget/lib/
import * as MobileActionEditorComponent from '@home/components/widget/lib/settings/common/action/mobile-action-editor.component';
import * as CustomDialogService from '@home/components/widget/dialog/custom-dialog.service';
import * as CustomDialogContainerComponent from '@home/components/widget/dialog/custom-dialog-container.component';
+import * as ImportExportService from '@shared/import-export/import-export.service';
import * as ImportDialogComponent from '@shared/import-export/import-dialog.component';
import * as AddWidgetToDashboardDialogComponent from '@home/components/attribute/add-widget-to-dashboard-dialog.component';
import * as ImportDialogCsvComponent from '@shared/import-export/import-dialog-csv.component';
@@ -255,6 +259,7 @@ import * as EventContentDialogComponent from '@home/components/event/event-conte
import * as SharedHomeComponentsModule from '@home/components/shared-home-components.module';
import * as WidgetConfigComponentsModule from '@home/components/widget/config/widget-config-components.module';
import * as BasicWidgetConfigModule from '@home/components/widget/config/basic/basic-widget-config.module';
+import * as TbFlot from '@home/components/widget/lib/flot-widget';
import * as WidgetSettingsCommonModule from '@home/components/widget/lib/settings/common/widget-settings-common.module';
import * as WidgetComponentsModule from '@home/components/widget/widget-components.module';
import * as SelectTargetLayoutDialogComponent from '@home/components/dashboard/select-target-layout-dialog.component';
@@ -435,6 +440,7 @@ class ModulesMap implements IModulesMap {
'@shared/decorators/enumerable': enumerable,
'@shared/decorators/tb-inject': TbInject,
+ '@shared/import-export/import-export.service': ImportExportService,
'@shared/import-export/import-dialog.component': ImportDialogComponent,
'@shared/import-export/import-dialog-csv.component': ImportDialogCsvComponent,
'@shared/import-export/table-columns-assignment.component': TableColumnsAssignmentComponent,
@@ -533,6 +539,9 @@ class ModulesMap implements IModulesMap {
'@shared/components/grid/scroll-grid.component': ScrollGridComponent,
'@shared/components/image/gallery-image-input.component': GalleryImageInputComponent,
'@shared/components/image/multiple-gallery-image-input.component': MultipleGalleryImageInputComponent,
+ '@shared/components/popover.service': TbPopoverService,
+
+ '@home/models/datasource/attribute-datasource': AttributeDatasource,
'@home/components/alarm/alarm-filter-config.component': AlarmFilterConfigComponent,
'@home/components/alarm/alarm-comment-dialog.component': AlarmCommentDialogComponent,
@@ -576,6 +585,7 @@ class ModulesMap implements IModulesMap {
'@home/components/widget/config/data-keys.component': DataKeysComponent,
'@home/components/widget/config/data-key-config-dialog.component': DataKeyConfigDialogComponent,
'@home/components/widget/config/data-key-config.component': DataKeyConfigComponent,
+ '@home/components/widget/lib/flot-widget': TbFlot,
'@home/components/widget/lib/settings/common/legend-config.component': LegendConfigComponent,
'@home/components/widget/action/manage-widget-actions.component': ManageWidgetActionsComponent,
'@home/components/widget/action/widget-action-dialog.component': WidgetActionDialogComponent,
diff --git a/ui-ngx/src/app/shared/components/public-api.ts b/ui-ngx/src/app/shared/components/public-api.ts
index 8aef3e83f7..8d7f825b5b 100644
--- a/ui-ngx/src/app/shared/components/public-api.ts
+++ b/ui-ngx/src/app/shared/components/public-api.ts
@@ -31,3 +31,4 @@ export * from './icon.component';
export * from './hint-tooltip-icon.component';
export * from './grid/scroll-grid-datasource';
export * from './grid/scroll-grid.component';
+export * from './table/table-datasource.abstract';