Commit 43b23cef4feb81697eb7807670b9ad5adb2edd0f

Authored by Igor Kulikov
1 parent 0a82a830

TB-61: Improve Alias list editor.

@@ -100,6 +100,7 @@ export default class AliasController { @@ -100,6 +100,7 @@ export default class AliasController {
100 aliasCtrl.resolvedAliasesToStateEntities[aliasId] = 100 aliasCtrl.resolvedAliasesToStateEntities[aliasId] =
101 aliasCtrl.stateController.getStateParams().entityId; 101 aliasCtrl.stateController.getStateParams().entityId;
102 } 102 }
  103 + aliasCtrl.$scope.$broadcast('entityAliasResolved', aliasId);
103 deferred.resolve(aliasInfo); 104 deferred.resolve(aliasInfo);
104 }, 105 },
105 function fail() { 106 function fail() {
@@ -239,6 +240,9 @@ export default class AliasController { @@ -239,6 +240,9 @@ export default class AliasController {
239 datasource.name = name; 240 datasource.name = name;
240 datasource.aliasName = name; 241 datasource.aliasName = name;
241 datasource.entityName = name; 242 datasource.entityName = name;
  243 + } else if (datasource.unresolvedStateEntity) {
  244 + datasource.name = "Unresolved";
  245 + datasource.entityName = "Unresolved";
242 } 246 }
243 datasource.dataKeys.forEach(function(dataKey) { 247 datasource.dataKeys.forEach(function(dataKey) {
244 if (datasource.generated) { 248 if (datasource.generated) {
@@ -73,6 +73,15 @@ export default class Subscription { @@ -73,6 +73,15 @@ export default class Subscription {
73 73
74 this.datasources = this.ctx.utils.validateDatasources(options.datasources); 74 this.datasources = this.ctx.utils.validateDatasources(options.datasources);
75 this.datasourceListeners = []; 75 this.datasourceListeners = [];
  76 +
  77 + /*
  78 + * data = array of datasourceData
  79 + * datasourceData = {
  80 + * tbDatasource,
  81 + * dataKey, { name, config }
  82 + * data = array of [time, value]
  83 + * }
  84 + */
76 this.data = []; 85 this.data = [];
77 this.hiddenData = []; 86 this.hiddenData = [];
78 this.originalTimewindow = null; 87 this.originalTimewindow = null;
@@ -543,39 +552,6 @@ export default class Subscription { @@ -543,39 +552,6 @@ export default class Subscription {
543 var datasource = this.datasources[i]; 552 var datasource = this.datasources[i];
544 if (angular.isFunction(datasource)) 553 if (angular.isFunction(datasource))
545 continue; 554 continue;
546 - /* var entityId = null;  
547 - var entityType = null;  
548 - if (datasource.type === this.ctx.types.datasourceType.entity) {  
549 - var aliasName = null;  
550 - var entityName = null;  
551 - if (datasource.entityId) {  
552 - entityId = datasource.entityId;  
553 - entityType = datasource.entityType;  
554 - datasource.name = datasource.entityName;  
555 - aliasName = datasource.entityName;  
556 - entityName = datasource.entityName;  
557 - } else if (datasource.entityAliasId) {  
558 - if (this.ctx.aliasesInfo.entityAliases[datasource.entityAliasId]) {  
559 - entityId = this.ctx.aliasesInfo.entityAliases[datasource.entityAliasId].entityId;  
560 - entityType = this.ctx.aliasesInfo.entityAliases[datasource.entityAliasId].entityType;  
561 - datasource.name = this.ctx.aliasesInfo.entityAliases[datasource.entityAliasId].alias;  
562 - aliasName = this.ctx.aliasesInfo.entityAliases[datasource.entityAliasId].alias;  
563 - entityName = '';  
564 - var entitiesInfo = this.ctx.aliasesInfo.entityAliasesInfo[datasource.entityAliasId];  
565 - for (var d = 0; d < entitiesInfo.length; d++) {  
566 - if (entitiesInfo[d].id === entityId) {  
567 - entityName = entitiesInfo[d].name;  
568 - break;  
569 - }  
570 - }  
571 - }  
572 - }  
573 - } else {  
574 - datasource.name = datasource.name || this.ctx.types.datasourceType.function;  
575 - }  
576 - for (var dk = 0; dk < datasource.dataKeys.length; dk++) {  
577 - updateDataKeyLabel(datasource.dataKeys[dk], datasource.name, entityName, aliasName);  
578 - }*/  
579 555
580 var subscription = this; 556 var subscription = this;
581 557
@@ -606,6 +582,10 @@ export default class Subscription { @@ -606,6 +582,10 @@ export default class Subscription {
606 582
607 this.datasourceListeners.push(listener); 583 this.datasourceListeners.push(listener);
608 this.ctx.datasourceService.subscribeToDatasource(listener); 584 this.ctx.datasourceService.subscribeToDatasource(listener);
  585 + if (datasource.unresolvedStateEntity) {
  586 + this.notifyDataLoaded();
  587 + this.onDataUpdated();
  588 + }
609 } 589 }
610 } 590 }
611 591
@@ -625,19 +605,6 @@ export default class Subscription { @@ -625,19 +605,6 @@ export default class Subscription {
625 } else { 605 } else {
626 return false; 606 return false;
627 } 607 }
628 - /*var deviceId = null;  
629 - if (this.ctx.aliasesInfo.entityAliases[this.targetDeviceAliasId]) {  
630 - deviceId = this.ctx.aliasesInfo.entityAliases[this.targetDeviceAliasId].entityId;  
631 - }  
632 - if (!angular.equals(deviceId, this.targetDeviceId)) {  
633 - this.targetDeviceId = deviceId;  
634 - if (this.targetDeviceId) {  
635 - this.rpcEnabled = true;  
636 - } else {  
637 - this.rpcEnabled = this.ctx.$scope.widgetEditMode ? true : false;  
638 - }  
639 - this.callbacks.rpcStateChanged(this);  
640 - }*/  
641 } 608 }
642 609
643 checkSubscriptions(aliasIds) { 610 checkSubscriptions(aliasIds) {
@@ -650,29 +617,8 @@ export default class Subscription { @@ -650,29 +617,8 @@ export default class Subscription {
650 break; 617 break;
651 } 618 }
652 } 619 }
653 - /*var entityId = null;  
654 - var entityType = null;  
655 - var aliasName = null;  
656 - if (listener.datasource.type === this.ctx.types.datasourceType.entity) {  
657 - if (listener.datasource.entityAliasId &&  
658 - this.ctx.aliasesInfo.entityAliases[listener.datasource.entityAliasId]) {  
659 - entityId = this.ctx.aliasesInfo.entityAliases[listener.datasource.entityAliasId].entityId;  
660 - entityType = this.ctx.aliasesInfo.entityAliases[listener.datasource.entityAliasId].entityType;  
661 - aliasName = this.ctx.aliasesInfo.entityAliases[listener.datasource.entityAliasId].alias;  
662 - }  
663 - if (!angular.equals(entityId, listener.entityId) ||  
664 - !angular.equals(entityType, listener.entityType) ||  
665 - !angular.equals(aliasName, listener.datasource.name)) {  
666 - subscriptionsChanged = true;  
667 - break;  
668 - }  
669 - }*/  
670 } 620 }
671 return subscriptionsChanged; 621 return subscriptionsChanged;
672 - /*if (subscriptionsChanged) {  
673 - this.unsubscribe();  
674 - this.subscribe();  
675 - }*/  
676 } 622 }
677 623
678 destroy() { 624 destroy() {
@@ -691,29 +637,6 @@ export default class Subscription { @@ -691,29 +637,6 @@ export default class Subscription {
691 637
692 } 638 }
693 639
694 -/*const varsRegex = /\$\{([^\}]*)\}/g;  
695 -  
696 -function updateDataKeyLabel(dataKey, dsName, entityName, aliasName) {  
697 - var pattern = dataKey.pattern;  
698 - var label = dataKey.pattern;  
699 - var match = varsRegex.exec(pattern);  
700 - while (match !== null) {  
701 - var variable = match[0];  
702 - var variableName = match[1];  
703 - if (variableName === 'dsName') {  
704 - label = label.split(variable).join(dsName);  
705 - } else if (variableName === 'entityName') {  
706 - label = label.split(variable).join(entityName);  
707 - } else if (variableName === 'deviceName') {  
708 - label = label.split(variable).join(entityName);  
709 - } else if (variableName === 'aliasName') {  
710 - label = label.split(variable).join(aliasName);  
711 - }  
712 - match = varsRegex.exec(pattern);  
713 - }  
714 - dataKey.label = label;  
715 -}*/  
716 -  
717 function calculateMin(data) { 640 function calculateMin(data) {
718 if (data.length > 0) { 641 if (data.length > 0) {
719 var result = Number(data[0][1]); 642 var result = Number(data[0][1]);
@@ -23,8 +23,10 @@ function DashboardUtils(types, utils, timeService) { @@ -23,8 +23,10 @@ function DashboardUtils(types, utils, timeService) {
23 23
24 var service = { 24 var service = {
25 validateAndUpdateDashboard: validateAndUpdateDashboard, 25 validateAndUpdateDashboard: validateAndUpdateDashboard,
  26 + validateAndUpdateWidget: validateAndUpdateWidget,
26 getRootStateId: getRootStateId, 27 getRootStateId: getRootStateId,
27 createSingleWidgetDashboard: createSingleWidgetDashboard, 28 createSingleWidgetDashboard: createSingleWidgetDashboard,
  29 + createSingleEntityFilter: createSingleEntityFilter,
28 getStateLayoutsData: getStateLayoutsData, 30 getStateLayoutsData: getStateLayoutsData,
29 createDefaultState: createDefaultState, 31 createDefaultState: createDefaultState,
30 createDefaultLayoutData: createDefaultLayoutData, 32 createDefaultLayoutData: createDefaultLayoutData,
@@ -39,7 +41,7 @@ function DashboardUtils(types, utils, timeService) { @@ -39,7 +41,7 @@ function DashboardUtils(types, utils, timeService) {
39 41
40 return service; 42 return service;
41 43
42 - function validateAndUpdateEntityAliases(configuration) { 44 + function validateAndUpdateEntityAliases(configuration, datasourcesByAliasId, targetDevicesByAliasId) {
43 var aliasId, entityAlias; 45 var aliasId, entityAlias;
44 if (angular.isUndefined(configuration.entityAliases)) { 46 if (angular.isUndefined(configuration.entityAliases)) {
45 configuration.entityAliases = {}; 47 configuration.entityAliases = {};
@@ -47,8 +49,8 @@ function DashboardUtils(types, utils, timeService) { @@ -47,8 +49,8 @@ function DashboardUtils(types, utils, timeService) {
47 var deviceAliases = configuration.deviceAliases; 49 var deviceAliases = configuration.deviceAliases;
48 for (aliasId in deviceAliases) { 50 for (aliasId in deviceAliases) {
49 var deviceAlias = deviceAliases[aliasId]; 51 var deviceAlias = deviceAliases[aliasId];
50 - entityAlias = validateAndUpdateDeviceAlias(aliasId, deviceAlias);  
51 - configuration.entityAliases[aliasId] = entityAlias; 52 + entityAlias = validateAndUpdateDeviceAlias(aliasId, deviceAlias, datasourcesByAliasId, targetDevicesByAliasId);
  53 + configuration.entityAliases[entityAlias.id] = entityAlias;
52 } 54 }
53 delete configuration.deviceAliases; 55 delete configuration.deviceAliases;
54 } 56 }
@@ -56,16 +58,43 @@ function DashboardUtils(types, utils, timeService) { @@ -56,16 +58,43 @@ function DashboardUtils(types, utils, timeService) {
56 var entityAliases = configuration.entityAliases; 58 var entityAliases = configuration.entityAliases;
57 for (aliasId in entityAliases) { 59 for (aliasId in entityAliases) {
58 entityAlias = entityAliases[aliasId]; 60 entityAlias = entityAliases[aliasId];
59 - entityAliases[aliasId] = validateAndUpdateEntityAlias(entityAlias);  
60 - if (!entityAliases[aliasId].id) {  
61 - entityAliases[aliasId].id = aliasId; 61 + entityAlias = validateAndUpdateEntityAlias(aliasId, entityAlias, datasourcesByAliasId, targetDevicesByAliasId);
  62 + if (aliasId != entityAlias.id) {
  63 + delete entityAliases[aliasId];
62 } 64 }
  65 + entityAliases[entityAlias.id] = entityAlias;
63 } 66 }
64 } 67 }
65 return configuration; 68 return configuration;
66 } 69 }
67 70
68 - function validateAndUpdateDeviceAlias(aliasId, deviceAlias) { 71 + function validateAliasId(aliasId, datasourcesByAliasId, targetDevicesByAliasId) {
  72 + if (!aliasId || !angular.isString(aliasId) || aliasId.length != 36) {
  73 + var newAliasId = utils.guid();
  74 + var aliasDatasources = datasourcesByAliasId[aliasId];
  75 + if (aliasDatasources) {
  76 + aliasDatasources.forEach(
  77 + function(datasource) {
  78 + datasource.entityAliasId = newAliasId;
  79 + }
  80 + );
  81 + }
  82 + var targetDeviceAliasIdsList = targetDevicesByAliasId[aliasId];
  83 + if (targetDeviceAliasIdsList) {
  84 + targetDeviceAliasIdsList.forEach(
  85 + function(targetDeviceAliasIds) {
  86 + targetDeviceAliasIds[0] = newAliasId;
  87 + }
  88 + );
  89 + }
  90 + return newAliasId;
  91 + } else {
  92 + return aliasId;
  93 + }
  94 + }
  95 +
  96 + function validateAndUpdateDeviceAlias(aliasId, deviceAlias, datasourcesByAliasId, targetDevicesByAliasId) {
  97 + aliasId = validateAliasId(aliasId, datasourcesByAliasId, targetDevicesByAliasId);
69 var alias = deviceAlias.alias; 98 var alias = deviceAlias.alias;
70 var entityAlias = { 99 var entityAlias = {
71 id: aliasId, 100 id: aliasId,
@@ -93,7 +122,8 @@ function DashboardUtils(types, utils, timeService) { @@ -93,7 +122,8 @@ function DashboardUtils(types, utils, timeService) {
93 return entityAlias; 122 return entityAlias;
94 } 123 }
95 124
96 - function validateAndUpdateEntityAlias(entityAlias) { 125 + function validateAndUpdateEntityAlias(aliasId, entityAlias, datasourcesByAliasId, targetDevicesByAliasId) {
  126 + entityAlias.id = validateAliasId(aliasId, datasourcesByAliasId, targetDevicesByAliasId);
97 if (!entityAlias.filter) { 127 if (!entityAlias.filter) {
98 entityAlias.filter = { 128 entityAlias.filter = {
99 type: entityAlias.entityFilter.useFilter ? types.aliasFilterType.entityName.value : types.aliasFilterType.entityList.value, 129 type: entityAlias.entityFilter.useFilter ? types.aliasFilterType.entityName.value : types.aliasFilterType.entityList.value,
@@ -206,12 +236,33 @@ function DashboardUtils(types, utils, timeService) { @@ -206,12 +236,33 @@ function DashboardUtils(types, utils, timeService) {
206 } 236 }
207 } 237 }
208 238
209 - /* var datasources = {}; 239 + var datasourcesByAliasId = {};
  240 + var targetDevicesByAliasId = {};
210 for (var widgetId in dashboard.configuration.widgets) { 241 for (var widgetId in dashboard.configuration.widgets) {
  242 + widget = dashboard.configuration.widgets[widgetId];
  243 + widget.config.datasources.forEach(function (datasource) {
  244 + if (datasource.entityAliasId) {
  245 + var aliasId = datasource.entityAliasId;
  246 + var aliasDatasources = datasourcesByAliasId[aliasId];
  247 + if (!aliasDatasources) {
  248 + aliasDatasources = [];
  249 + datasourcesByAliasId[aliasId] = aliasDatasources;
  250 + }
  251 + aliasDatasources.push(datasource);
  252 + }
  253 + });
  254 + if (widget.config.targetDeviceAliasIds && widget.config.targetDeviceAliasIds.length) {
  255 + var aliasId = widget.config.targetDeviceAliasIds[0];
  256 + var targetDeviceAliasIdsList = targetDevicesByAliasId[aliasId];
  257 + if (!targetDeviceAliasIdsList) {
  258 + targetDeviceAliasIdsList = [];
  259 + targetDevicesByAliasId[aliasId] = targetDeviceAliasIdsList;
  260 + }
  261 + targetDeviceAliasIdsList.push(widget.config.targetDeviceAliasIds);
  262 + }
  263 + }
211 264
212 - }*/  
213 -  
214 - dashboard.configuration = validateAndUpdateEntityAliases(dashboard.configuration); 265 + dashboard.configuration = validateAndUpdateEntityAliases(dashboard.configuration, datasourcesByAliasId, targetDevicesByAliasId);
215 266
216 if (angular.isUndefined(dashboard.configuration.timewindow)) { 267 if (angular.isUndefined(dashboard.configuration.timewindow)) {
217 dashboard.configuration.timewindow = timeService.defaultTimewindow(); 268 dashboard.configuration.timewindow = timeService.defaultTimewindow();
@@ -288,6 +339,16 @@ function DashboardUtils(types, utils, timeService) { @@ -288,6 +339,16 @@ function DashboardUtils(types, utils, timeService) {
288 return dashboard; 339 return dashboard;
289 } 340 }
290 341
  342 + function createSingleEntityFilter(entityType, entityId) {
  343 + return {
  344 + type: types.aliasFilterType.entityList.value,
  345 + stateEntity: false,
  346 + entityList: [entityId],
  347 + entityType: entityType,
  348 + resolveMultiple: false
  349 + };
  350 + }
  351 +
291 function getStateLayoutsData(dashboard, targetState) { 352 function getStateLayoutsData(dashboard, targetState) {
292 var dashboardConfiguration = dashboard.configuration; 353 var dashboardConfiguration = dashboard.configuration;
293 var states = dashboardConfiguration.states; 354 var states = dashboardConfiguration.states;
@@ -106,6 +106,7 @@ function Utils($mdColorPalette, $rootScope, $window, types) { @@ -106,6 +106,7 @@ function Utils($mdColorPalette, $rootScope, $window, types) {
106 isDescriptorSchemaNotEmpty: isDescriptorSchemaNotEmpty, 106 isDescriptorSchemaNotEmpty: isDescriptorSchemaNotEmpty,
107 filterSearchTextEntities: filterSearchTextEntities, 107 filterSearchTextEntities: filterSearchTextEntities,
108 guid: guid, 108 guid: guid,
  109 + cleanCopy: cleanCopy,
109 isLocalUrl: isLocalUrl, 110 isLocalUrl: isLocalUrl,
110 validateDatasources: validateDatasources, 111 validateDatasources: validateDatasources,
111 createKey: createKey, 112 createKey: createKey,
@@ -291,6 +292,16 @@ function Utils($mdColorPalette, $rootScope, $window, types) { @@ -291,6 +292,16 @@ function Utils($mdColorPalette, $rootScope, $window, types) {
291 s4() + '-' + s4() + s4() + s4(); 292 s4() + '-' + s4() + s4() + s4();
292 } 293 }
293 294
  295 + function cleanCopy(object) {
  296 + var copy = angular.copy(object);
  297 + for (var prop in copy) {
  298 + if (prop && prop.startsWith('$$')) {
  299 + delete copy[prop];
  300 + }
  301 + }
  302 + return copy;
  303 + }
  304 +
294 function genNextColor(datasources) { 305 function genNextColor(datasources) {
295 var index = 0; 306 var index = 0;
296 if (datasources) { 307 if (datasources) {
@@ -85,7 +85,7 @@ function Dashboard() { @@ -85,7 +85,7 @@ function Dashboard() {
85 } 85 }
86 86
87 /*@ngInject*/ 87 /*@ngInject*/
88 -function DashboardController($scope, $rootScope, $element, $timeout, $mdMedia, timeService, types, utils) { 88 +function DashboardController($scope, $rootScope, $element, $timeout, $mdMedia, $mdUtil, timeService, types, utils) {
89 89
90 var highlightedMode = false; 90 var highlightedMode = false;
91 var highlightedWidget = null; 91 var highlightedWidget = null;
@@ -792,7 +792,7 @@ function DashboardController($scope, $rootScope, $element, $timeout, $mdMedia, t @@ -792,7 +792,7 @@ function DashboardController($scope, $rootScope, $element, $timeout, $mdMedia, t
792 } 792 }
793 793
794 function dashboardLoaded() { 794 function dashboardLoaded() {
795 - $timeout(function () { 795 + $mdUtil.nextTick(function () {
796 if (vm.dashboardTimewindowWatch) { 796 if (vm.dashboardTimewindowWatch) {
797 vm.dashboardTimewindowWatch(); 797 vm.dashboardTimewindowWatch();
798 vm.dashboardTimewindowWatch = null; 798 vm.dashboardTimewindowWatch = null;
@@ -802,14 +802,27 @@ function DashboardController($scope, $rootScope, $element, $timeout, $mdMedia, t @@ -802,14 +802,27 @@ function DashboardController($scope, $rootScope, $element, $timeout, $mdMedia, t
802 }, true); 802 }, true);
803 adoptMaxRows(); 803 adoptMaxRows();
804 vm.dashboardLoading = false; 804 vm.dashboardLoading = false;
805 - $timeout(function () {  
806 - var gridsterScope = gridsterElement.scope();  
807 - vm.gridster = gridsterScope.gridster;  
808 - if (vm.onInit) {  
809 - vm.onInit({dashboard: vm}); 805 + if ($scope.gridsterScopeWatcher) {
  806 + $scope.gridsterScopeWatcher();
  807 + }
  808 + $scope.gridsterScopeWatcher = $scope.$watch(
  809 + function() {
  810 + var hasScope = gridsterElement.scope() ? true : false;
  811 + return hasScope;
  812 + },
  813 + function(hasScope) {
  814 + if (hasScope) {
  815 + $scope.gridsterScopeWatcher();
  816 + $scope.gridsterScopeWatcher = null;
  817 + var gridsterScope = gridsterElement.scope();
  818 + vm.gridster = gridsterScope.gridster;
  819 + if (vm.onInit) {
  820 + vm.onInit({dashboard: vm});
  821 + }
  822 + }
810 } 823 }
811 - }, 0, false);  
812 - }, 0, false); 824 + );
  825 + });
813 } 826 }
814 827
815 function loading() { 828 function loading() {
@@ -20,9 +20,9 @@ import Subscription from '../api/subscription'; @@ -20,9 +20,9 @@ import Subscription from '../api/subscription';
20 /* eslint-disable angular/angularelement */ 20 /* eslint-disable angular/angularelement */
21 21
22 /*@ngInject*/ 22 /*@ngInject*/
23 -export default function WidgetController($scope, $timeout, $window, $element, $q, $log, $injector, $filter, tbRaf, types, utils, timeService, 23 +export default function WidgetController($scope, $timeout, $window, $element, $q, $log, $injector, $filter, $compile, tbRaf, types, utils, timeService,
24 datasourceService, entityService, deviceService, visibleRect, isEdit, stDiff, dashboardTimewindow, 24 datasourceService, entityService, deviceService, visibleRect, isEdit, stDiff, dashboardTimewindow,
25 - dashboardTimewindowApi, widget, aliasController, stateController, widgetType) { 25 + dashboardTimewindowApi, widget, aliasController, stateController, widgetInfo, widgetType) {
26 26
27 var vm = this; 27 var vm = this;
28 28
@@ -42,20 +42,11 @@ export default function WidgetController($scope, $timeout, $window, $element, $q @@ -42,20 +42,11 @@ export default function WidgetController($scope, $timeout, $window, $element, $q
42 42
43 var cafs = {}; 43 var cafs = {};
44 44
45 - /*  
46 - * data = array of datasourceData  
47 - * datasourceData = {  
48 - * tbDatasource,  
49 - * dataKey, { name, config }  
50 - * data = array of [time, value]  
51 - * }  
52 - */  
53 -  
54 var widgetContext = { 45 var widgetContext = {
55 inited: false, 46 inited: false,
56 $scope: $scope, 47 $scope: $scope,
57 - $container: $('#container', $element),  
58 - $containerParent: $($element), 48 + $container: null,
  49 + $containerParent: null,
59 width: 0, 50 width: 0,
60 height: 0, 51 height: 0,
61 isEdit: isEdit, 52 isEdit: isEdit,
@@ -82,30 +73,6 @@ export default function WidgetController($scope, $timeout, $window, $element, $q @@ -82,30 +73,6 @@ export default function WidgetController($scope, $timeout, $window, $element, $q
82 createSubscription: function(options, subscribe) { 73 createSubscription: function(options, subscribe) {
83 return createSubscription(options, subscribe); 74 return createSubscription(options, subscribe);
84 }, 75 },
85 -  
86 -  
87 - // type: "timeseries" or "latest" or "rpc"  
88 - /* subscriptionInfo = [  
89 - {  
90 - entityType: ""  
91 - entityId: ""  
92 - entityName: ""  
93 - timeseries: [{ name: "", label: "" }, ..]  
94 - attributes: [{ name: "", label: "" }, ..]  
95 - }  
96 - ..  
97 - ]*/  
98 -  
99 - // options = {  
100 - // timeWindowConfig,  
101 - // useDashboardTimewindow,  
102 - // legendConfig,  
103 - // decimals,  
104 - // units,  
105 - // callbacks [ onDataUpdated(subscription, apply) ]  
106 - // }  
107 - //  
108 -  
109 createSubscriptionFromInfo: function (type, subscriptionsInfo, options, useDefaultComponents, subscribe) { 76 createSubscriptionFromInfo: function (type, subscriptionsInfo, options, useDefaultComponents, subscribe) {
110 return createSubscriptionFromInfo(type, subscriptionsInfo, options, useDefaultComponents, subscribe); 77 return createSubscriptionFromInfo(type, subscriptionsInfo, options, useDefaultComponents, subscribe);
111 }, 78 },
@@ -211,21 +178,6 @@ export default function WidgetController($scope, $timeout, $window, $element, $q @@ -211,21 +178,6 @@ export default function WidgetController($scope, $timeout, $window, $element, $q
211 } 178 }
212 ); 179 );
213 180
214 - /*  
215 - options = {  
216 - type,  
217 - targetDeviceAliasIds, // RPC  
218 - targetDeviceIds, // RPC  
219 - datasources,  
220 - timeWindowConfig,  
221 - useDashboardTimewindow,  
222 - legendConfig,  
223 - decimals,  
224 - units,  
225 - callbacks  
226 - }  
227 - */  
228 -  
229 function createSubscriptionFromInfo(type, subscriptionsInfo, options, useDefaultComponents, subscribe) { 181 function createSubscriptionFromInfo(type, subscriptionsInfo, options, useDefaultComponents, subscribe) {
230 var deferred = $q.defer(); 182 var deferred = $q.defer();
231 options.type = type; 183 options.type = type;
@@ -400,6 +352,101 @@ export default function WidgetController($scope, $timeout, $window, $element, $q @@ -400,6 +352,101 @@ export default function WidgetController($scope, $timeout, $window, $element, $q
400 return deferred.promise; 352 return deferred.promise;
401 } 353 }
402 354
  355 + function configureWidgetElement() {
  356 +
  357 + $scope.displayLegend = angular.isDefined(widget.config.showLegend) ?
  358 + widget.config.showLegend : widget.type === types.widgetType.timeseries.value;
  359 +
  360 + if ($scope.displayLegend) {
  361 + $scope.legendConfig = widget.config.legendConfig ||
  362 + {
  363 + position: types.position.bottom.value,
  364 + showMin: false,
  365 + showMax: false,
  366 + showAvg: widget.type === types.widgetType.timeseries.value,
  367 + showTotal: false
  368 + };
  369 + $scope.legendData = {
  370 + keys: [],
  371 + data: []
  372 + };
  373 + }
  374 +
  375 + var html = '<div class="tb-absolute-fill tb-widget-error" ng-if="widgetErrorData">' +
  376 + '<span>Widget Error: {{ widgetErrorData.name + ": " + widgetErrorData.message}}</span>' +
  377 + '</div>' +
  378 + '<div class="tb-absolute-fill tb-widget-loading" ng-show="loadingData" layout="column" layout-align="center center">' +
  379 + '<md-progress-circular md-mode="indeterminate" ng-disabled="!loadingData" class="md-accent" md-diameter="40"></md-progress-circular>' +
  380 + '</div>';
  381 +
  382 + var containerHtml = '<div id="container">' + widgetInfo.templateHtml + '</div>';
  383 + if ($scope.displayLegend) {
  384 + var layoutType;
  385 + if ($scope.legendConfig.position === types.position.top.value ||
  386 + $scope.legendConfig.position === types.position.bottom.value) {
  387 + layoutType = 'column';
  388 + } else {
  389 + layoutType = 'row';
  390 + }
  391 +
  392 + var legendStyle;
  393 + switch($scope.legendConfig.position) {
  394 + case types.position.top.value:
  395 + legendStyle = 'padding-bottom: 8px;';
  396 + break;
  397 + case types.position.bottom.value:
  398 + legendStyle = 'padding-top: 8px;';
  399 + break;
  400 + case types.position.left.value:
  401 + legendStyle = 'padding-right: 0px;';
  402 + break;
  403 + case types.position.right.value:
  404 + legendStyle = 'padding-left: 0px;';
  405 + break;
  406 + }
  407 +
  408 + var legendHtml = '<tb-legend style="'+legendStyle+'" legend-config="legendConfig" legend-data="legendData"></tb-legend>';
  409 + containerHtml = '<div flex id="widget-container">' + containerHtml + '</div>';
  410 + html += '<div class="tb-absolute-fill" layout="'+layoutType+'">';
  411 + if ($scope.legendConfig.position === types.position.top.value ||
  412 + $scope.legendConfig.position === types.position.left.value) {
  413 + html += legendHtml;
  414 + html += containerHtml;
  415 + } else {
  416 + html += containerHtml;
  417 + html += legendHtml;
  418 + }
  419 + html += '</div>';
  420 + } else {
  421 + html += containerHtml;
  422 + }
  423 +
  424 + //TODO:
  425 + /*if (progressElement) {
  426 + progressScope.$destroy();
  427 + progressScope = null;
  428 +
  429 + progressElement.remove();
  430 + progressElement = null;
  431 + }*/
  432 +
  433 + $element.html(html);
  434 +
  435 + var containerElement = $scope.displayLegend ? angular.element($element[0].querySelector('#widget-container')) : $element;
  436 + widgetContext.$container = $('#container', containerElement);
  437 + widgetContext.$containerParent = $(containerElement);
  438 +
  439 + $compile($element.contents())($scope);
  440 +
  441 + addResizeListener(widgetContext.$containerParent[0], onResize); // eslint-disable-line no-undef
  442 + }
  443 +
  444 + function destroyWidgetElement() {
  445 + removeResizeListener(widgetContext.$containerParent[0], onResize); // eslint-disable-line no-undef
  446 + $element.html('');
  447 + widgetContext.$container = null;
  448 + widgetContext.$containerParent = null;
  449 + }
403 450
404 function initialize() { 451 function initialize() {
405 452
@@ -407,8 +454,6 @@ export default function WidgetController($scope, $timeout, $window, $element, $q @@ -407,8 +454,6 @@ export default function WidgetController($scope, $timeout, $window, $element, $q
407 onEditModeChanged(isEdit); 454 onEditModeChanged(isEdit);
408 }); 455 });
409 456
410 - addResizeListener(widgetContext.$containerParent[0], onResize); // eslint-disable-line no-undef  
411 -  
412 $scope.$watch(function () { 457 $scope.$watch(function () {
413 return widget.row + ',' + widget.col + ',' + widget.config.mobileOrder; 458 return widget.row + ',' + widget.col + ',' + widget.config.mobileOrder;
414 }, function () { 459 }, function () {
@@ -439,10 +484,10 @@ export default function WidgetController($scope, $timeout, $window, $element, $q @@ -439,10 +484,10 @@ export default function WidgetController($scope, $timeout, $window, $element, $q
439 }); 484 });
440 485
441 $scope.$on("$destroy", function () { 486 $scope.$on("$destroy", function () {
442 - removeResizeListener(widgetContext.$containerParent[0], onResize); // eslint-disable-line no-undef  
443 onDestroy(); 487 onDestroy();
444 }); 488 });
445 489
  490 + configureWidgetElement();
446 var deferred = $q.defer(); 491 var deferred = $q.defer();
447 if (!vm.useCustomDatasources) { 492 if (!vm.useCustomDatasources) {
448 createDefaultSubscription().then( 493 createDefaultSubscription().then(
@@ -465,6 +510,7 @@ export default function WidgetController($scope, $timeout, $window, $element, $q @@ -465,6 +510,7 @@ export default function WidgetController($scope, $timeout, $window, $element, $q
465 510
466 function reInit() { 511 function reInit() {
467 onDestroy(); 512 onDestroy();
  513 + configureWidgetElement();
468 if (!vm.useCustomDatasources) { 514 if (!vm.useCustomDatasources) {
469 createDefaultSubscription().then( 515 createDefaultSubscription().then(
470 function success() { 516 function success() {
@@ -636,6 +682,7 @@ export default function WidgetController($scope, $timeout, $window, $element, $q @@ -636,6 +682,7 @@ export default function WidgetController($scope, $timeout, $window, $element, $q
636 handleWidgetException(e); 682 handleWidgetException(e);
637 } 683 }
638 } 684 }
  685 + destroyWidgetElement();
639 } 686 }
640 687
641 //TODO: widgets visibility 688 //TODO: widgets visibility
@@ -28,7 +28,7 @@ export default angular.module('thingsboard.directives.widget', [thingsboardLegen @@ -28,7 +28,7 @@ export default angular.module('thingsboard.directives.widget', [thingsboardLegen
28 .name; 28 .name;
29 29
30 /*@ngInject*/ 30 /*@ngInject*/
31 -function Widget($controller, $compile, types, widgetService) { 31 +function Widget($controller, widgetService) {
32 return { 32 return {
33 scope: true, 33 scope: true,
34 link: function (scope, elem, attrs) { 34 link: function (scope, elem, attrs) {
@@ -81,90 +81,9 @@ function Widget($controller, $compile, types, widgetService) { @@ -81,90 +81,9 @@ function Widget($controller, $compile, types, widgetService) {
81 81
82 elem.addClass(widgetNamespace); 82 elem.addClass(widgetNamespace);
83 83
84 - var html = '<div class="tb-absolute-fill tb-widget-error" ng-if="widgetErrorData">' +  
85 - '<span>Widget Error: {{ widgetErrorData.name + ": " + widgetErrorData.message}}</span>' +  
86 - '</div>' +  
87 - '<div class="tb-absolute-fill tb-widget-loading" ng-show="loadingData" layout="column" layout-align="center center">' +  
88 - '<md-progress-circular md-mode="indeterminate" ng-disabled="!loadingData" class="md-accent" md-diameter="40"></md-progress-circular>' +  
89 - '</div>';  
90 -  
91 - scope.displayLegend = angular.isDefined(widget.config.showLegend) ?  
92 - widget.config.showLegend : widget.type === types.widgetType.timeseries.value;  
93 -  
94 -  
95 - var containerHtml = '<div id="container">' + widgetInfo.templateHtml + '</div>';  
96 - if (scope.displayLegend) {  
97 - scope.legendConfig = widget.config.legendConfig ||  
98 - {  
99 - position: types.position.bottom.value,  
100 - showMin: false,  
101 - showMax: false,  
102 - showAvg: widget.type === types.widgetType.timeseries.value,  
103 - showTotal: false  
104 - };  
105 - scope.legendData = {  
106 - keys: [],  
107 - data: []  
108 - };  
109 -  
110 - var layoutType;  
111 - if (scope.legendConfig.position === types.position.top.value ||  
112 - scope.legendConfig.position === types.position.bottom.value) {  
113 - layoutType = 'column';  
114 - } else {  
115 - layoutType = 'row';  
116 - }  
117 -  
118 - var legendStyle;  
119 - switch(scope.legendConfig.position) {  
120 - case types.position.top.value:  
121 - legendStyle = 'padding-bottom: 8px;';  
122 - break;  
123 - case types.position.bottom.value:  
124 - legendStyle = 'padding-top: 8px;';  
125 - break;  
126 - case types.position.left.value:  
127 - legendStyle = 'padding-right: 0px;';  
128 - break;  
129 - case types.position.right.value:  
130 - legendStyle = 'padding-left: 0px;';  
131 - break;  
132 - }  
133 -  
134 - var legendHtml = '<tb-legend style="'+legendStyle+'" legend-config="legendConfig" legend-data="legendData"></tb-legend>';  
135 - containerHtml = '<div flex id="widget-container">' + containerHtml + '</div>';  
136 - html += '<div class="tb-absolute-fill" layout="'+layoutType+'">';  
137 - if (scope.legendConfig.position === types.position.top.value ||  
138 - scope.legendConfig.position === types.position.left.value) {  
139 - html += legendHtml;  
140 - html += containerHtml;  
141 - } else {  
142 - html += containerHtml;  
143 - html += legendHtml;  
144 - }  
145 - html += '</div>';  
146 - } else {  
147 - html += containerHtml;  
148 - }  
149 -  
150 - //TODO:  
151 - /*if (progressElement) {  
152 - progressScope.$destroy();  
153 - progressScope = null;  
154 -  
155 - progressElement.remove();  
156 - progressElement = null;  
157 - }*/  
158 -  
159 - elem.html(html);  
160 -  
161 - var containerElement = scope.displayLegend ? angular.element(elem[0].querySelector('#widget-container')) : elem;  
162 -  
163 - $compile(elem.contents())(scope);  
164 -  
165 var widgetType = widgetService.getWidgetTypeFunction(widget.bundleAlias, widget.typeAlias, widget.isSystemType); 84 var widgetType = widgetService.getWidgetTypeFunction(widget.bundleAlias, widget.typeAlias, widget.isSystemType);
166 85
167 - angular.extend(locals, {$scope: scope, $element: containerElement, widgetType: widgetType}); 86 + angular.extend(locals, {$scope: scope, $element: elem, widgetInfo: widgetInfo, widgetType: widgetType});
168 87
169 widgetController = $controller('WidgetController', locals); 88 widgetController = $controller('WidgetController', locals);
170 89
@@ -15,7 +15,7 @@ @@ -15,7 +15,7 @@
15 */ 15 */
16 16
17 /*@ngInject*/ 17 /*@ngInject*/
18 -export default function AliasesEntitySelectPanelController(mdPanelRef, $scope, types, aliasController, onEntityAliasesUpdate) { 18 +export default function AliasesEntitySelectPanelController(mdPanelRef, $scope, $filter, types, aliasController, onEntityAliasesUpdate) {
19 19
20 var vm = this; 20 var vm = this;
21 vm._mdPanelRef = mdPanelRef; 21 vm._mdPanelRef = mdPanelRef;
@@ -31,13 +31,18 @@ export default function AliasesEntitySelectPanelController(mdPanelRef, $scope, t @@ -31,13 +31,18 @@ export default function AliasesEntitySelectPanelController(mdPanelRef, $scope, t
31 var aliasInfo = vm.aliasController.getInstantAliasInfo(aliasId); 31 var aliasInfo = vm.aliasController.getInstantAliasInfo(aliasId);
32 if (aliasInfo && !aliasInfo.resolveMultiple && aliasInfo.currentEntity) { 32 if (aliasInfo && !aliasInfo.resolveMultiple && aliasInfo.currentEntity) {
33 vm.entityAliasesInfo[aliasId] = angular.copy(aliasInfo); 33 vm.entityAliasesInfo[aliasId] = angular.copy(aliasInfo);
  34 + vm.entityAliasesInfo[aliasId].selectedId = aliasInfo.currentEntity.id;
34 } 35 }
35 } 36 }
36 37
37 - function currentAliasEntityChanged(aliasId, currentEntity) {  
38 - vm.aliasController.updateCurrentAliasEntity(aliasId, currentEntity);  
39 - if (onEntityAliasesUpdate) {  
40 - onEntityAliasesUpdate(); 38 + function currentAliasEntityChanged(aliasId, selectedId) {
  39 + var resolvedEntities = vm.entityAliasesInfo[aliasId].resolvedEntities;
  40 + var selected = $filter('filter')(resolvedEntities, {id: selectedId});
  41 + if (selected && selected.length) {
  42 + vm.aliasController.updateCurrentAliasEntity(aliasId, selected[0]);
  43 + if (onEntityAliasesUpdate) {
  44 + onEntityAliasesUpdate();
  45 + }
41 } 46 }
42 } 47 }
43 48
@@ -21,8 +21,8 @@ @@ -21,8 +21,8 @@
21 <div flex layout="row" ng-repeat="(aliasId, entityAliasInfo) in vm.entityAliasesInfo"> 21 <div flex layout="row" ng-repeat="(aliasId, entityAliasInfo) in vm.entityAliasesInfo">
22 <md-input-container flex> 22 <md-input-container flex>
23 <label>{{entityAliasInfo.alias}}</label> 23 <label>{{entityAliasInfo.alias}}</label>
24 - <md-select ng-model="entityAliasInfo.currentEntity" ng-change="vm.currentAliasEntityChanged(aliasId, entityAliasInfo.currentEntity)">  
25 - <md-option ng-repeat="resolvedEntity in entityAliasInfo.resolvedEntities" ng-value="resolvedEntity"> 24 + <md-select ng-model="entityAliasInfo.selectedId" ng-change="vm.currentAliasEntityChanged(aliasId, entityAliasInfo.selectedId)">
  25 + <md-option ng-repeat="resolvedEntity in entityAliasInfo.resolvedEntities" ng-value="resolvedEntity.id">
26 {{resolvedEntity.name}} 26 {{resolvedEntity.name}}
27 </md-option> 27 </md-option>
28 </md-select> 28 </md-select>
@@ -94,6 +94,14 @@ export default function AliasesEntitySelectDirective($compile, $templateCache, $ @@ -94,6 +94,14 @@ export default function AliasesEntitySelectDirective($compile, $templateCache, $
94 $mdPanel.open(config); 94 $mdPanel.open(config);
95 } 95 }
96 96
  97 + scope.$on('entityAliasesChanged', function() {
  98 + scope.updateView();
  99 + });
  100 +
  101 + scope.$on('entityAliasResolved', function() {
  102 + scope.updateView();
  103 + });
  104 +
97 scope.updateView = function () { 105 scope.updateView = function () {
98 updateDisplayValue(); 106 updateDisplayValue();
99 } 107 }
@@ -22,7 +22,7 @@ import selectTargetLayoutTemplate from '../../dashboard/layouts/select-target-la @@ -22,7 +22,7 @@ import selectTargetLayoutTemplate from '../../dashboard/layouts/select-target-la
22 /* eslint-enable import/no-unresolved, import/default */ 22 /* eslint-enable import/no-unresolved, import/default */
23 23
24 /*@ngInject*/ 24 /*@ngInject*/
25 -export default function AddWidgetToDashboardDialogController($scope, $mdDialog, $state, $q, $document, 25 +export default function AddWidgetToDashboardDialogController($scope, $mdDialog, $state, $q, $document, dashboardUtils,
26 types, itembuffer, dashboardService, entityId, entityType, entityName, widget) { 26 types, itembuffer, dashboardService, entityId, entityType, entityName, widget) {
27 27
28 var vm = this; 28 var vm = this;
@@ -126,15 +126,8 @@ export default function AddWidgetToDashboardDialogController($scope, $mdDialog, @@ -126,15 +126,8 @@ export default function AddWidgetToDashboardDialogController($scope, $mdDialog,
126 targetDeviceAliases: {} 126 targetDeviceAliases: {}
127 }; 127 };
128 aliasesInfo.datasourceAliases[0] = { 128 aliasesInfo.datasourceAliases[0] = {
129 - id: 1,  
130 alias: entityName, 129 alias: entityName,
131 - filter: {  
132 - type: types.aliasFilterType.entityList.value,  
133 - stateEntity: false,  
134 - entityList: [entityId],  
135 - entityType: entityType,  
136 - resolveMultiple: false  
137 - } 130 + filter: dashboardUtils.createSingleEntityFilter(entityType, entityId)
138 }; 131 };
139 itembuffer.addWidgetToDashboard(theDashboard, targetState, targetLayout, vm.widget, aliasesInfo, null, 48, null, -1, -1).then( 132 itembuffer.addWidgetToDashboard(theDashboard, targetState, targetLayout, vm.widget, aliasesInfo, null, 48, null, -1, -1).then(
140 function(theDashboard) { 133 function(theDashboard) {
@@ -26,10 +26,12 @@ import editAttributeValueTemplate from './edit-attribute-value.tpl.html'; @@ -26,10 +26,12 @@ import editAttributeValueTemplate from './edit-attribute-value.tpl.html';
26 /* eslint-enable import/no-unresolved, import/default */ 26 /* eslint-enable import/no-unresolved, import/default */
27 27
28 import EditAttributeValueController from './edit-attribute-value.controller'; 28 import EditAttributeValueController from './edit-attribute-value.controller';
  29 +import AliasController from '../../api/alias-controller';
29 30
30 /*@ngInject*/ 31 /*@ngInject*/
31 export default function AttributeTableDirective($compile, $templateCache, $rootScope, $q, $mdEditDialog, $mdDialog, 32 export default function AttributeTableDirective($compile, $templateCache, $rootScope, $q, $mdEditDialog, $mdDialog,
32 - $document, $translate, $filter, utils, types, dashboardService, attributeService, widgetService) { 33 + $mdUtil, $document, $translate, $filter, utils, types, dashboardUtils,
  34 + dashboardService, entityService, attributeService, widgetService) {
33 35
34 var linker = function (scope, element, attrs) { 36 var linker = function (scope, element, attrs) {
35 37
@@ -246,15 +248,19 @@ export default function AttributeTableDirective($compile, $templateCache, $rootS @@ -246,15 +248,19 @@ export default function AttributeTableDirective($compile, $templateCache, $rootS
246 } 248 }
247 249
248 scope.nextWidget = function() { 250 scope.nextWidget = function() {
249 - if (scope.widgetsCarousel.index < scope.widgetsList.length-1) {  
250 - scope.widgetsCarousel.index++;  
251 - } 251 + $mdUtil.nextTick(function () {
  252 + if (scope.widgetsCarousel.index < scope.widgetsList.length - 1) {
  253 + scope.widgetsCarousel.index++;
  254 + }
  255 + });
252 } 256 }
253 257
254 scope.prevWidget = function() { 258 scope.prevWidget = function() {
255 - if (scope.widgetsCarousel.index > 0) {  
256 - scope.widgetsCarousel.index--;  
257 - } 259 + $mdUtil.nextTick(function () {
  260 + if (scope.widgetsCarousel.index > 0) {
  261 + scope.widgetsCarousel.index--;
  262 + }
  263 + });
258 } 264 }
259 265
260 scope.enterWidgetMode = function() { 266 scope.enterWidgetMode = function() {
@@ -281,23 +287,28 @@ export default function AttributeTableDirective($compile, $templateCache, $rootS @@ -281,23 +287,28 @@ export default function AttributeTableDirective($compile, $templateCache, $rootS
281 scope.firstBundle = true; 287 scope.firstBundle = true;
282 scope.selectedWidgetsBundleAlias = types.systemBundleAlias.cards; 288 scope.selectedWidgetsBundleAlias = types.systemBundleAlias.cards;
283 289
284 - scope.aliasesInfo = {  
285 - entityAliases: {  
286 - '1': {alias: scope.entityName, entityType: scope.entityType, entityId: scope.entityId}  
287 - },  
288 - entityAliasesInfo: {  
289 - '1': [  
290 - {name: scope.entityName, entityType: scope.entityType, id: scope.entityId}  
291 - ] 290 + var entityAlias = {
  291 + id: utils.guid(),
  292 + alias: scope.entityName,
  293 + filter: dashboardUtils.createSingleEntityFilter(scope.entityType, scope.entityId)
  294 + };
  295 + var entitiAliases = {};
  296 + entitiAliases[entityAlias.id] = entityAlias;
  297 +
  298 + var stateController = {
  299 + getStateParams: function() {
  300 + return {};
292 } 301 }
293 }; 302 };
  303 + scope.aliasController = new AliasController(scope, $q, $filter, utils,
  304 + types, entityService, stateController, entitiAliases);
294 305
295 var dataKeyType = scope.attributeScope === types.latestTelemetry ? 306 var dataKeyType = scope.attributeScope === types.latestTelemetry ?
296 types.dataKeyType.timeseries : types.dataKeyType.attribute; 307 types.dataKeyType.timeseries : types.dataKeyType.attribute;
297 308
298 var datasource = { 309 var datasource = {
299 type: types.datasourceType.entity, 310 type: types.datasourceType.entity,
300 - entityAliasId: '1', 311 + entityAliasId: entityAlias.id,
301 dataKeys: [] 312 dataKeys: []
302 } 313 }
303 var i = 0; 314 var i = 0;
@@ -156,7 +156,7 @@ @@ -156,7 +156,7 @@
156 rn-swipe-disabled="true"> 156 rn-swipe-disabled="true">
157 <li ng-repeat="widgets in widgetsList"> 157 <li ng-repeat="widgets in widgetsList">
158 <tb-dashboard 158 <tb-dashboard
159 - aliases-info="aliasesInfo" 159 + alias-controller="aliasController"
160 widgets="widgets" 160 widgets="widgets"
161 get-st-diff="getServerTimeDiff()" 161 get-st-diff="getServerTimeDiff()"
162 columns="20" 162 columns="20"
@@ -113,12 +113,7 @@ export default function EntityAliasesController(utils, entityService, toast, $sc @@ -113,12 +113,7 @@ export default function EntityAliasesController(utils, entityService, toast, $sc
113 } 113 }
114 114
115 function addAlias() { 115 function addAlias() {
116 - var aliasId = 0;  
117 - for (var a in vm.entityAliases) {  
118 - aliasId = Math.max(vm.entityAliases[a].id, aliasId);  
119 - }  
120 - aliasId++;  
121 - var entityAlias = {id: aliasId, alias: '', filter: {}, changed: false}; 116 + var entityAlias = {id: utils.guid(), alias: '', filter: {}, changed: false};
122 vm.entityAliases.push(entityAlias); 117 vm.entityAliases.push(entityAlias);
123 } 118 }
124 119
@@ -162,23 +157,21 @@ export default function EntityAliasesController(utils, entityService, toast, $sc @@ -162,23 +157,21 @@ export default function EntityAliasesController(utils, entityService, toast, $sc
162 var uniqueAliasList = {}; 157 var uniqueAliasList = {};
163 158
164 var valid = true; 159 var valid = true;
165 - var aliasId, maxAliasId; 160 + var aliasId;
166 var alias; 161 var alias;
167 var i; 162 var i;
168 163
169 if (vm.isSingleEntityAlias) { 164 if (vm.isSingleEntityAlias) {
170 - maxAliasId = 0; 165 + if (!vm.singleEntityAlias.id) {
  166 + vm.singleEntityAlias.id = utils.guid();
  167 + }
171 for (i = 0; i < vm.entityAliases.length; i ++) { 168 for (i = 0; i < vm.entityAliases.length; i ++) {
172 - aliasId = vm.entityAliases[i].id;  
173 alias = vm.entityAliases[i].alias; 169 alias = vm.entityAliases[i].alias;
174 if (alias === vm.singleEntityAlias.alias) { 170 if (alias === vm.singleEntityAlias.alias) {
175 valid = false; 171 valid = false;
176 break; 172 break;
177 } 173 }
178 - maxAliasId = Math.max(aliasId, maxAliasId);  
179 } 174 }
180 - maxAliasId++;  
181 - vm.singleEntityAlias.id = maxAliasId;  
182 } else { 175 } else {
183 for (i = 0; i < vm.entityAliases.length; i++) { 176 for (i = 0; i < vm.entityAliases.length; i++) {
184 aliasId = vm.entityAliases[i].id; 177 aliasId = vm.entityAliases[i].id;
@@ -18,11 +18,20 @@ @@ -18,11 +18,20 @@
18 .md-dialog-content { 18 .md-dialog-content {
19 padding-bottom: 0px; 19 padding-bottom: 0px;
20 } 20 }
  21 + .tb-aliases-header {
  22 + min-height: 40px;
  23 + padding: 0 34px 0 34px;
  24 + margin: 5px;
  25 + .tb-header-label {
  26 + font-size: 14px;
  27 + color: rgba(0, 0, 0, 0.570588);
  28 + }
  29 + }
21 .tb-alias { 30 .tb-alias {
22 - padding: 10px 0 0 10px; 31 + padding: 0 0 0 10px;
23 margin: 5px; 32 margin: 5px;
24 - md-select.tb-entity-type-select {  
25 - padding-bottom: 24px; 33 + md-input-container {
  34 + margin: 0px;
26 } 35 }
27 } 36 }
28 } 37 }
@@ -28,23 +28,28 @@ @@ -28,23 +28,28 @@
28 </md-toolbar> 28 </md-toolbar>
29 <md-progress-linear class="md-warn" md-mode="indeterminate" ng-disabled="!loading" ng-show="loading"></md-progress-linear> 29 <md-progress-linear class="md-warn" md-mode="indeterminate" ng-disabled="!loading" ng-show="loading"></md-progress-linear>
30 <span style="min-height: 5px;" flex="" ng-show="!loading"></span> 30 <span style="min-height: 5px;" flex="" ng-show="!loading"></span>
  31 + <div class="tb-aliases-header" ng-show="!vm.isSingleEntityAlias" flex layout="row" layout-align="start center">
  32 + <span flex="5"></span>
  33 + <div flex layout="row" layout-align="start center">
  34 + <span class="tb-header-label" translate flex="20" style="min-width: 150px;">entity.alias</span>
  35 + <div flex="80" layout="row" layout-align="start center" style="min-width: 240px; padding-left: 10px;">
  36 + <span class="tb-header-label" translate flex="70">alias.entity-filter</span>
  37 + <span class="tb-header-label" translate flex="30" style="padding-left: 10px;" >alias.resolve-multiple</span>
  38 + </div>
  39 + <span style="min-width: 40px; margin: 0 6px;"></span>
  40 + </div>
  41 + </div>
  42 + <md-divider ng-show="!vm.isSingleEntityAlias"></md-divider>
31 <md-dialog-content> 43 <md-dialog-content>
32 <div class="md-dialog-content"> 44 <div class="md-dialog-content">
33 <fieldset ng-disabled="loading"> 45 <fieldset ng-disabled="loading">
34 <div ng-show="vm.isSingleEntityAlias" layout="row"> 46 <div ng-show="vm.isSingleEntityAlias" layout="row">
35 - <tb-entity-filter flex allowed-entity-types="vm.allowedEntityTypes" ng-model="vm.singleEntityAlias.filter"> 47 + <tb-entity-filter flex
  48 + allowed-entity-types="vm.allowedEntityTypes"
  49 + ng-model="vm.singleEntityAlias.filter">
36 </tb-entity-filter> 50 </tb-entity-filter>
37 </div> 51 </div>
38 - <div ng-show="!vm.isSingleEntityAlias" flex layout="row" layout-align="start center">  
39 - <span flex="5"></span>  
40 - <div flex layout="row" layout-align="start center"  
41 - style="padding: 0 0 0 10px; margin: 5px;">  
42 - <span translate flex="20" style="min-width: 150px;">entity.alias</span>  
43 - <span translate flex="80" style="min-width: 240px; padding-left: 10px;">alias.entity-filter</span>  
44 - <span style="min-width: 40px;"></span>  
45 - </div>  
46 - </div>  
47 - <div ng-show="!vm.isSingleEntityAlias" style="max-height: 500px; overflow: auto; padding-bottom: 20px;"> 52 + <div ng-show="!vm.isSingleEntityAlias" style="height: 100%; overflow: auto; padding-bottom: 20px;">
48 <div ng-form name="aliasForm" flex layout="row" layout-align="start center" ng-repeat="entityAlias in vm.entityAliases track by $index"> 53 <div ng-form name="aliasForm" flex layout="row" layout-align="start center" ng-repeat="entityAlias in vm.entityAliases track by $index">
49 <span flex="5">{{$index + 1}}.</span> 54 <span flex="5">{{$index + 1}}.</span>
50 <div class="md-whiteframe-4dp tb-alias" flex layout="row" layout-align="start center"> 55 <div class="md-whiteframe-4dp tb-alias" flex layout="row" layout-align="start center">
@@ -54,13 +59,12 @@ @@ -54,13 +59,12 @@
54 <div translate ng-message="required">entity.alias-required</div> 59 <div translate ng-message="required">entity.alias-required</div>
55 </div> 60 </div>
56 </md-input-container> 61 </md-input-container>
57 - <section flex="80" layout="column">  
58 - <tb-entity-filter style="padding-left: 10px;"  
59 - allowed-entity-types="vm.allowedEntityTypes"  
60 - ng-model="entityAlias.filter"  
61 - on-matching-entity-change="vm.onFilterEntityChanged(entity, stateEntity, entityAlias)">  
62 - </tb-entity-filter>  
63 - </section> 62 + <tb-entity-filter flex="80" style="min-width: 240px; padding-left: 10px;"
  63 + hide-labels
  64 + allowed-entity-types="vm.allowedEntityTypes"
  65 + ng-model="entityAlias.filter"
  66 + on-matching-entity-change="vm.onFilterEntityChanged(entity, stateEntity, entityAlias)">
  67 + </tb-entity-filter>
64 <md-button ng-disabled="loading" class="md-icon-button md-primary" style="min-width: 40px;" 68 <md-button ng-disabled="loading" class="md-icon-button md-primary" style="min-width: 40px;"
65 ng-click="vm.removeAlias($event, entityAlias)" aria-label="{{ 'action.remove' | translate }}"> 69 ng-click="vm.removeAlias($event, entityAlias)" aria-label="{{ 'action.remove' | translate }}">
66 <md-tooltip md-direction="top"> 70 <md-tooltip md-direction="top">
@@ -73,18 +77,18 @@ @@ -73,18 +77,18 @@
73 </div> 77 </div>
74 </div> 78 </div>
75 </div> 79 </div>
76 - <div ng-show="!vm.isSingleEntityAlias && !vm.disableAdd" style="padding-bottom: 10px;">  
77 - <md-button ng-disabled="loading" class="md-primary md-raised" ng-click="vm.addAlias($event)" aria-label="{{ 'action.add' | translate }}">  
78 - <md-tooltip md-direction="top">  
79 - {{ 'entity.add-alias' | translate }}  
80 - </md-tooltip>  
81 - <span translate>action.add</span>  
82 - </md-button>  
83 - </div>  
84 </fieldset> 80 </fieldset>
85 </div> 81 </div>
86 </md-dialog-content> 82 </md-dialog-content>
87 <md-dialog-actions layout="row"> 83 <md-dialog-actions layout="row">
  84 + <md-button ng-show="!vm.isSingleEntityAlias && !vm.disableAdd" ng-disabled="loading" class="md-primary md-raised"
  85 + ng-click="vm.addAlias($event)"
  86 + aria-label="{{ 'action.add' | translate }}">
  87 + <md-tooltip md-direction="top">
  88 + {{ 'entity.add-alias' | translate }}
  89 + </md-tooltip>
  90 + <span translate>action.add</span>
  91 + </md-button>
88 <span flex></span> 92 <span flex></span>
89 <md-button ng-disabled="loading || theForm.$invalid || !theForm.$dirty" type="submit" class="md-raised md-primary"> 93 <md-button ng-disabled="loading || theForm.$invalid || !theForm.$dirty" type="submit" class="md-raised md-primary">
90 {{ 'action.save' | translate }} 94 {{ 'action.save' | translate }}
@@ -35,46 +35,16 @@ export default function EntityFilterDirective($compile, $templateCache, $q, $doc @@ -35,46 +35,16 @@ export default function EntityFilterDirective($compile, $templateCache, $q, $doc
35 35
36 scope.ngModelCtrl = ngModelCtrl; 36 scope.ngModelCtrl = ngModelCtrl;
37 scope.types = types; 37 scope.types = types;
38 -  
39 - /* scope.fetchEntities = function(searchText, limit) {  
40 - var deferred = $q.defer();  
41 - entityService.getEntitiesByNameFilter(scope.entityType, searchText, limit).then(function success(result) {  
42 - if (result) {  
43 - deferred.resolve(result);  
44 - } else {  
45 - deferred.resolve([]);  
46 - }  
47 - }, function fail() {  
48 - deferred.reject();  
49 - });  
50 - return deferred.promise;  
51 - }*/ 38 + scope.hideLabels = angular.isDefined(attrs.hideLabels);
52 39
53 scope.updateValidity = function() { 40 scope.updateValidity = function() {
54 if (ngModelCtrl.$viewValue) { 41 if (ngModelCtrl.$viewValue) {
55 var value = ngModelCtrl.$viewValue; 42 var value = ngModelCtrl.$viewValue;
56 ngModelCtrl.$setValidity('filter', value.type ? true : false); 43 ngModelCtrl.$setValidity('filter', value.type ? true : false);
57 - /*if (value.useFilter) {  
58 - ngModelCtrl.$setValidity('entityList', true);  
59 - if (angular.isDefined(value.entityNameFilter) && value.entityNameFilter.length > 0) {  
60 - ngModelCtrl.$setValidity('entityNameFilter', true);  
61 - valid = angular.isDefined(scope.model.matchingFilterEntity) && scope.model.matchingFilterEntity != null;  
62 - ngModelCtrl.$setValidity('entityNameFilterEntityMatch', valid);  
63 - } else {  
64 - ngModelCtrl.$setValidity('entityNameFilter', false);  
65 - }  
66 - } else {  
67 - ngModelCtrl.$setValidity('entityNameFilter', true);  
68 - ngModelCtrl.$setValidity('entityNameFilterDeviceMatch', true);  
69 - valid = angular.isDefined(value.entityList) && value.entityList.length > 0;  
70 - ngModelCtrl.$setValidity('entityList', valid);  
71 - }*/  
72 -  
73 } 44 }
74 } 45 }
75 46
76 ngModelCtrl.$render = function () { 47 ngModelCtrl.$render = function () {
77 - //destroyWatchers();  
78 if (ngModelCtrl.$viewValue) { 48 if (ngModelCtrl.$viewValue) {
79 scope.model = angular.copy(ngModelCtrl.$viewValue); 49 scope.model = angular.copy(ngModelCtrl.$viewValue);
80 } else { 50 } else {
@@ -83,28 +53,6 @@ export default function EntityFilterDirective($compile, $templateCache, $q, $doc @@ -83,28 +53,6 @@ export default function EntityFilterDirective($compile, $templateCache, $q, $doc
83 resolveMultiple: false 53 resolveMultiple: false
84 } 54 }
85 } 55 }
86 - /* if (ngModelCtrl.$viewValue) {  
87 - var value = ngModelCtrl.$viewValue;  
88 - var model = scope.model;  
89 - model.useFilter = value.useFilter === true ? true: false;  
90 - model.entityList = [];  
91 - model.entityNameFilter = value.entityNameFilter || '';  
92 - processEntityNameFilter(model.entityNameFilter).then(  
93 - function(entity) {  
94 - scope.model.matchingFilterEntity = entity;  
95 - if (value.entityList && value.entityList.length > 0) {  
96 - entityService.getEntities(scope.entityType, value.entityList).then(function (entities) {  
97 - model.entityList = entities;  
98 - updateMatchingEntity();  
99 - initWatchers();  
100 - });  
101 - } else {  
102 - updateMatchingEntity();  
103 - initWatchers();  
104 - }  
105 - }  
106 - )  
107 - }*/  
108 } 56 }
109 57
110 scope.$watch('model.resolveMultiple', function () { 58 scope.$watch('model.resolveMultiple', function () {
@@ -149,115 +97,6 @@ export default function EntityFilterDirective($compile, $templateCache, $q, $doc @@ -149,115 +97,6 @@ export default function EntityFilterDirective($compile, $templateCache, $q, $doc
149 }); 97 });
150 } 98 }
151 99
152 - /* function updateMatchingEntity() {  
153 - if (scope.model.useFilter) {  
154 - scope.model.matchingEntity = scope.model.matchingFilterEntity;  
155 - } else {  
156 - if (scope.model.entityList && scope.model.entityList.length > 0) {  
157 - scope.model.matchingEntity = scope.model.entityList[0];  
158 - } else {  
159 - scope.model.matchingEntity = null;  
160 - }  
161 - }  
162 - }  
163 -  
164 - function processEntityNameFilter(entityNameFilter) {  
165 - var deferred = $q.defer();  
166 - if (angular.isDefined(entityNameFilter) && entityNameFilter.length > 0) {  
167 - scope.fetchEntities(entityNameFilter, 1).then(function (entities) {  
168 - if (entities && entities.length > 0) {  
169 - deferred.resolve(entities[0]);  
170 - } else {  
171 - deferred.resolve(null);  
172 - }  
173 - });  
174 - } else {  
175 - deferred.resolve(null);  
176 - }  
177 - return deferred.promise;  
178 - }  
179 -  
180 - function destroyWatchers() {  
181 - if (scope.entityTypeDeregistration) {  
182 - scope.entityTypeDeregistration();  
183 - scope.entityTypeDeregistration = null;  
184 - }  
185 - if (scope.entityListDeregistration) {  
186 - scope.entityListDeregistration();  
187 - scope.entityListDeregistration = null;  
188 - }  
189 - if (scope.useFilterDeregistration) {  
190 - scope.useFilterDeregistration();  
191 - scope.useFilterDeregistration = null;  
192 - }  
193 - if (scope.entityNameFilterDeregistration) {  
194 - scope.entityNameFilterDeregistration();  
195 - scope.entityNameFilterDeregistration = null;  
196 - }  
197 - if (scope.matchingEntityDeregistration) {  
198 - scope.matchingEntityDeregistration();  
199 - scope.matchingEntityDeregistration = null;  
200 - }  
201 - }  
202 -  
203 - function initWatchers() {  
204 -  
205 - scope.entityTypeDeregistration = scope.$watch('entityType', function (newEntityType, prevEntityType) {  
206 - if (!angular.equals(newEntityType, prevEntityType)) {  
207 - scope.model.entityList = [];  
208 - scope.model.entityNameFilter = '';  
209 - }  
210 - });  
211 -  
212 - scope.entityListDeregistration = scope.$watch('model.entityList', function () {  
213 - if (ngModelCtrl.$viewValue) {  
214 - var value = ngModelCtrl.$viewValue;  
215 - value.entityList = [];  
216 - if (scope.model.entityList && scope.model.entityList.length > 0) {  
217 - for (var i=0;i<scope.model.entityList.length;i++) {  
218 - value.entityList.push(scope.model.entityList[i].id.id);  
219 - }  
220 - }  
221 - updateMatchingEntity();  
222 - ngModelCtrl.$setViewValue(value);  
223 - scope.updateValidity();  
224 - }  
225 - }, true);  
226 - scope.useFilterDeregistration = scope.$watch('model.useFilter', function () {  
227 - if (ngModelCtrl.$viewValue) {  
228 - var value = ngModelCtrl.$viewValue;  
229 - value.useFilter = scope.model.useFilter;  
230 - updateMatchingEntity();  
231 - ngModelCtrl.$setViewValue(value);  
232 - scope.updateValidity();  
233 - }  
234 - });  
235 - scope.entityNameFilterDeregistration = scope.$watch('model.entityNameFilter', function (newNameFilter, prevNameFilter) {  
236 - if (ngModelCtrl.$viewValue) {  
237 - if (!angular.equals(newNameFilter, prevNameFilter)) {  
238 - var value = ngModelCtrl.$viewValue;  
239 - value.entityNameFilter = scope.model.entityNameFilter;  
240 - processEntityNameFilter(value.entityNameFilter).then(  
241 - function(entity) {  
242 - scope.model.matchingFilterEntity = entity;  
243 - updateMatchingEntity();  
244 - ngModelCtrl.$setViewValue(value);  
245 - scope.updateValidity();  
246 - }  
247 - );  
248 - }  
249 - }  
250 - });  
251 -  
252 - scope.matchingEntityDeregistration = scope.$watch('model.matchingEntity', function (newMatchingEntity, prevMatchingEntity) {  
253 - if (!angular.equals(newMatchingEntity, prevMatchingEntity)) {  
254 - if (scope.onMatchingEntityChange) {  
255 - scope.onMatchingEntityChange({entity: newMatchingEntity});  
256 - }  
257 - }  
258 - });  
259 - }*/  
260 -  
261 $compile(element.contents())(scope); 100 $compile(element.contents())(scope);
262 101
263 } 102 }
@@ -14,18 +14,6 @@ @@ -14,18 +14,6 @@
14 * limitations under the License. 14 * limitations under the License.
15 */ 15 */
16 .tb-entity-filter { 16 .tb-entity-filter {
17 - #entity_list_chips {  
18 - .md-chips {  
19 - padding-bottom: 1px;  
20 - }  
21 - }  
22 - .entity-name-filter-input {  
23 - margin-top: 10px;  
24 - margin-bottom: 0px;  
25 - .md-errors-spacer {  
26 - min-height: 0px;  
27 - }  
28 - }  
29 .tb-filter-switch { 17 .tb-filter-switch {
30 padding-left: 10px; 18 padding-left: 10px;
31 .filter-switch { 19 .filter-switch {
@@ -39,7 +27,8 @@ @@ -39,7 +27,8 @@
39 margin-top: -11px; 27 margin-top: -11px;
40 height: 35px; 28 height: 35px;
41 .tb-error-message { 29 .tb-error-message {
42 - padding-left: 1px; 30 + padding-left: 8px;
  31 + padding-top: 14px;
43 } 32 }
44 } 33 }
45 } 34 }
@@ -15,80 +15,37 @@ @@ -15,80 +15,37 @@
15 limitations under the License. 15 limitations under the License.
16 16
17 --> 17 -->
18 -<section layout='column' class="tb-entity-filter">  
19 - <section layout='row'>  
20 - <!--section layout="column" flex ng-show="!model.useFilter">  
21 - <md-chips flex  
22 - id="entity_list_chips"  
23 - ng-required="!useFilter"  
24 - ng-model="model.entityList" md-autocomplete-snap  
25 - md-require-match="true">  
26 - <md-autocomplete  
27 - md-no-cache="true"  
28 - id="entity"  
29 - md-selected-item="selectedEntity"  
30 - md-search-text="entitySearchText"  
31 - md-items="item in fetchEntities(entitySearchText, 10)"  
32 - md-item-text="item.name"  
33 - md-min-length="0"  
34 - placeholder="{{ 'entity.entity-list' | translate }}">  
35 - <md-item-template>  
36 - <span md-highlight-text="entitySearchText" md-highlight-flags="^i">{{item.name}}</span>  
37 - </md-item-template>  
38 - <md-not-found>  
39 - <span translate translate-values='{ entity: entitySearchText }'>entity.no-entities-matching</span>  
40 - </md-not-found>  
41 - </md-autocomplete>  
42 - <md-chip-template>  
43 - <span>  
44 - <strong>{{$chip.name}}</strong>  
45 - </span>  
46 - </md-chip-template>  
47 - </md-chips>  
48 - </section>  
49 - <section layout="row" flex ng-show="model.useFilter">  
50 - <md-input-container flex class="entity-name-filter-input">  
51 - <label translate>entity.name-starts-with</label>  
52 - <input ng-model="model.entityNameFilter" aria-label="{{ 'entity.name-starts-with' | translate }}">  
53 - </md-input-container>  
54 - </section-->  
55 - <section layout="row" flex layout-align="start center">  
56 - <div flex ng-if="model.type">{{ types.aliasFilterType[model.type].name | translate }}</div>  
57 - <md-button ng-if="model.type" ng-disabled="loading" class="md-icon-button md-primary"  
58 - style="min-width: 40px;"  
59 - ng-click="editFilter($event)"  
60 - aria-label="{{ 'alias.edit-entity-filter' | translate }}">  
61 - <md-tooltip md-direction="top">  
62 - {{ 'alias.edit-entity-filter' | translate }}  
63 - </md-tooltip>  
64 - <md-icon aria-label="{{ 'alias.edit-entity-filter' | translate }}" 18 +<section layout='row' class="tb-entity-filter">
  19 + <section layout="row" flex="70">
  20 + <section flex layout="column" layout-align="center start">
  21 + <div ng-if="model.type">{{ types.aliasFilterType[model.type].name | translate }}</div>
  22 + <md-button ng-if="!model.type"
  23 + ng-disabled="loading" class="md-primary"
  24 + ng-click="createFilter($event)"
  25 + aria-label="{{ 'alias.create-entity-filter' | translate }}">
  26 + <md-icon aria-label="{{ 'alias.create-entity-filter' | translate }}"
65 class="material-icons"> 27 class="material-icons">
66 - edit 28 + add
67 </md-icon> 29 </md-icon>
  30 + {{ 'alias.create-entity-filter' | translate }}
68 </md-button> 31 </md-button>
69 - <div ng-if="!model.type" layout="row" layout-align="center start">  
70 - <md-button ng-disabled="loading" class="md-primary md-raised"  
71 - ng-click="createFilter($event)"  
72 - aria-label="{{ 'alias.create-entity-filter' | translate }}">  
73 - <md-icon aria-label="{{ 'alias.create-entity-filter' | translate }}"  
74 - class="material-icons">  
75 - add  
76 - </md-icon>  
77 - {{ 'alias.create-entity-filter' | translate }}  
78 - </md-button>  
79 - </div>  
80 - </section>  
81 - <section class="tb-filter-switch" layout="column" layout-align="center center">  
82 - <label class="tb-small filter-label" translate>alias.resolve-multiple</label>  
83 - <md-switch class="filter-switch" ng-model="model.resolveMultiple" aria-label="resolve-multiple-switcher">  
84 - </md-switch>  
85 </section> 32 </section>
  33 + <md-button ng-if="model.type" ng-disabled="loading" class="md-icon-button md-primary"
  34 + style="min-width: 40px;"
  35 + ng-click="editFilter($event)"
  36 + aria-label="{{ 'alias.edit-entity-filter' | translate }}">
  37 + <md-tooltip md-direction="top">
  38 + {{ 'alias.edit-entity-filter' | translate }}
  39 + </md-tooltip>
  40 + <md-icon aria-label="{{ 'alias.edit-entity-filter' | translate }}"
  41 + class="material-icons">
  42 + edit
  43 + </md-icon>
  44 + </md-button>
  45 + </section>
  46 + <section class="tb-filter-switch" layout="column" flex="30" layout-align="center center">
  47 + <label ng-if="!hideLabels" class="tb-small filter-label" translate>alias.resolve-multiple</label>
  48 + <md-switch class="filter-switch" ng-model="model.resolveMultiple" aria-label="resolve-multiple-switcher">
  49 + </md-switch>
86 </section> 50 </section>
87 - <div class="tb-error-messages" ng-messages="ngModelCtrl.$error" role="alert">  
88 - <div translate ng-message="filter" class="tb-error-message">alias.entity-filter-required</div>  
89 - <!--div translate ng-message="entityList" class="tb-error-message">entity.entity-list-empty</div>  
90 - <div translate ng-message="entityNameFilter" class="tb-error-message">entity.entity-name-filter-required</div>  
91 - <div translate translate-values='{ entity: model.entityNameFilter }' ng-message="entityNameFilterEntityMatch"  
92 - class="tb-error-message">entity.entity-name-filter-no-entity-matched</div-->  
93 - </div>  
94 -</section>  
  51 +</section>
@@ -24,7 +24,7 @@ import entityAliasesTemplate from '../entity/entity-aliases.tpl.html'; @@ -24,7 +24,7 @@ import entityAliasesTemplate from '../entity/entity-aliases.tpl.html';
24 /* eslint-disable no-undef, angular/window-service, angular/document-service */ 24 /* eslint-disable no-undef, angular/window-service, angular/document-service */
25 25
26 /*@ngInject*/ 26 /*@ngInject*/
27 -export default function ImportExport($log, $translate, $q, $mdDialog, $document, itembuffer, types, dashboardUtils, 27 +export default function ImportExport($log, $translate, $q, $mdDialog, $document, itembuffer, utils, types, dashboardUtils,
28 entityService, dashboardService, pluginService, ruleService, widgetService, toast) { 28 entityService, dashboardService, pluginService, ruleService, widgetService, toast) {
29 29
30 30
@@ -415,6 +415,7 @@ export default function ImportExport($log, $translate, $q, $mdDialog, $document, @@ -415,6 +415,7 @@ export default function ImportExport($log, $translate, $q, $mdDialog, $document,
415 deferred.reject(); 415 deferred.reject();
416 } else { 416 } else {
417 var widget = widgetItem.widget; 417 var widget = widgetItem.widget;
  418 + widget = dashboardUtils.validateAndUpdateWidget(widget);
418 var aliasesInfo = prepareAliasesInfo(widgetItem.aliasesInfo); 419 var aliasesInfo = prepareAliasesInfo(widgetItem.aliasesInfo);
419 var originalColumns = widgetItem.originalColumns; 420 var originalColumns = widgetItem.originalColumns;
420 var originalSize = widgetItem.originalSize; 421 var originalSize = widgetItem.originalSize;
@@ -425,22 +426,22 @@ export default function ImportExport($log, $translate, $q, $mdDialog, $document, @@ -425,22 +426,22 @@ export default function ImportExport($log, $translate, $q, $mdDialog, $document,
425 var entityAliases = {}; 426 var entityAliases = {};
426 var datasourceAliasesMap = {}; 427 var datasourceAliasesMap = {};
427 var targetDeviceAliasesMap = {}; 428 var targetDeviceAliasesMap = {};
428 - var aliasId = 1; 429 + var aliasId;
429 var datasourceIndex; 430 var datasourceIndex;
430 if (datasourceAliases) { 431 if (datasourceAliases) {
431 for (datasourceIndex in datasourceAliases) { 432 for (datasourceIndex in datasourceAliases) {
  433 + aliasId = utils.guid();
432 datasourceAliasesMap[aliasId] = datasourceIndex; 434 datasourceAliasesMap[aliasId] = datasourceIndex;
433 entityAliases[aliasId] = datasourceAliases[datasourceIndex]; 435 entityAliases[aliasId] = datasourceAliases[datasourceIndex];
434 entityAliases[aliasId].id = aliasId; 436 entityAliases[aliasId].id = aliasId;
435 - aliasId++;  
436 } 437 }
437 } 438 }
438 if (targetDeviceAliases) { 439 if (targetDeviceAliases) {
439 for (datasourceIndex in targetDeviceAliases) { 440 for (datasourceIndex in targetDeviceAliases) {
  441 + aliasId = utils.guid();
440 targetDeviceAliasesMap[aliasId] = datasourceIndex; 442 targetDeviceAliasesMap[aliasId] = datasourceIndex;
441 entityAliases[aliasId] = targetDeviceAliases[datasourceIndex]; 443 entityAliases[aliasId] = targetDeviceAliases[datasourceIndex];
442 entityAliases[aliasId].id = aliasId; 444 entityAliases[aliasId].id = aliasId;
443 - aliasId++;  
444 } 445 }
445 } 446 }
446 447
@@ -124,7 +124,7 @@ export default angular.module('thingsboard.locale', []) @@ -124,7 +124,7 @@ export default angular.module('thingsboard.locale', [])
124 "create-entity-filter": "Create entity filter", 124 "create-entity-filter": "Create entity filter",
125 "edit-entity-filter": "Edit entity filter", 125 "edit-entity-filter": "Edit entity filter",
126 "entity-filter-required": "Entity filter is required.", 126 "entity-filter-required": "Entity filter is required.",
127 - "resolve-multiple": "Multiple", 127 + "resolve-multiple": "Resolve as multiple entities",
128 "filter-type": "Filter type", 128 "filter-type": "Filter type",
129 "filter-type-required": "Filter type is required.", 129 "filter-type-required": "Filter type is required.",
130 "use-state-entity": "Use state entity", 130 "use-state-entity": "Use state entity",
@@ -298,11 +298,7 @@ function ItemBuffer($q, bufferStore, types, utils, dashboardUtils) { @@ -298,11 +298,7 @@ function ItemBuffer($q, bufferStore, types, utils, dashboardUtils) {
298 } 298 }
299 if (!newAliasId) { 299 if (!newAliasId) {
300 var newAliasName = createEntityAliasName(entityAliases, aliasInfo.alias); 300 var newAliasName = createEntityAliasName(entityAliases, aliasInfo.alias);
301 - newAliasId = 0;  
302 - for (aliasId in entityAliases) {  
303 - newAliasId = Math.max(newAliasId, aliasId);  
304 - }  
305 - newAliasId++; 301 + newAliasId = utils.guid();
306 entityAliases[newAliasId] = {id: newAliasId, alias: newAliasName, filter: aliasInfo.filter}; 302 entityAliases[newAliasId] = {id: newAliasId, alias: newAliasName, filter: aliasInfo.filter};
307 } 303 }
308 return newAliasId; 304 return newAliasId;