thingsboard-memoizeit
Changes
ui/src/app/api/alias-controller.js 4(+4 -0)
ui/src/app/api/subscription.js 103(+13 -90)
ui/src/app/common/dashboard-utils.service.js 85(+73 -12)
ui/src/app/common/utils.service.js 11(+11 -0)
ui/src/app/components/dashboard.directive.js 31(+22 -9)
ui/src/app/components/widget.controller.js 157(+102 -55)
ui/src/app/components/widget.directive.js 85(+2 -83)
ui/src/app/entity/entity-aliases.scss 15(+12 -3)
ui/src/app/entity/entity-aliases.tpl.html 56(+30 -26)
ui/src/app/entity/entity-filter.directive.js 163(+1 -162)
ui/src/app/entity/entity-filter.scss 15(+2 -13)
ui/src/app/entity/entity-filter.tpl.html 101(+29 -72)
ui/src/app/locale/locale.constant.js 2(+1 -1)
Details
ui/src/app/api/alias-controller.js 4(+4 -0)
diff --git a/ui/src/app/api/alias-controller.js b/ui/src/app/api/alias-controller.js
index 49eb8fe..b6d29a9 100644
--- a/ui/src/app/api/alias-controller.js
+++ b/ui/src/app/api/alias-controller.js
@@ -100,6 +100,7 @@ export default class AliasController {
aliasCtrl.resolvedAliasesToStateEntities[aliasId] =
aliasCtrl.stateController.getStateParams().entityId;
}
+ aliasCtrl.$scope.$broadcast('entityAliasResolved', aliasId);
deferred.resolve(aliasInfo);
},
function fail() {
@@ -239,6 +240,9 @@ export default class AliasController {
datasource.name = name;
datasource.aliasName = name;
datasource.entityName = name;
+ } else if (datasource.unresolvedStateEntity) {
+ datasource.name = "Unresolved";
+ datasource.entityName = "Unresolved";
}
datasource.dataKeys.forEach(function(dataKey) {
if (datasource.generated) {
ui/src/app/api/subscription.js 103(+13 -90)
diff --git a/ui/src/app/api/subscription.js b/ui/src/app/api/subscription.js
index dd518c7..4cb382c 100644
--- a/ui/src/app/api/subscription.js
+++ b/ui/src/app/api/subscription.js
@@ -73,6 +73,15 @@ export default class Subscription {
this.datasources = this.ctx.utils.validateDatasources(options.datasources);
this.datasourceListeners = [];
+
+ /*
+ * data = array of datasourceData
+ * datasourceData = {
+ * tbDatasource,
+ * dataKey, { name, config }
+ * data = array of [time, value]
+ * }
+ */
this.data = [];
this.hiddenData = [];
this.originalTimewindow = null;
@@ -543,39 +552,6 @@ export default class Subscription {
var datasource = this.datasources[i];
if (angular.isFunction(datasource))
continue;
- /* var entityId = null;
- var entityType = null;
- if (datasource.type === this.ctx.types.datasourceType.entity) {
- var aliasName = null;
- var entityName = null;
- if (datasource.entityId) {
- entityId = datasource.entityId;
- entityType = datasource.entityType;
- datasource.name = datasource.entityName;
- aliasName = datasource.entityName;
- entityName = datasource.entityName;
- } else if (datasource.entityAliasId) {
- if (this.ctx.aliasesInfo.entityAliases[datasource.entityAliasId]) {
- entityId = this.ctx.aliasesInfo.entityAliases[datasource.entityAliasId].entityId;
- entityType = this.ctx.aliasesInfo.entityAliases[datasource.entityAliasId].entityType;
- datasource.name = this.ctx.aliasesInfo.entityAliases[datasource.entityAliasId].alias;
- aliasName = this.ctx.aliasesInfo.entityAliases[datasource.entityAliasId].alias;
- entityName = '';
- var entitiesInfo = this.ctx.aliasesInfo.entityAliasesInfo[datasource.entityAliasId];
- for (var d = 0; d < entitiesInfo.length; d++) {
- if (entitiesInfo[d].id === entityId) {
- entityName = entitiesInfo[d].name;
- break;
- }
- }
- }
- }
- } else {
- datasource.name = datasource.name || this.ctx.types.datasourceType.function;
- }
- for (var dk = 0; dk < datasource.dataKeys.length; dk++) {
- updateDataKeyLabel(datasource.dataKeys[dk], datasource.name, entityName, aliasName);
- }*/
var subscription = this;
@@ -606,6 +582,10 @@ export default class Subscription {
this.datasourceListeners.push(listener);
this.ctx.datasourceService.subscribeToDatasource(listener);
+ if (datasource.unresolvedStateEntity) {
+ this.notifyDataLoaded();
+ this.onDataUpdated();
+ }
}
}
@@ -625,19 +605,6 @@ export default class Subscription {
} else {
return false;
}
- /*var deviceId = null;
- if (this.ctx.aliasesInfo.entityAliases[this.targetDeviceAliasId]) {
- deviceId = this.ctx.aliasesInfo.entityAliases[this.targetDeviceAliasId].entityId;
- }
- if (!angular.equals(deviceId, this.targetDeviceId)) {
- this.targetDeviceId = deviceId;
- if (this.targetDeviceId) {
- this.rpcEnabled = true;
- } else {
- this.rpcEnabled = this.ctx.$scope.widgetEditMode ? true : false;
- }
- this.callbacks.rpcStateChanged(this);
- }*/
}
checkSubscriptions(aliasIds) {
@@ -650,29 +617,8 @@ export default class Subscription {
break;
}
}
- /*var entityId = null;
- var entityType = null;
- var aliasName = null;
- if (listener.datasource.type === this.ctx.types.datasourceType.entity) {
- if (listener.datasource.entityAliasId &&
- this.ctx.aliasesInfo.entityAliases[listener.datasource.entityAliasId]) {
- entityId = this.ctx.aliasesInfo.entityAliases[listener.datasource.entityAliasId].entityId;
- entityType = this.ctx.aliasesInfo.entityAliases[listener.datasource.entityAliasId].entityType;
- aliasName = this.ctx.aliasesInfo.entityAliases[listener.datasource.entityAliasId].alias;
- }
- if (!angular.equals(entityId, listener.entityId) ||
- !angular.equals(entityType, listener.entityType) ||
- !angular.equals(aliasName, listener.datasource.name)) {
- subscriptionsChanged = true;
- break;
- }
- }*/
}
return subscriptionsChanged;
- /*if (subscriptionsChanged) {
- this.unsubscribe();
- this.subscribe();
- }*/
}
destroy() {
@@ -691,29 +637,6 @@ export default class Subscription {
}
-/*const varsRegex = /\$\{([^\}]*)\}/g;
-
-function updateDataKeyLabel(dataKey, dsName, entityName, aliasName) {
- var pattern = dataKey.pattern;
- var label = dataKey.pattern;
- var match = varsRegex.exec(pattern);
- while (match !== null) {
- var variable = match[0];
- var variableName = match[1];
- if (variableName === 'dsName') {
- label = label.split(variable).join(dsName);
- } else if (variableName === 'entityName') {
- label = label.split(variable).join(entityName);
- } else if (variableName === 'deviceName') {
- label = label.split(variable).join(entityName);
- } else if (variableName === 'aliasName') {
- label = label.split(variable).join(aliasName);
- }
- match = varsRegex.exec(pattern);
- }
- dataKey.label = label;
-}*/
-
function calculateMin(data) {
if (data.length > 0) {
var result = Number(data[0][1]);
ui/src/app/common/dashboard-utils.service.js 85(+73 -12)
diff --git a/ui/src/app/common/dashboard-utils.service.js b/ui/src/app/common/dashboard-utils.service.js
index 58d1dbd..fe8aa93 100644
--- a/ui/src/app/common/dashboard-utils.service.js
+++ b/ui/src/app/common/dashboard-utils.service.js
@@ -23,8 +23,10 @@ function DashboardUtils(types, utils, timeService) {
var service = {
validateAndUpdateDashboard: validateAndUpdateDashboard,
+ validateAndUpdateWidget: validateAndUpdateWidget,
getRootStateId: getRootStateId,
createSingleWidgetDashboard: createSingleWidgetDashboard,
+ createSingleEntityFilter: createSingleEntityFilter,
getStateLayoutsData: getStateLayoutsData,
createDefaultState: createDefaultState,
createDefaultLayoutData: createDefaultLayoutData,
@@ -39,7 +41,7 @@ function DashboardUtils(types, utils, timeService) {
return service;
- function validateAndUpdateEntityAliases(configuration) {
+ function validateAndUpdateEntityAliases(configuration, datasourcesByAliasId, targetDevicesByAliasId) {
var aliasId, entityAlias;
if (angular.isUndefined(configuration.entityAliases)) {
configuration.entityAliases = {};
@@ -47,8 +49,8 @@ function DashboardUtils(types, utils, timeService) {
var deviceAliases = configuration.deviceAliases;
for (aliasId in deviceAliases) {
var deviceAlias = deviceAliases[aliasId];
- entityAlias = validateAndUpdateDeviceAlias(aliasId, deviceAlias);
- configuration.entityAliases[aliasId] = entityAlias;
+ entityAlias = validateAndUpdateDeviceAlias(aliasId, deviceAlias, datasourcesByAliasId, targetDevicesByAliasId);
+ configuration.entityAliases[entityAlias.id] = entityAlias;
}
delete configuration.deviceAliases;
}
@@ -56,16 +58,43 @@ function DashboardUtils(types, utils, timeService) {
var entityAliases = configuration.entityAliases;
for (aliasId in entityAliases) {
entityAlias = entityAliases[aliasId];
- entityAliases[aliasId] = validateAndUpdateEntityAlias(entityAlias);
- if (!entityAliases[aliasId].id) {
- entityAliases[aliasId].id = aliasId;
+ entityAlias = validateAndUpdateEntityAlias(aliasId, entityAlias, datasourcesByAliasId, targetDevicesByAliasId);
+ if (aliasId != entityAlias.id) {
+ delete entityAliases[aliasId];
}
+ entityAliases[entityAlias.id] = entityAlias;
}
}
return configuration;
}
- function validateAndUpdateDeviceAlias(aliasId, deviceAlias) {
+ function validateAliasId(aliasId, datasourcesByAliasId, targetDevicesByAliasId) {
+ if (!aliasId || !angular.isString(aliasId) || aliasId.length != 36) {
+ var newAliasId = utils.guid();
+ var aliasDatasources = datasourcesByAliasId[aliasId];
+ if (aliasDatasources) {
+ aliasDatasources.forEach(
+ function(datasource) {
+ datasource.entityAliasId = newAliasId;
+ }
+ );
+ }
+ var targetDeviceAliasIdsList = targetDevicesByAliasId[aliasId];
+ if (targetDeviceAliasIdsList) {
+ targetDeviceAliasIdsList.forEach(
+ function(targetDeviceAliasIds) {
+ targetDeviceAliasIds[0] = newAliasId;
+ }
+ );
+ }
+ return newAliasId;
+ } else {
+ return aliasId;
+ }
+ }
+
+ function validateAndUpdateDeviceAlias(aliasId, deviceAlias, datasourcesByAliasId, targetDevicesByAliasId) {
+ aliasId = validateAliasId(aliasId, datasourcesByAliasId, targetDevicesByAliasId);
var alias = deviceAlias.alias;
var entityAlias = {
id: aliasId,
@@ -93,7 +122,8 @@ function DashboardUtils(types, utils, timeService) {
return entityAlias;
}
- function validateAndUpdateEntityAlias(entityAlias) {
+ function validateAndUpdateEntityAlias(aliasId, entityAlias, datasourcesByAliasId, targetDevicesByAliasId) {
+ entityAlias.id = validateAliasId(aliasId, datasourcesByAliasId, targetDevicesByAliasId);
if (!entityAlias.filter) {
entityAlias.filter = {
type: entityAlias.entityFilter.useFilter ? types.aliasFilterType.entityName.value : types.aliasFilterType.entityList.value,
@@ -206,12 +236,33 @@ function DashboardUtils(types, utils, timeService) {
}
}
- /* var datasources = {};
+ var datasourcesByAliasId = {};
+ var targetDevicesByAliasId = {};
for (var widgetId in dashboard.configuration.widgets) {
+ widget = dashboard.configuration.widgets[widgetId];
+ widget.config.datasources.forEach(function (datasource) {
+ if (datasource.entityAliasId) {
+ var aliasId = datasource.entityAliasId;
+ var aliasDatasources = datasourcesByAliasId[aliasId];
+ if (!aliasDatasources) {
+ aliasDatasources = [];
+ datasourcesByAliasId[aliasId] = aliasDatasources;
+ }
+ aliasDatasources.push(datasource);
+ }
+ });
+ if (widget.config.targetDeviceAliasIds && widget.config.targetDeviceAliasIds.length) {
+ var aliasId = widget.config.targetDeviceAliasIds[0];
+ var targetDeviceAliasIdsList = targetDevicesByAliasId[aliasId];
+ if (!targetDeviceAliasIdsList) {
+ targetDeviceAliasIdsList = [];
+ targetDevicesByAliasId[aliasId] = targetDeviceAliasIdsList;
+ }
+ targetDeviceAliasIdsList.push(widget.config.targetDeviceAliasIds);
+ }
+ }
- }*/
-
- dashboard.configuration = validateAndUpdateEntityAliases(dashboard.configuration);
+ dashboard.configuration = validateAndUpdateEntityAliases(dashboard.configuration, datasourcesByAliasId, targetDevicesByAliasId);
if (angular.isUndefined(dashboard.configuration.timewindow)) {
dashboard.configuration.timewindow = timeService.defaultTimewindow();
@@ -288,6 +339,16 @@ function DashboardUtils(types, utils, timeService) {
return dashboard;
}
+ function createSingleEntityFilter(entityType, entityId) {
+ return {
+ type: types.aliasFilterType.entityList.value,
+ stateEntity: false,
+ entityList: [entityId],
+ entityType: entityType,
+ resolveMultiple: false
+ };
+ }
+
function getStateLayoutsData(dashboard, targetState) {
var dashboardConfiguration = dashboard.configuration;
var states = dashboardConfiguration.states;
ui/src/app/common/utils.service.js 11(+11 -0)
diff --git a/ui/src/app/common/utils.service.js b/ui/src/app/common/utils.service.js
index 7b4d65e..8bf76c4 100644
--- a/ui/src/app/common/utils.service.js
+++ b/ui/src/app/common/utils.service.js
@@ -106,6 +106,7 @@ function Utils($mdColorPalette, $rootScope, $window, types) {
isDescriptorSchemaNotEmpty: isDescriptorSchemaNotEmpty,
filterSearchTextEntities: filterSearchTextEntities,
guid: guid,
+ cleanCopy: cleanCopy,
isLocalUrl: isLocalUrl,
validateDatasources: validateDatasources,
createKey: createKey,
@@ -291,6 +292,16 @@ function Utils($mdColorPalette, $rootScope, $window, types) {
s4() + '-' + s4() + s4() + s4();
}
+ function cleanCopy(object) {
+ var copy = angular.copy(object);
+ for (var prop in copy) {
+ if (prop && prop.startsWith('$$')) {
+ delete copy[prop];
+ }
+ }
+ return copy;
+ }
+
function genNextColor(datasources) {
var index = 0;
if (datasources) {
ui/src/app/components/dashboard.directive.js 31(+22 -9)
diff --git a/ui/src/app/components/dashboard.directive.js b/ui/src/app/components/dashboard.directive.js
index 965b838..a88e656 100644
--- a/ui/src/app/components/dashboard.directive.js
+++ b/ui/src/app/components/dashboard.directive.js
@@ -85,7 +85,7 @@ function Dashboard() {
}
/*@ngInject*/
-function DashboardController($scope, $rootScope, $element, $timeout, $mdMedia, timeService, types, utils) {
+function DashboardController($scope, $rootScope, $element, $timeout, $mdMedia, $mdUtil, timeService, types, utils) {
var highlightedMode = false;
var highlightedWidget = null;
@@ -792,7 +792,7 @@ function DashboardController($scope, $rootScope, $element, $timeout, $mdMedia, t
}
function dashboardLoaded() {
- $timeout(function () {
+ $mdUtil.nextTick(function () {
if (vm.dashboardTimewindowWatch) {
vm.dashboardTimewindowWatch();
vm.dashboardTimewindowWatch = null;
@@ -802,14 +802,27 @@ function DashboardController($scope, $rootScope, $element, $timeout, $mdMedia, t
}, true);
adoptMaxRows();
vm.dashboardLoading = false;
- $timeout(function () {
- var gridsterScope = gridsterElement.scope();
- vm.gridster = gridsterScope.gridster;
- if (vm.onInit) {
- vm.onInit({dashboard: vm});
+ if ($scope.gridsterScopeWatcher) {
+ $scope.gridsterScopeWatcher();
+ }
+ $scope.gridsterScopeWatcher = $scope.$watch(
+ function() {
+ var hasScope = gridsterElement.scope() ? true : false;
+ return hasScope;
+ },
+ function(hasScope) {
+ if (hasScope) {
+ $scope.gridsterScopeWatcher();
+ $scope.gridsterScopeWatcher = null;
+ var gridsterScope = gridsterElement.scope();
+ vm.gridster = gridsterScope.gridster;
+ if (vm.onInit) {
+ vm.onInit({dashboard: vm});
+ }
+ }
}
- }, 0, false);
- }, 0, false);
+ );
+ });
}
function loading() {
ui/src/app/components/widget.controller.js 157(+102 -55)
diff --git a/ui/src/app/components/widget.controller.js b/ui/src/app/components/widget.controller.js
index 4407381..08885b8 100644
--- a/ui/src/app/components/widget.controller.js
+++ b/ui/src/app/components/widget.controller.js
@@ -20,9 +20,9 @@ import Subscription from '../api/subscription';
/* eslint-disable angular/angularelement */
/*@ngInject*/
-export default function WidgetController($scope, $timeout, $window, $element, $q, $log, $injector, $filter, tbRaf, types, utils, timeService,
+export default function WidgetController($scope, $timeout, $window, $element, $q, $log, $injector, $filter, $compile, tbRaf, types, utils, timeService,
datasourceService, entityService, deviceService, visibleRect, isEdit, stDiff, dashboardTimewindow,
- dashboardTimewindowApi, widget, aliasController, stateController, widgetType) {
+ dashboardTimewindowApi, widget, aliasController, stateController, widgetInfo, widgetType) {
var vm = this;
@@ -42,20 +42,11 @@ export default function WidgetController($scope, $timeout, $window, $element, $q
var cafs = {};
- /*
- * data = array of datasourceData
- * datasourceData = {
- * tbDatasource,
- * dataKey, { name, config }
- * data = array of [time, value]
- * }
- */
-
var widgetContext = {
inited: false,
$scope: $scope,
- $container: $('#container', $element),
- $containerParent: $($element),
+ $container: null,
+ $containerParent: null,
width: 0,
height: 0,
isEdit: isEdit,
@@ -82,30 +73,6 @@ export default function WidgetController($scope, $timeout, $window, $element, $q
createSubscription: function(options, subscribe) {
return createSubscription(options, subscribe);
},
-
-
- // type: "timeseries" or "latest" or "rpc"
- /* subscriptionInfo = [
- {
- entityType: ""
- entityId: ""
- entityName: ""
- timeseries: [{ name: "", label: "" }, ..]
- attributes: [{ name: "", label: "" }, ..]
- }
- ..
- ]*/
-
- // options = {
- // timeWindowConfig,
- // useDashboardTimewindow,
- // legendConfig,
- // decimals,
- // units,
- // callbacks [ onDataUpdated(subscription, apply) ]
- // }
- //
-
createSubscriptionFromInfo: function (type, subscriptionsInfo, options, useDefaultComponents, subscribe) {
return createSubscriptionFromInfo(type, subscriptionsInfo, options, useDefaultComponents, subscribe);
},
@@ -211,21 +178,6 @@ export default function WidgetController($scope, $timeout, $window, $element, $q
}
);
- /*
- options = {
- type,
- targetDeviceAliasIds, // RPC
- targetDeviceIds, // RPC
- datasources,
- timeWindowConfig,
- useDashboardTimewindow,
- legendConfig,
- decimals,
- units,
- callbacks
- }
- */
-
function createSubscriptionFromInfo(type, subscriptionsInfo, options, useDefaultComponents, subscribe) {
var deferred = $q.defer();
options.type = type;
@@ -400,6 +352,101 @@ export default function WidgetController($scope, $timeout, $window, $element, $q
return deferred.promise;
}
+ function configureWidgetElement() {
+
+ $scope.displayLegend = angular.isDefined(widget.config.showLegend) ?
+ widget.config.showLegend : widget.type === types.widgetType.timeseries.value;
+
+ if ($scope.displayLegend) {
+ $scope.legendConfig = widget.config.legendConfig ||
+ {
+ position: types.position.bottom.value,
+ showMin: false,
+ showMax: false,
+ showAvg: widget.type === types.widgetType.timeseries.value,
+ showTotal: false
+ };
+ $scope.legendData = {
+ keys: [],
+ data: []
+ };
+ }
+
+ var html = '<div class="tb-absolute-fill tb-widget-error" ng-if="widgetErrorData">' +
+ '<span>Widget Error: {{ widgetErrorData.name + ": " + widgetErrorData.message}}</span>' +
+ '</div>' +
+ '<div class="tb-absolute-fill tb-widget-loading" ng-show="loadingData" layout="column" layout-align="center center">' +
+ '<md-progress-circular md-mode="indeterminate" ng-disabled="!loadingData" class="md-accent" md-diameter="40"></md-progress-circular>' +
+ '</div>';
+
+ var containerHtml = '<div id="container">' + widgetInfo.templateHtml + '</div>';
+ if ($scope.displayLegend) {
+ var layoutType;
+ if ($scope.legendConfig.position === types.position.top.value ||
+ $scope.legendConfig.position === types.position.bottom.value) {
+ layoutType = 'column';
+ } else {
+ layoutType = 'row';
+ }
+
+ var legendStyle;
+ switch($scope.legendConfig.position) {
+ case types.position.top.value:
+ legendStyle = 'padding-bottom: 8px;';
+ break;
+ case types.position.bottom.value:
+ legendStyle = 'padding-top: 8px;';
+ break;
+ case types.position.left.value:
+ legendStyle = 'padding-right: 0px;';
+ break;
+ case types.position.right.value:
+ legendStyle = 'padding-left: 0px;';
+ break;
+ }
+
+ var legendHtml = '<tb-legend style="'+legendStyle+'" legend-config="legendConfig" legend-data="legendData"></tb-legend>';
+ containerHtml = '<div flex id="widget-container">' + containerHtml + '</div>';
+ html += '<div class="tb-absolute-fill" layout="'+layoutType+'">';
+ if ($scope.legendConfig.position === types.position.top.value ||
+ $scope.legendConfig.position === types.position.left.value) {
+ html += legendHtml;
+ html += containerHtml;
+ } else {
+ html += containerHtml;
+ html += legendHtml;
+ }
+ html += '</div>';
+ } else {
+ html += containerHtml;
+ }
+
+ //TODO:
+ /*if (progressElement) {
+ progressScope.$destroy();
+ progressScope = null;
+
+ progressElement.remove();
+ progressElement = null;
+ }*/
+
+ $element.html(html);
+
+ var containerElement = $scope.displayLegend ? angular.element($element[0].querySelector('#widget-container')) : $element;
+ widgetContext.$container = $('#container', containerElement);
+ widgetContext.$containerParent = $(containerElement);
+
+ $compile($element.contents())($scope);
+
+ addResizeListener(widgetContext.$containerParent[0], onResize); // eslint-disable-line no-undef
+ }
+
+ function destroyWidgetElement() {
+ removeResizeListener(widgetContext.$containerParent[0], onResize); // eslint-disable-line no-undef
+ $element.html('');
+ widgetContext.$container = null;
+ widgetContext.$containerParent = null;
+ }
function initialize() {
@@ -407,8 +454,6 @@ export default function WidgetController($scope, $timeout, $window, $element, $q
onEditModeChanged(isEdit);
});
- addResizeListener(widgetContext.$containerParent[0], onResize); // eslint-disable-line no-undef
-
$scope.$watch(function () {
return widget.row + ',' + widget.col + ',' + widget.config.mobileOrder;
}, function () {
@@ -439,10 +484,10 @@ export default function WidgetController($scope, $timeout, $window, $element, $q
});
$scope.$on("$destroy", function () {
- removeResizeListener(widgetContext.$containerParent[0], onResize); // eslint-disable-line no-undef
onDestroy();
});
+ configureWidgetElement();
var deferred = $q.defer();
if (!vm.useCustomDatasources) {
createDefaultSubscription().then(
@@ -465,6 +510,7 @@ export default function WidgetController($scope, $timeout, $window, $element, $q
function reInit() {
onDestroy();
+ configureWidgetElement();
if (!vm.useCustomDatasources) {
createDefaultSubscription().then(
function success() {
@@ -636,6 +682,7 @@ export default function WidgetController($scope, $timeout, $window, $element, $q
handleWidgetException(e);
}
}
+ destroyWidgetElement();
}
//TODO: widgets visibility
ui/src/app/components/widget.directive.js 85(+2 -83)
diff --git a/ui/src/app/components/widget.directive.js b/ui/src/app/components/widget.directive.js
index c92e544..a0f1b83 100644
--- a/ui/src/app/components/widget.directive.js
+++ b/ui/src/app/components/widget.directive.js
@@ -28,7 +28,7 @@ export default angular.module('thingsboard.directives.widget', [thingsboardLegen
.name;
/*@ngInject*/
-function Widget($controller, $compile, types, widgetService) {
+function Widget($controller, widgetService) {
return {
scope: true,
link: function (scope, elem, attrs) {
@@ -81,90 +81,9 @@ function Widget($controller, $compile, types, widgetService) {
elem.addClass(widgetNamespace);
- var html = '<div class="tb-absolute-fill tb-widget-error" ng-if="widgetErrorData">' +
- '<span>Widget Error: {{ widgetErrorData.name + ": " + widgetErrorData.message}}</span>' +
- '</div>' +
- '<div class="tb-absolute-fill tb-widget-loading" ng-show="loadingData" layout="column" layout-align="center center">' +
- '<md-progress-circular md-mode="indeterminate" ng-disabled="!loadingData" class="md-accent" md-diameter="40"></md-progress-circular>' +
- '</div>';
-
- scope.displayLegend = angular.isDefined(widget.config.showLegend) ?
- widget.config.showLegend : widget.type === types.widgetType.timeseries.value;
-
-
- var containerHtml = '<div id="container">' + widgetInfo.templateHtml + '</div>';
- if (scope.displayLegend) {
- scope.legendConfig = widget.config.legendConfig ||
- {
- position: types.position.bottom.value,
- showMin: false,
- showMax: false,
- showAvg: widget.type === types.widgetType.timeseries.value,
- showTotal: false
- };
- scope.legendData = {
- keys: [],
- data: []
- };
-
- var layoutType;
- if (scope.legendConfig.position === types.position.top.value ||
- scope.legendConfig.position === types.position.bottom.value) {
- layoutType = 'column';
- } else {
- layoutType = 'row';
- }
-
- var legendStyle;
- switch(scope.legendConfig.position) {
- case types.position.top.value:
- legendStyle = 'padding-bottom: 8px;';
- break;
- case types.position.bottom.value:
- legendStyle = 'padding-top: 8px;';
- break;
- case types.position.left.value:
- legendStyle = 'padding-right: 0px;';
- break;
- case types.position.right.value:
- legendStyle = 'padding-left: 0px;';
- break;
- }
-
- var legendHtml = '<tb-legend style="'+legendStyle+'" legend-config="legendConfig" legend-data="legendData"></tb-legend>';
- containerHtml = '<div flex id="widget-container">' + containerHtml + '</div>';
- html += '<div class="tb-absolute-fill" layout="'+layoutType+'">';
- if (scope.legendConfig.position === types.position.top.value ||
- scope.legendConfig.position === types.position.left.value) {
- html += legendHtml;
- html += containerHtml;
- } else {
- html += containerHtml;
- html += legendHtml;
- }
- html += '</div>';
- } else {
- html += containerHtml;
- }
-
- //TODO:
- /*if (progressElement) {
- progressScope.$destroy();
- progressScope = null;
-
- progressElement.remove();
- progressElement = null;
- }*/
-
- elem.html(html);
-
- var containerElement = scope.displayLegend ? angular.element(elem[0].querySelector('#widget-container')) : elem;
-
- $compile(elem.contents())(scope);
-
var widgetType = widgetService.getWidgetTypeFunction(widget.bundleAlias, widget.typeAlias, widget.isSystemType);
- angular.extend(locals, {$scope: scope, $element: containerElement, widgetType: widgetType});
+ angular.extend(locals, {$scope: scope, $element: elem, widgetInfo: widgetInfo, widgetType: widgetType});
widgetController = $controller('WidgetController', locals);
diff --git a/ui/src/app/entity/aliases-entity-select.directive.js b/ui/src/app/entity/aliases-entity-select.directive.js
index 7e174ef..9a61311 100644
--- a/ui/src/app/entity/aliases-entity-select.directive.js
+++ b/ui/src/app/entity/aliases-entity-select.directive.js
@@ -94,6 +94,14 @@ export default function AliasesEntitySelectDirective($compile, $templateCache, $
$mdPanel.open(config);
}
+ scope.$on('entityAliasesChanged', function() {
+ scope.updateView();
+ });
+
+ scope.$on('entityAliasResolved', function() {
+ scope.updateView();
+ });
+
scope.updateView = function () {
updateDisplayValue();
}
diff --git a/ui/src/app/entity/aliases-entity-select-panel.controller.js b/ui/src/app/entity/aliases-entity-select-panel.controller.js
index 8439269..5365db7 100644
--- a/ui/src/app/entity/aliases-entity-select-panel.controller.js
+++ b/ui/src/app/entity/aliases-entity-select-panel.controller.js
@@ -15,7 +15,7 @@
*/
/*@ngInject*/
-export default function AliasesEntitySelectPanelController(mdPanelRef, $scope, types, aliasController, onEntityAliasesUpdate) {
+export default function AliasesEntitySelectPanelController(mdPanelRef, $scope, $filter, types, aliasController, onEntityAliasesUpdate) {
var vm = this;
vm._mdPanelRef = mdPanelRef;
@@ -31,13 +31,18 @@ export default function AliasesEntitySelectPanelController(mdPanelRef, $scope, t
var aliasInfo = vm.aliasController.getInstantAliasInfo(aliasId);
if (aliasInfo && !aliasInfo.resolveMultiple && aliasInfo.currentEntity) {
vm.entityAliasesInfo[aliasId] = angular.copy(aliasInfo);
+ vm.entityAliasesInfo[aliasId].selectedId = aliasInfo.currentEntity.id;
}
}
- function currentAliasEntityChanged(aliasId, currentEntity) {
- vm.aliasController.updateCurrentAliasEntity(aliasId, currentEntity);
- if (onEntityAliasesUpdate) {
- onEntityAliasesUpdate();
+ function currentAliasEntityChanged(aliasId, selectedId) {
+ var resolvedEntities = vm.entityAliasesInfo[aliasId].resolvedEntities;
+ var selected = $filter('filter')(resolvedEntities, {id: selectedId});
+ if (selected && selected.length) {
+ vm.aliasController.updateCurrentAliasEntity(aliasId, selected[0]);
+ if (onEntityAliasesUpdate) {
+ onEntityAliasesUpdate();
+ }
}
}
diff --git a/ui/src/app/entity/aliases-entity-select-panel.tpl.html b/ui/src/app/entity/aliases-entity-select-panel.tpl.html
index edc8e5a..d197d0b 100644
--- a/ui/src/app/entity/aliases-entity-select-panel.tpl.html
+++ b/ui/src/app/entity/aliases-entity-select-panel.tpl.html
@@ -21,8 +21,8 @@
<div flex layout="row" ng-repeat="(aliasId, entityAliasInfo) in vm.entityAliasesInfo">
<md-input-container flex>
<label>{{entityAliasInfo.alias}}</label>
- <md-select ng-model="entityAliasInfo.currentEntity" ng-change="vm.currentAliasEntityChanged(aliasId, entityAliasInfo.currentEntity)">
- <md-option ng-repeat="resolvedEntity in entityAliasInfo.resolvedEntities" ng-value="resolvedEntity">
+ <md-select ng-model="entityAliasInfo.selectedId" ng-change="vm.currentAliasEntityChanged(aliasId, entityAliasInfo.selectedId)">
+ <md-option ng-repeat="resolvedEntity in entityAliasInfo.resolvedEntities" ng-value="resolvedEntity.id">
{{resolvedEntity.name}}
</md-option>
</md-select>
diff --git a/ui/src/app/entity/attribute/add-widget-to-dashboard-dialog.controller.js b/ui/src/app/entity/attribute/add-widget-to-dashboard-dialog.controller.js
index b28a46b..bcf37dd 100644
--- a/ui/src/app/entity/attribute/add-widget-to-dashboard-dialog.controller.js
+++ b/ui/src/app/entity/attribute/add-widget-to-dashboard-dialog.controller.js
@@ -22,7 +22,7 @@ import selectTargetLayoutTemplate from '../../dashboard/layouts/select-target-la
/* eslint-enable import/no-unresolved, import/default */
/*@ngInject*/
-export default function AddWidgetToDashboardDialogController($scope, $mdDialog, $state, $q, $document,
+export default function AddWidgetToDashboardDialogController($scope, $mdDialog, $state, $q, $document, dashboardUtils,
types, itembuffer, dashboardService, entityId, entityType, entityName, widget) {
var vm = this;
@@ -126,15 +126,8 @@ export default function AddWidgetToDashboardDialogController($scope, $mdDialog,
targetDeviceAliases: {}
};
aliasesInfo.datasourceAliases[0] = {
- id: 1,
alias: entityName,
- filter: {
- type: types.aliasFilterType.entityList.value,
- stateEntity: false,
- entityList: [entityId],
- entityType: entityType,
- resolveMultiple: false
- }
+ filter: dashboardUtils.createSingleEntityFilter(entityType, entityId)
};
itembuffer.addWidgetToDashboard(theDashboard, targetState, targetLayout, vm.widget, aliasesInfo, null, 48, null, -1, -1).then(
function(theDashboard) {
diff --git a/ui/src/app/entity/attribute/attribute-table.directive.js b/ui/src/app/entity/attribute/attribute-table.directive.js
index da7697d..62d2081 100644
--- a/ui/src/app/entity/attribute/attribute-table.directive.js
+++ b/ui/src/app/entity/attribute/attribute-table.directive.js
@@ -26,10 +26,12 @@ import editAttributeValueTemplate from './edit-attribute-value.tpl.html';
/* eslint-enable import/no-unresolved, import/default */
import EditAttributeValueController from './edit-attribute-value.controller';
+import AliasController from '../../api/alias-controller';
/*@ngInject*/
export default function AttributeTableDirective($compile, $templateCache, $rootScope, $q, $mdEditDialog, $mdDialog,
- $document, $translate, $filter, utils, types, dashboardService, attributeService, widgetService) {
+ $mdUtil, $document, $translate, $filter, utils, types, dashboardUtils,
+ dashboardService, entityService, attributeService, widgetService) {
var linker = function (scope, element, attrs) {
@@ -246,15 +248,19 @@ export default function AttributeTableDirective($compile, $templateCache, $rootS
}
scope.nextWidget = function() {
- if (scope.widgetsCarousel.index < scope.widgetsList.length-1) {
- scope.widgetsCarousel.index++;
- }
+ $mdUtil.nextTick(function () {
+ if (scope.widgetsCarousel.index < scope.widgetsList.length - 1) {
+ scope.widgetsCarousel.index++;
+ }
+ });
}
scope.prevWidget = function() {
- if (scope.widgetsCarousel.index > 0) {
- scope.widgetsCarousel.index--;
- }
+ $mdUtil.nextTick(function () {
+ if (scope.widgetsCarousel.index > 0) {
+ scope.widgetsCarousel.index--;
+ }
+ });
}
scope.enterWidgetMode = function() {
@@ -281,23 +287,28 @@ export default function AttributeTableDirective($compile, $templateCache, $rootS
scope.firstBundle = true;
scope.selectedWidgetsBundleAlias = types.systemBundleAlias.cards;
- scope.aliasesInfo = {
- entityAliases: {
- '1': {alias: scope.entityName, entityType: scope.entityType, entityId: scope.entityId}
- },
- entityAliasesInfo: {
- '1': [
- {name: scope.entityName, entityType: scope.entityType, id: scope.entityId}
- ]
+ var entityAlias = {
+ id: utils.guid(),
+ alias: scope.entityName,
+ filter: dashboardUtils.createSingleEntityFilter(scope.entityType, scope.entityId)
+ };
+ var entitiAliases = {};
+ entitiAliases[entityAlias.id] = entityAlias;
+
+ var stateController = {
+ getStateParams: function() {
+ return {};
}
};
+ scope.aliasController = new AliasController(scope, $q, $filter, utils,
+ types, entityService, stateController, entitiAliases);
var dataKeyType = scope.attributeScope === types.latestTelemetry ?
types.dataKeyType.timeseries : types.dataKeyType.attribute;
var datasource = {
type: types.datasourceType.entity,
- entityAliasId: '1',
+ entityAliasId: entityAlias.id,
dataKeys: []
}
var i = 0;
diff --git a/ui/src/app/entity/attribute/attribute-table.tpl.html b/ui/src/app/entity/attribute/attribute-table.tpl.html
index 1afd1bb..2566a08 100644
--- a/ui/src/app/entity/attribute/attribute-table.tpl.html
+++ b/ui/src/app/entity/attribute/attribute-table.tpl.html
@@ -156,7 +156,7 @@
rn-swipe-disabled="true">
<li ng-repeat="widgets in widgetsList">
<tb-dashboard
- aliases-info="aliasesInfo"
+ alias-controller="aliasController"
widgets="widgets"
get-st-diff="getServerTimeDiff()"
columns="20"
diff --git a/ui/src/app/entity/entity-aliases.controller.js b/ui/src/app/entity/entity-aliases.controller.js
index 088f8b9..50bbfd9 100644
--- a/ui/src/app/entity/entity-aliases.controller.js
+++ b/ui/src/app/entity/entity-aliases.controller.js
@@ -113,12 +113,7 @@ export default function EntityAliasesController(utils, entityService, toast, $sc
}
function addAlias() {
- var aliasId = 0;
- for (var a in vm.entityAliases) {
- aliasId = Math.max(vm.entityAliases[a].id, aliasId);
- }
- aliasId++;
- var entityAlias = {id: aliasId, alias: '', filter: {}, changed: false};
+ var entityAlias = {id: utils.guid(), alias: '', filter: {}, changed: false};
vm.entityAliases.push(entityAlias);
}
@@ -162,23 +157,21 @@ export default function EntityAliasesController(utils, entityService, toast, $sc
var uniqueAliasList = {};
var valid = true;
- var aliasId, maxAliasId;
+ var aliasId;
var alias;
var i;
if (vm.isSingleEntityAlias) {
- maxAliasId = 0;
+ if (!vm.singleEntityAlias.id) {
+ vm.singleEntityAlias.id = utils.guid();
+ }
for (i = 0; i < vm.entityAliases.length; i ++) {
- aliasId = vm.entityAliases[i].id;
alias = vm.entityAliases[i].alias;
if (alias === vm.singleEntityAlias.alias) {
valid = false;
break;
}
- maxAliasId = Math.max(aliasId, maxAliasId);
}
- maxAliasId++;
- vm.singleEntityAlias.id = maxAliasId;
} else {
for (i = 0; i < vm.entityAliases.length; i++) {
aliasId = vm.entityAliases[i].id;
ui/src/app/entity/entity-aliases.scss 15(+12 -3)
diff --git a/ui/src/app/entity/entity-aliases.scss b/ui/src/app/entity/entity-aliases.scss
index b108dc0..4180bce 100644
--- a/ui/src/app/entity/entity-aliases.scss
+++ b/ui/src/app/entity/entity-aliases.scss
@@ -18,11 +18,20 @@
.md-dialog-content {
padding-bottom: 0px;
}
+ .tb-aliases-header {
+ min-height: 40px;
+ padding: 0 34px 0 34px;
+ margin: 5px;
+ .tb-header-label {
+ font-size: 14px;
+ color: rgba(0, 0, 0, 0.570588);
+ }
+ }
.tb-alias {
- padding: 10px 0 0 10px;
+ padding: 0 0 0 10px;
margin: 5px;
- md-select.tb-entity-type-select {
- padding-bottom: 24px;
+ md-input-container {
+ margin: 0px;
}
}
}
ui/src/app/entity/entity-aliases.tpl.html 56(+30 -26)
diff --git a/ui/src/app/entity/entity-aliases.tpl.html b/ui/src/app/entity/entity-aliases.tpl.html
index ef8b032..4fd33d9 100644
--- a/ui/src/app/entity/entity-aliases.tpl.html
+++ b/ui/src/app/entity/entity-aliases.tpl.html
@@ -28,23 +28,28 @@
</md-toolbar>
<md-progress-linear class="md-warn" md-mode="indeterminate" ng-disabled="!loading" ng-show="loading"></md-progress-linear>
<span style="min-height: 5px;" flex="" ng-show="!loading"></span>
+ <div class="tb-aliases-header" ng-show="!vm.isSingleEntityAlias" flex layout="row" layout-align="start center">
+ <span flex="5"></span>
+ <div flex layout="row" layout-align="start center">
+ <span class="tb-header-label" translate flex="20" style="min-width: 150px;">entity.alias</span>
+ <div flex="80" layout="row" layout-align="start center" style="min-width: 240px; padding-left: 10px;">
+ <span class="tb-header-label" translate flex="70">alias.entity-filter</span>
+ <span class="tb-header-label" translate flex="30" style="padding-left: 10px;" >alias.resolve-multiple</span>
+ </div>
+ <span style="min-width: 40px; margin: 0 6px;"></span>
+ </div>
+ </div>
+ <md-divider ng-show="!vm.isSingleEntityAlias"></md-divider>
<md-dialog-content>
<div class="md-dialog-content">
<fieldset ng-disabled="loading">
<div ng-show="vm.isSingleEntityAlias" layout="row">
- <tb-entity-filter flex allowed-entity-types="vm.allowedEntityTypes" ng-model="vm.singleEntityAlias.filter">
+ <tb-entity-filter flex
+ allowed-entity-types="vm.allowedEntityTypes"
+ ng-model="vm.singleEntityAlias.filter">
</tb-entity-filter>
</div>
- <div ng-show="!vm.isSingleEntityAlias" flex layout="row" layout-align="start center">
- <span flex="5"></span>
- <div flex layout="row" layout-align="start center"
- style="padding: 0 0 0 10px; margin: 5px;">
- <span translate flex="20" style="min-width: 150px;">entity.alias</span>
- <span translate flex="80" style="min-width: 240px; padding-left: 10px;">alias.entity-filter</span>
- <span style="min-width: 40px;"></span>
- </div>
- </div>
- <div ng-show="!vm.isSingleEntityAlias" style="max-height: 500px; overflow: auto; padding-bottom: 20px;">
+ <div ng-show="!vm.isSingleEntityAlias" style="height: 100%; overflow: auto; padding-bottom: 20px;">
<div ng-form name="aliasForm" flex layout="row" layout-align="start center" ng-repeat="entityAlias in vm.entityAliases track by $index">
<span flex="5">{{$index + 1}}.</span>
<div class="md-whiteframe-4dp tb-alias" flex layout="row" layout-align="start center">
@@ -54,13 +59,12 @@
<div translate ng-message="required">entity.alias-required</div>
</div>
</md-input-container>
- <section flex="80" layout="column">
- <tb-entity-filter style="padding-left: 10px;"
- allowed-entity-types="vm.allowedEntityTypes"
- ng-model="entityAlias.filter"
- on-matching-entity-change="vm.onFilterEntityChanged(entity, stateEntity, entityAlias)">
- </tb-entity-filter>
- </section>
+ <tb-entity-filter flex="80" style="min-width: 240px; padding-left: 10px;"
+ hide-labels
+ allowed-entity-types="vm.allowedEntityTypes"
+ ng-model="entityAlias.filter"
+ on-matching-entity-change="vm.onFilterEntityChanged(entity, stateEntity, entityAlias)">
+ </tb-entity-filter>
<md-button ng-disabled="loading" class="md-icon-button md-primary" style="min-width: 40px;"
ng-click="vm.removeAlias($event, entityAlias)" aria-label="{{ 'action.remove' | translate }}">
<md-tooltip md-direction="top">
@@ -73,18 +77,18 @@
</div>
</div>
</div>
- <div ng-show="!vm.isSingleEntityAlias && !vm.disableAdd" style="padding-bottom: 10px;">
- <md-button ng-disabled="loading" class="md-primary md-raised" ng-click="vm.addAlias($event)" aria-label="{{ 'action.add' | translate }}">
- <md-tooltip md-direction="top">
- {{ 'entity.add-alias' | translate }}
- </md-tooltip>
- <span translate>action.add</span>
- </md-button>
- </div>
</fieldset>
</div>
</md-dialog-content>
<md-dialog-actions layout="row">
+ <md-button ng-show="!vm.isSingleEntityAlias && !vm.disableAdd" ng-disabled="loading" class="md-primary md-raised"
+ ng-click="vm.addAlias($event)"
+ aria-label="{{ 'action.add' | translate }}">
+ <md-tooltip md-direction="top">
+ {{ 'entity.add-alias' | translate }}
+ </md-tooltip>
+ <span translate>action.add</span>
+ </md-button>
<span flex></span>
<md-button ng-disabled="loading || theForm.$invalid || !theForm.$dirty" type="submit" class="md-raised md-primary">
{{ 'action.save' | translate }}
ui/src/app/entity/entity-filter.directive.js 163(+1 -162)
diff --git a/ui/src/app/entity/entity-filter.directive.js b/ui/src/app/entity/entity-filter.directive.js
index beded8a..0f9cf5c 100644
--- a/ui/src/app/entity/entity-filter.directive.js
+++ b/ui/src/app/entity/entity-filter.directive.js
@@ -35,46 +35,16 @@ export default function EntityFilterDirective($compile, $templateCache, $q, $doc
scope.ngModelCtrl = ngModelCtrl;
scope.types = types;
-
- /* scope.fetchEntities = function(searchText, limit) {
- var deferred = $q.defer();
- entityService.getEntitiesByNameFilter(scope.entityType, searchText, limit).then(function success(result) {
- if (result) {
- deferred.resolve(result);
- } else {
- deferred.resolve([]);
- }
- }, function fail() {
- deferred.reject();
- });
- return deferred.promise;
- }*/
+ scope.hideLabels = angular.isDefined(attrs.hideLabels);
scope.updateValidity = function() {
if (ngModelCtrl.$viewValue) {
var value = ngModelCtrl.$viewValue;
ngModelCtrl.$setValidity('filter', value.type ? true : false);
- /*if (value.useFilter) {
- ngModelCtrl.$setValidity('entityList', true);
- if (angular.isDefined(value.entityNameFilter) && value.entityNameFilter.length > 0) {
- ngModelCtrl.$setValidity('entityNameFilter', true);
- valid = angular.isDefined(scope.model.matchingFilterEntity) && scope.model.matchingFilterEntity != null;
- ngModelCtrl.$setValidity('entityNameFilterEntityMatch', valid);
- } else {
- ngModelCtrl.$setValidity('entityNameFilter', false);
- }
- } else {
- ngModelCtrl.$setValidity('entityNameFilter', true);
- ngModelCtrl.$setValidity('entityNameFilterDeviceMatch', true);
- valid = angular.isDefined(value.entityList) && value.entityList.length > 0;
- ngModelCtrl.$setValidity('entityList', valid);
- }*/
-
}
}
ngModelCtrl.$render = function () {
- //destroyWatchers();
if (ngModelCtrl.$viewValue) {
scope.model = angular.copy(ngModelCtrl.$viewValue);
} else {
@@ -83,28 +53,6 @@ export default function EntityFilterDirective($compile, $templateCache, $q, $doc
resolveMultiple: false
}
}
- /* if (ngModelCtrl.$viewValue) {
- var value = ngModelCtrl.$viewValue;
- var model = scope.model;
- model.useFilter = value.useFilter === true ? true: false;
- model.entityList = [];
- model.entityNameFilter = value.entityNameFilter || '';
- processEntityNameFilter(model.entityNameFilter).then(
- function(entity) {
- scope.model.matchingFilterEntity = entity;
- if (value.entityList && value.entityList.length > 0) {
- entityService.getEntities(scope.entityType, value.entityList).then(function (entities) {
- model.entityList = entities;
- updateMatchingEntity();
- initWatchers();
- });
- } else {
- updateMatchingEntity();
- initWatchers();
- }
- }
- )
- }*/
}
scope.$watch('model.resolveMultiple', function () {
@@ -149,115 +97,6 @@ export default function EntityFilterDirective($compile, $templateCache, $q, $doc
});
}
- /* function updateMatchingEntity() {
- if (scope.model.useFilter) {
- scope.model.matchingEntity = scope.model.matchingFilterEntity;
- } else {
- if (scope.model.entityList && scope.model.entityList.length > 0) {
- scope.model.matchingEntity = scope.model.entityList[0];
- } else {
- scope.model.matchingEntity = null;
- }
- }
- }
-
- function processEntityNameFilter(entityNameFilter) {
- var deferred = $q.defer();
- if (angular.isDefined(entityNameFilter) && entityNameFilter.length > 0) {
- scope.fetchEntities(entityNameFilter, 1).then(function (entities) {
- if (entities && entities.length > 0) {
- deferred.resolve(entities[0]);
- } else {
- deferred.resolve(null);
- }
- });
- } else {
- deferred.resolve(null);
- }
- return deferred.promise;
- }
-
- function destroyWatchers() {
- if (scope.entityTypeDeregistration) {
- scope.entityTypeDeregistration();
- scope.entityTypeDeregistration = null;
- }
- if (scope.entityListDeregistration) {
- scope.entityListDeregistration();
- scope.entityListDeregistration = null;
- }
- if (scope.useFilterDeregistration) {
- scope.useFilterDeregistration();
- scope.useFilterDeregistration = null;
- }
- if (scope.entityNameFilterDeregistration) {
- scope.entityNameFilterDeregistration();
- scope.entityNameFilterDeregistration = null;
- }
- if (scope.matchingEntityDeregistration) {
- scope.matchingEntityDeregistration();
- scope.matchingEntityDeregistration = null;
- }
- }
-
- function initWatchers() {
-
- scope.entityTypeDeregistration = scope.$watch('entityType', function (newEntityType, prevEntityType) {
- if (!angular.equals(newEntityType, prevEntityType)) {
- scope.model.entityList = [];
- scope.model.entityNameFilter = '';
- }
- });
-
- scope.entityListDeregistration = scope.$watch('model.entityList', function () {
- if (ngModelCtrl.$viewValue) {
- var value = ngModelCtrl.$viewValue;
- value.entityList = [];
- if (scope.model.entityList && scope.model.entityList.length > 0) {
- for (var i=0;i<scope.model.entityList.length;i++) {
- value.entityList.push(scope.model.entityList[i].id.id);
- }
- }
- updateMatchingEntity();
- ngModelCtrl.$setViewValue(value);
- scope.updateValidity();
- }
- }, true);
- scope.useFilterDeregistration = scope.$watch('model.useFilter', function () {
- if (ngModelCtrl.$viewValue) {
- var value = ngModelCtrl.$viewValue;
- value.useFilter = scope.model.useFilter;
- updateMatchingEntity();
- ngModelCtrl.$setViewValue(value);
- scope.updateValidity();
- }
- });
- scope.entityNameFilterDeregistration = scope.$watch('model.entityNameFilter', function (newNameFilter, prevNameFilter) {
- if (ngModelCtrl.$viewValue) {
- if (!angular.equals(newNameFilter, prevNameFilter)) {
- var value = ngModelCtrl.$viewValue;
- value.entityNameFilter = scope.model.entityNameFilter;
- processEntityNameFilter(value.entityNameFilter).then(
- function(entity) {
- scope.model.matchingFilterEntity = entity;
- updateMatchingEntity();
- ngModelCtrl.$setViewValue(value);
- scope.updateValidity();
- }
- );
- }
- }
- });
-
- scope.matchingEntityDeregistration = scope.$watch('model.matchingEntity', function (newMatchingEntity, prevMatchingEntity) {
- if (!angular.equals(newMatchingEntity, prevMatchingEntity)) {
- if (scope.onMatchingEntityChange) {
- scope.onMatchingEntityChange({entity: newMatchingEntity});
- }
- }
- });
- }*/
-
$compile(element.contents())(scope);
}
ui/src/app/entity/entity-filter.scss 15(+2 -13)
diff --git a/ui/src/app/entity/entity-filter.scss b/ui/src/app/entity/entity-filter.scss
index 1525842..10ddcd3 100644
--- a/ui/src/app/entity/entity-filter.scss
+++ b/ui/src/app/entity/entity-filter.scss
@@ -14,18 +14,6 @@
* limitations under the License.
*/
.tb-entity-filter {
- #entity_list_chips {
- .md-chips {
- padding-bottom: 1px;
- }
- }
- .entity-name-filter-input {
- margin-top: 10px;
- margin-bottom: 0px;
- .md-errors-spacer {
- min-height: 0px;
- }
- }
.tb-filter-switch {
padding-left: 10px;
.filter-switch {
@@ -39,7 +27,8 @@
margin-top: -11px;
height: 35px;
.tb-error-message {
- padding-left: 1px;
+ padding-left: 8px;
+ padding-top: 14px;
}
}
}
\ No newline at end of file
ui/src/app/entity/entity-filter.tpl.html 101(+29 -72)
diff --git a/ui/src/app/entity/entity-filter.tpl.html b/ui/src/app/entity/entity-filter.tpl.html
index 9a5337a..6ce95fa 100644
--- a/ui/src/app/entity/entity-filter.tpl.html
+++ b/ui/src/app/entity/entity-filter.tpl.html
@@ -15,80 +15,37 @@
limitations under the License.
-->
-<section layout='column' class="tb-entity-filter">
- <section layout='row'>
- <!--section layout="column" flex ng-show="!model.useFilter">
- <md-chips flex
- id="entity_list_chips"
- ng-required="!useFilter"
- ng-model="model.entityList" md-autocomplete-snap
- md-require-match="true">
- <md-autocomplete
- md-no-cache="true"
- id="entity"
- md-selected-item="selectedEntity"
- md-search-text="entitySearchText"
- md-items="item in fetchEntities(entitySearchText, 10)"
- md-item-text="item.name"
- md-min-length="0"
- placeholder="{{ 'entity.entity-list' | translate }}">
- <md-item-template>
- <span md-highlight-text="entitySearchText" md-highlight-flags="^i">{{item.name}}</span>
- </md-item-template>
- <md-not-found>
- <span translate translate-values='{ entity: entitySearchText }'>entity.no-entities-matching</span>
- </md-not-found>
- </md-autocomplete>
- <md-chip-template>
- <span>
- <strong>{{$chip.name}}</strong>
- </span>
- </md-chip-template>
- </md-chips>
- </section>
- <section layout="row" flex ng-show="model.useFilter">
- <md-input-container flex class="entity-name-filter-input">
- <label translate>entity.name-starts-with</label>
- <input ng-model="model.entityNameFilter" aria-label="{{ 'entity.name-starts-with' | translate }}">
- </md-input-container>
- </section-->
- <section layout="row" flex layout-align="start center">
- <div flex ng-if="model.type">{{ types.aliasFilterType[model.type].name | translate }}</div>
- <md-button ng-if="model.type" ng-disabled="loading" class="md-icon-button md-primary"
- style="min-width: 40px;"
- ng-click="editFilter($event)"
- aria-label="{{ 'alias.edit-entity-filter' | translate }}">
- <md-tooltip md-direction="top">
- {{ 'alias.edit-entity-filter' | translate }}
- </md-tooltip>
- <md-icon aria-label="{{ 'alias.edit-entity-filter' | translate }}"
+<section layout='row' class="tb-entity-filter">
+ <section layout="row" flex="70">
+ <section flex layout="column" layout-align="center start">
+ <div ng-if="model.type">{{ types.aliasFilterType[model.type].name | translate }}</div>
+ <md-button ng-if="!model.type"
+ ng-disabled="loading" class="md-primary"
+ ng-click="createFilter($event)"
+ aria-label="{{ 'alias.create-entity-filter' | translate }}">
+ <md-icon aria-label="{{ 'alias.create-entity-filter' | translate }}"
class="material-icons">
- edit
+ add
</md-icon>
+ {{ 'alias.create-entity-filter' | translate }}
</md-button>
- <div ng-if="!model.type" layout="row" layout-align="center start">
- <md-button ng-disabled="loading" class="md-primary md-raised"
- ng-click="createFilter($event)"
- aria-label="{{ 'alias.create-entity-filter' | translate }}">
- <md-icon aria-label="{{ 'alias.create-entity-filter' | translate }}"
- class="material-icons">
- add
- </md-icon>
- {{ 'alias.create-entity-filter' | translate }}
- </md-button>
- </div>
- </section>
- <section class="tb-filter-switch" layout="column" layout-align="center center">
- <label class="tb-small filter-label" translate>alias.resolve-multiple</label>
- <md-switch class="filter-switch" ng-model="model.resolveMultiple" aria-label="resolve-multiple-switcher">
- </md-switch>
</section>
+ <md-button ng-if="model.type" ng-disabled="loading" class="md-icon-button md-primary"
+ style="min-width: 40px;"
+ ng-click="editFilter($event)"
+ aria-label="{{ 'alias.edit-entity-filter' | translate }}">
+ <md-tooltip md-direction="top">
+ {{ 'alias.edit-entity-filter' | translate }}
+ </md-tooltip>
+ <md-icon aria-label="{{ 'alias.edit-entity-filter' | translate }}"
+ class="material-icons">
+ edit
+ </md-icon>
+ </md-button>
+ </section>
+ <section class="tb-filter-switch" layout="column" flex="30" layout-align="center center">
+ <label ng-if="!hideLabels" class="tb-small filter-label" translate>alias.resolve-multiple</label>
+ <md-switch class="filter-switch" ng-model="model.resolveMultiple" aria-label="resolve-multiple-switcher">
+ </md-switch>
</section>
- <div class="tb-error-messages" ng-messages="ngModelCtrl.$error" role="alert">
- <div translate ng-message="filter" class="tb-error-message">alias.entity-filter-required</div>
- <!--div translate ng-message="entityList" class="tb-error-message">entity.entity-list-empty</div>
- <div translate ng-message="entityNameFilter" class="tb-error-message">entity.entity-name-filter-required</div>
- <div translate translate-values='{ entity: model.entityNameFilter }' ng-message="entityNameFilterEntityMatch"
- class="tb-error-message">entity.entity-name-filter-no-entity-matched</div-->
- </div>
-</section>
\ No newline at end of file
+</section>
diff --git a/ui/src/app/import-export/import-export.service.js b/ui/src/app/import-export/import-export.service.js
index 7f7f774..9b36c38 100644
--- a/ui/src/app/import-export/import-export.service.js
+++ b/ui/src/app/import-export/import-export.service.js
@@ -24,7 +24,7 @@ import entityAliasesTemplate from '../entity/entity-aliases.tpl.html';
/* eslint-disable no-undef, angular/window-service, angular/document-service */
/*@ngInject*/
-export default function ImportExport($log, $translate, $q, $mdDialog, $document, itembuffer, types, dashboardUtils,
+export default function ImportExport($log, $translate, $q, $mdDialog, $document, itembuffer, utils, types, dashboardUtils,
entityService, dashboardService, pluginService, ruleService, widgetService, toast) {
@@ -415,6 +415,7 @@ export default function ImportExport($log, $translate, $q, $mdDialog, $document,
deferred.reject();
} else {
var widget = widgetItem.widget;
+ widget = dashboardUtils.validateAndUpdateWidget(widget);
var aliasesInfo = prepareAliasesInfo(widgetItem.aliasesInfo);
var originalColumns = widgetItem.originalColumns;
var originalSize = widgetItem.originalSize;
@@ -425,22 +426,22 @@ export default function ImportExport($log, $translate, $q, $mdDialog, $document,
var entityAliases = {};
var datasourceAliasesMap = {};
var targetDeviceAliasesMap = {};
- var aliasId = 1;
+ var aliasId;
var datasourceIndex;
if (datasourceAliases) {
for (datasourceIndex in datasourceAliases) {
+ aliasId = utils.guid();
datasourceAliasesMap[aliasId] = datasourceIndex;
entityAliases[aliasId] = datasourceAliases[datasourceIndex];
entityAliases[aliasId].id = aliasId;
- aliasId++;
}
}
if (targetDeviceAliases) {
for (datasourceIndex in targetDeviceAliases) {
+ aliasId = utils.guid();
targetDeviceAliasesMap[aliasId] = datasourceIndex;
entityAliases[aliasId] = targetDeviceAliases[datasourceIndex];
entityAliases[aliasId].id = aliasId;
- aliasId++;
}
}
ui/src/app/locale/locale.constant.js 2(+1 -1)
diff --git a/ui/src/app/locale/locale.constant.js b/ui/src/app/locale/locale.constant.js
index 84c7097..9c6695b 100644
--- a/ui/src/app/locale/locale.constant.js
+++ b/ui/src/app/locale/locale.constant.js
@@ -124,7 +124,7 @@ export default angular.module('thingsboard.locale', [])
"create-entity-filter": "Create entity filter",
"edit-entity-filter": "Edit entity filter",
"entity-filter-required": "Entity filter is required.",
- "resolve-multiple": "Multiple",
+ "resolve-multiple": "Resolve as multiple entities",
"filter-type": "Filter type",
"filter-type-required": "Filter type is required.",
"use-state-entity": "Use state entity",
diff --git a/ui/src/app/services/item-buffer.service.js b/ui/src/app/services/item-buffer.service.js
index 309e53e..d29ad18 100644
--- a/ui/src/app/services/item-buffer.service.js
+++ b/ui/src/app/services/item-buffer.service.js
@@ -298,11 +298,7 @@ function ItemBuffer($q, bufferStore, types, utils, dashboardUtils) {
}
if (!newAliasId) {
var newAliasName = createEntityAliasName(entityAliases, aliasInfo.alias);
- newAliasId = 0;
- for (aliasId in entityAliases) {
- newAliasId = Math.max(newAliasId, aliasId);
- }
- newAliasId++;
+ newAliasId = utils.guid();
entityAliases[newAliasId] = {id: newAliasId, alias: newAliasName, filter: aliasInfo.filter};
}
return newAliasId;