Browse Source

TB-61: Improve Alias list editor.

pull/164/head
Igor Kulikov 9 years ago
parent
commit
43b23cef4f
  1. 4
      ui/src/app/api/alias-controller.js
  2. 103
      ui/src/app/api/subscription.js
  3. 85
      ui/src/app/common/dashboard-utils.service.js
  4. 11
      ui/src/app/common/utils.service.js
  5. 31
      ui/src/app/components/dashboard.directive.js
  6. 157
      ui/src/app/components/widget.controller.js
  7. 85
      ui/src/app/components/widget.directive.js
  8. 15
      ui/src/app/entity/aliases-entity-select-panel.controller.js
  9. 4
      ui/src/app/entity/aliases-entity-select-panel.tpl.html
  10. 8
      ui/src/app/entity/aliases-entity-select.directive.js
  11. 11
      ui/src/app/entity/attribute/add-widget-to-dashboard-dialog.controller.js
  12. 43
      ui/src/app/entity/attribute/attribute-table.directive.js
  13. 2
      ui/src/app/entity/attribute/attribute-table.tpl.html
  14. 17
      ui/src/app/entity/entity-aliases.controller.js
  15. 15
      ui/src/app/entity/entity-aliases.scss
  16. 56
      ui/src/app/entity/entity-aliases.tpl.html
  17. 163
      ui/src/app/entity/entity-filter.directive.js
  18. 15
      ui/src/app/entity/entity-filter.scss
  19. 101
      ui/src/app/entity/entity-filter.tpl.html
  20. 9
      ui/src/app/import-export/import-export.service.js
  21. 2
      ui/src/app/locale/locale.constant.js
  22. 6
      ui/src/app/services/item-buffer.service.js

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

103
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]);

85
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;

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

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

157
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

85
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);

15
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();
}
}
}

4
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>

8
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();
}

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

43
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;

2
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"

17
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;

15
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;
}
}
}

56
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 }}

163
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);
}

15
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;
}
}
}

101
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>
</section>

9
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++;
}
}

2
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",

6
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;

Loading…
Cancel
Save