diff --git a/ui/src/app/api/widget.service.js b/ui/src/app/api/widget.service.js
index 1c5e5f4126..f8f27ed932 100644
--- a/ui/src/app/api/widget.service.js
+++ b/ui/src/app/api/widget.service.js
@@ -20,6 +20,7 @@ import tinycolor from 'tinycolor2';
import thingsboardLedLight from '../components/led-light.directive';
import thingsboardTimeseriesTableWidget from '../widget/lib/timeseries-table-widget';
import thingsboardAlarmsTableWidget from '../widget/lib/alarms-table-widget';
+import thingsboardEntitiesTableWidget from '../widget/lib/entities-table-widget';
import TbFlot from '../widget/lib/flot-widget';
import TbAnalogueLinearGauge from '../widget/lib/analogue-linear-gauge';
@@ -34,7 +35,7 @@ import thingsboardTypes from '../common/types.constant';
import thingsboardUtils from '../common/utils.service';
export default angular.module('thingsboard.api.widget', ['oc.lazyLoad', thingsboardLedLight, thingsboardTimeseriesTableWidget,
- thingsboardAlarmsTableWidget, thingsboardTypes, thingsboardUtils])
+ thingsboardAlarmsTableWidget, thingsboardEntitiesTableWidget, thingsboardTypes, thingsboardUtils])
.factory('widgetService', WidgetService)
.name;
@@ -546,6 +547,14 @@ function WidgetService($rootScope, $http, $q, $filter, $ocLazyLoad, $window, typ
' }\n\n' +
+ ' self.typeParameters = function() {\n\n' +
+ {
+ useCustomDatasources: false,
+ maxDatasources: -1 //unlimited
+ maxDataKeys: -1 //unlimited
+ }
+ ' }\n\n' +
+
' self.onResize = function() {\n\n' +
' }\n\n' +
@@ -586,10 +595,21 @@ function WidgetService($rootScope, $http, $q, $filter, $ocLazyLoad, $window, typ
if (angular.isFunction(widgetTypeInstance.getDataKeySettingsSchema)) {
result.dataKeySettingsSchema = widgetTypeInstance.getDataKeySettingsSchema();
}
+ if (angular.isFunction(widgetTypeInstance.typeParameters)) {
+ result.typeParameters = widgetTypeInstance.typeParameters();
+ } else {
+ result.typeParameters = {};
+ }
if (angular.isFunction(widgetTypeInstance.useCustomDatasources)) {
- result.useCustomDatasources = widgetTypeInstance.useCustomDatasources();
+ result.typeParameters.useCustomDatasources = widgetTypeInstance.useCustomDatasources();
} else {
- result.useCustomDatasources = false;
+ result.typeParameters.useCustomDatasources = false;
+ }
+ if (angular.isUndefined(result.typeParameters.maxDatasources)) {
+ result.typeParameters.maxDatasources = -1;
+ }
+ if (angular.isUndefined(result.typeParameters.maxDataKeys)) {
+ result.typeParameters.maxDataKeys = -1;
}
return result;
} catch (e) {
@@ -629,7 +649,7 @@ function WidgetService($rootScope, $http, $q, $filter, $ocLazyLoad, $window, typ
if (widgetType.dataKeySettingsSchema) {
widgetInfo.typeDataKeySettingsSchema = widgetType.dataKeySettingsSchema;
}
- widgetInfo.useCustomDatasources = widgetType.useCustomDatasources;
+ widgetInfo.typeParameters = widgetType.typeParameters;
putWidgetInfoToCache(widgetInfo, bundleAlias, widgetInfo.alias, isSystem);
putWidgetTypeFunctionToCache(widgetType.widgetTypeFunction, bundleAlias, widgetInfo.alias, isSystem);
deferred.resolve(widgetInfo);
diff --git a/ui/src/app/components/datasource-entity.directive.js b/ui/src/app/components/datasource-entity.directive.js
index e6ec8f83a6..46c8b6344f 100644
--- a/ui/src/app/components/datasource-entity.directive.js
+++ b/ui/src/app/components/datasource-entity.directive.js
@@ -156,11 +156,19 @@ function DatasourceEntity($compile, $templateCache, $q, $mdDialog, $window, $doc
};
scope.transformTimeseriesDataKeyChip = function (chip) {
- return scope.generateDataKey({chip: chip, type: types.dataKeyType.timeseries});
+ if (scope.maxDataKeys > 0 && ngModelCtrl.$viewValue.dataKeys.length >= scope.maxDataKeys ) {
+ return null;
+ } else {
+ return scope.generateDataKey({chip: chip, type: types.dataKeyType.timeseries});
+ }
};
scope.transformAttributeDataKeyChip = function (chip) {
- return scope.generateDataKey({chip: chip, type: types.dataKeyType.attribute});
+ if (scope.maxDataKeys > 0 && ngModelCtrl.$viewValue.dataKeys.length >= scope.maxDataKeys ) {
+ return null;
+ } else {
+ return scope.generateDataKey({chip: chip, type: types.dataKeyType.attribute});
+ }
};
scope.transformAlarmDataKeyChip = function (chip) {
@@ -272,6 +280,7 @@ function DatasourceEntity($compile, $templateCache, $q, $mdDialog, $window, $doc
require: "^ngModel",
scope: {
widgetType: '=',
+ maxDataKeys: '=',
aliasController: '=',
datakeySettingsSchema: '=',
generateDataKey: '&',
diff --git a/ui/src/app/components/datasource-entity.tpl.html b/ui/src/app/components/datasource-entity.tpl.html
index 9876491086..e788f30949 100644
--- a/ui/src/app/components/datasource-entity.tpl.html
+++ b/ui/src/app/components/datasource-entity.tpl.html
@@ -186,5 +186,10 @@
datakey.timeseries-or-attributes-required
datakey.alarm-fields-required
+
diff --git a/ui/src/app/components/datasource-func.directive.js b/ui/src/app/components/datasource-func.directive.js
index 2a2ae82111..96e03871c1 100644
--- a/ui/src/app/components/datasource-func.directive.js
+++ b/ui/src/app/components/datasource-func.directive.js
@@ -117,7 +117,11 @@ function DatasourceFunc($compile, $templateCache, $mdDialog, $window, $document,
};
scope.transformFuncDataKeyChip = function (chip) {
- return scope.generateDataKey({chip: chip, type: types.dataKeyType.function});
+ if (scope.maxDataKeys > 0 && ngModelCtrl.$viewValue.dataKeys.length >= scope.maxDataKeys ) {
+ return null;
+ } else {
+ return scope.generateDataKey({chip: chip, type: types.dataKeyType.function});
+ }
};
scope.transformAlarmDataKeyChip = function (chip) {
@@ -217,6 +221,7 @@ function DatasourceFunc($compile, $templateCache, $mdDialog, $window, $document,
require: "^ngModel",
scope: {
widgetType: '=',
+ maxDataKeys: '=',
generateDataKey: '&',
datakeySettingsSchema: '='
},
diff --git a/ui/src/app/components/datasource-func.tpl.html b/ui/src/app/components/datasource-func.tpl.html
index 7fa4aac008..8a57b07699 100644
--- a/ui/src/app/components/datasource-func.tpl.html
+++ b/ui/src/app/components/datasource-func.tpl.html
@@ -17,7 +17,7 @@
-->
diff --git a/ui/src/app/components/datasource.directive.js b/ui/src/app/components/datasource.directive.js
index b5327e298c..42011b03a4 100644
--- a/ui/src/app/components/datasource.directive.js
+++ b/ui/src/app/components/datasource.directive.js
@@ -82,6 +82,7 @@ function Datasource($compile, $templateCache, utils, types) {
require: "^ngModel",
scope: {
aliasController: '=',
+ maxDataKeys: '=',
widgetType: '=',
functionsOnly: '=',
datakeySettingsSchema: '=',
diff --git a/ui/src/app/components/datasource.tpl.html b/ui/src/app/components/datasource.tpl.html
index 0633f5f2bf..41b18dbb51 100644
--- a/ui/src/app/components/datasource.tpl.html
+++ b/ui/src/app/components/datasource.tpl.html
@@ -27,6 +27,7 @@
- {{ 'widget-config.datasources' | translate }}
+
+
{{ 'widget-config.datasources' | translate }}
+
+
@@ -88,6 +95,7 @@
style="padding: 0 0 0 10px; margin: 5px;">
-
{{ 'widget-config.add-datasource' | translate }}
@@ -140,7 +148,7 @@
-
diff --git a/ui/src/app/components/widget.controller.js b/ui/src/app/components/widget.controller.js
index baedd094b0..f2e231fa29 100644
--- a/ui/src/app/components/widget.controller.js
+++ b/ui/src/app/components/widget.controller.js
@@ -128,7 +128,7 @@ export default function WidgetController($scope, $timeout, $window, $element, $q
var widgetTypeInstance;
- vm.useCustomDatasources = false;
+ vm.typeParameters = widgetInfo.typeParameters;
try {
widgetTypeInstance = new widgetType(widgetContext);
@@ -154,9 +154,6 @@ export default function WidgetController($scope, $timeout, $window, $element, $q
if (!widgetTypeInstance.onDestroy) {
widgetTypeInstance.onDestroy = function() {};
}
- if (widgetTypeInstance.useCustomDatasources) {
- vm.useCustomDatasources = widgetTypeInstance.useCustomDatasources();
- }
//TODO: widgets visibility
@@ -502,7 +499,7 @@ export default function WidgetController($scope, $timeout, $window, $element, $q
var subscription = widgetContext.subscriptions[id];
subscriptionChanged = subscriptionChanged || subscription.onAliasesChanged(aliasIds);
}
- if (subscriptionChanged && !vm.useCustomDatasources) {
+ if (subscriptionChanged && !vm.typeParameters.useCustomDatasources) {
reInit();
}
});
@@ -513,7 +510,7 @@ export default function WidgetController($scope, $timeout, $window, $element, $q
configureWidgetElement();
var deferred = $q.defer();
- if (!vm.useCustomDatasources) {
+ if (!vm.typeParameters.useCustomDatasources) {
createDefaultSubscription().then(
function success() {
subscriptionInited = true;
@@ -535,7 +532,7 @@ export default function WidgetController($scope, $timeout, $window, $element, $q
function reInit() {
onDestroy();
configureWidgetElement();
- if (!vm.useCustomDatasources) {
+ if (!vm.typeParameters.useCustomDatasources) {
createDefaultSubscription().then(
function success() {
subscriptionInited = true;
@@ -575,7 +572,7 @@ export default function WidgetController($scope, $timeout, $window, $element, $q
} catch (e) {
handleWidgetException(e);
}
- if (!vm.useCustomDatasources && widgetContext.defaultSubscription) {
+ if (!vm.typeParameters.useCustomDatasources && widgetContext.defaultSubscription) {
widgetContext.defaultSubscription.subscribe();
}
}
diff --git a/ui/src/app/dashboard/add-widget.tpl.html b/ui/src/app/dashboard/add-widget.tpl.html
index 761776057b..894c23d482 100644
--- a/ui/src/app/dashboard/add-widget.tpl.html
+++ b/ui/src/app/dashboard/add-widget.tpl.html
@@ -33,6 +33,7 @@