diff --git a/ui/src/app/api/entity.service.js b/ui/src/app/api/entity.service.js
index 5ce4fd7108..51336ee374 100644
--- a/ui/src/app/api/entity.service.js
+++ b/ui/src/app/api/entity.service.js
@@ -848,7 +848,50 @@ function EntityService($http, $q, $filter, $translate, $log, userService, device
return deferred.promise;
}
+ function getEntityFieldKeys (entityType, searchText) {
+ let entityFieldKeys = [];
+ let query = searchText.toLowerCase();
+ switch(entityType) {
+ case types.entityType.user:
+ entityFieldKeys.push(types.entityField.name.keyName);
+ entityFieldKeys.push(types.entityField.email.keyName);
+ entityFieldKeys.push(types.entityField.firstName.keyName);
+ entityFieldKeys.push(types.entityField.lastName.keyName);
+ break;
+ case types.entityType.tenant:
+ case types.entityType.customer:
+ entityFieldKeys.push(types.entityField.title.keyName);
+ entityFieldKeys.push(types.entityField.email.keyName);
+ entityFieldKeys.push(types.entityField.country.keyName);
+ entityFieldKeys.push(types.entityField.state.keyName);
+ entityFieldKeys.push(types.entityField.city.keyName);
+ entityFieldKeys.push(types.entityField.address.keyName);
+ entityFieldKeys.push(types.entityField.address2.keyName);
+ entityFieldKeys.push(types.entityField.zip.keyName);
+ entityFieldKeys.push(types.entityField.phone.keyName);
+ break;
+ case types.entityType.entityView:
+ entityFieldKeys.push(types.entityField.name.keyName);
+ entityFieldKeys.push(types.entityField.type.keyName);
+ break;
+ case types.entityType.device:
+ case types.entityType.asset:
+ entityFieldKeys.push(types.entityField.name.keyName);
+ entityFieldKeys.push(types.entityField.type.keyName);
+ entityFieldKeys.push(types.entityField.label.keyName);
+ break;
+ case types.entityType.dashboard:
+ entityFieldKeys.push(types.entityField.title.keyName);
+ break;
+ }
+
+ return query ? entityFieldKeys.filter((entityField) => entityField.toLowerCase().indexOf(query) === 0) : entityFieldKeys;
+ }
+
function getEntityKeys(entityType, entityId, query, type, config) {
+ if (type === types.dataKeyType.entityField) {
+ return $q.when(getEntityFieldKeys(entityType, query));
+ }
var deferred = $q.defer();
var url = '/api/plugins/telemetry/' + entityType + '/' + entityId + '/keys/';
if (type === types.dataKeyType.timeseries) {
diff --git a/ui/src/app/api/subscription.js b/ui/src/app/api/subscription.js
index 4ad374bfe4..86ab823294 100644
--- a/ui/src/app/api/subscription.js
+++ b/ui/src/app/api/subscription.js
@@ -350,6 +350,11 @@ export default class Subscription {
dataKey: dataKey,
data: []
};
+ if (dataKey.type === this.ctx.types.dataKeyType.entityField) {
+ if(datasource.entity && datasource.entity[this.ctx.types.entityField[dataKey.name].value]){
+ datasourceData.data.push([Date.now(), datasource.entity[this.ctx.types.entityField[dataKey.name].value]]);
+ }
+ }
this.data.push(datasourceData);
this.hiddenData.push({data: []});
if (this.displayLegend) {
@@ -878,8 +883,14 @@ export default class Subscription {
};
}
+ var entityFieldKey = false;
+
for (var a = 0; a < datasource.dataKeys.length; a++) {
- this.data[index + a].data = [];
+ if (datasource.dataKeys[a].type !== this.ctx.types.dataKeyType.entityField) {
+ this.data[index + a].data = [];
+ } else {
+ entityFieldKey = true;
+ }
}
index += datasource.dataKeys.length;
@@ -891,7 +902,7 @@ export default class Subscription {
}
var forceUpdate = false;
- if (datasource.unresolvedStateEntity ||
+ if (datasource.unresolvedStateEntity || entityFieldKey ||
!datasource.dataKeys.length ||
(datasource.type === this.ctx.types.datasourceType.entity && !datasource.entityId)
) {
diff --git a/ui/src/app/app.config.js b/ui/src/app/app.config.js
index c38deae93b..d441d87d8b 100644
--- a/ui/src/app/app.config.js
+++ b/ui/src/app/app.config.js
@@ -78,7 +78,8 @@ export default function AppConfig($provide,
$mdIconProvider.iconSet('mdi', mdiIconSet);
ngMdIconServiceProvider
- .addShape('alpha-a-circle-outline', '');
+ .addShape('alpha-a-circle-outline', '')
+ .addShape('alpha-e-circle-outline', '');
configureTheme();
@@ -170,4 +171,4 @@ export default function AppConfig($provide,
return aliases;
}
-}
\ No newline at end of file
+}
diff --git a/ui/src/app/common/types.constant.js b/ui/src/app/common/types.constant.js
index e6e65bbecf..6b11af555f 100644
--- a/ui/src/app/common/types.constant.js
+++ b/ui/src/app/common/types.constant.js
@@ -322,7 +322,8 @@ export default angular.module('thingsboard.types', [])
timeseries: "timeseries",
attribute: "attribute",
function: "function",
- alarm: "alarm"
+ alarm: "alarm",
+ entityField: "entityField"
},
contentType: {
"JSON": {
@@ -467,6 +468,84 @@ export default angular.module('thingsboard.types', [])
list: 'entity.type-current-customer'
}
},
+ entityField: {
+ createdTime: {
+ keyName: 'createdTime',
+ name: 'entity-field.created-time',
+ value: 'createdTime',
+ time: true
+ },
+ name: {
+ keyName: 'name',
+ name: 'entity-field.name',
+ value: 'name'
+ },
+ type: {
+ keyName: 'type',
+ name: 'entity-field.type',
+ value: 'type'
+ },
+ firstName: {
+ keyName: 'firstName',
+ name: 'entity-field.first-name',
+ value: 'firstName'
+ },
+ lastName: {
+ keyName: 'lastName',
+ name: 'entity-field.last-name',
+ value: 'lastName'
+ },
+ email: {
+ keyName: 'email',
+ name: 'entity-field.email',
+ value: 'email'
+ },
+ title: {
+ keyName: 'title',
+ name: 'entity-field.title',
+ value: 'title'
+ },
+ country: {
+ keyName: 'country',
+ name: 'entity-field.country',
+ value: 'country'
+ },
+ state: {
+ keyName: 'state',
+ name: 'entity-field.state',
+ value: 'state'
+ },
+ city: {
+ keyName: 'city',
+ name: 'entity-field.city',
+ value: 'city'
+ },
+ address: {
+ keyName: 'address',
+ name: 'entity-field.address',
+ value: 'address'
+ },
+ address2: {
+ keyName: 'address2',
+ name: 'entity-field.address2',
+ value: 'address2'
+ },
+ zip: {
+ keyName: 'zip',
+ name: 'entity-field.zip',
+ value: 'zip'
+ },
+ phone: {
+ keyName: 'phone',
+ name: 'entity-field.phone',
+ value: 'phone'
+ },
+ label: {
+ keyName: 'label',
+ name: 'entity-field.label',
+ value: 'label'
+ }
+ },
entitySearchDirection: {
from: "FROM",
to: "TO"
diff --git a/ui/src/app/components/datakey-config.tpl.html b/ui/src/app/components/datakey-config.tpl.html
index 0b5b11d690..f8da179141 100644
--- a/ui/src/app/components/datakey-config.tpl.html
+++ b/ui/src/app/components/datakey-config.tpl.html
@@ -16,9 +16,7 @@
-->
-
-
\ No newline at end of file
+
diff --git a/ui/src/app/components/datasource-entity.directive.js b/ui/src/app/components/datasource-entity.directive.js
index 9ed05b8812..844e60e97e 100644
--- a/ui/src/app/components/datasource-entity.directive.js
+++ b/ui/src/app/components/datasource-entity.directive.js
@@ -124,7 +124,7 @@ function DatasourceEntity($compile, $templateCache, $q, $mdDialog, $window, $doc
var alarmDataKeys = [];
for (var d in ngModelCtrl.$viewValue.dataKeys) {
var dataKey = ngModelCtrl.$viewValue.dataKeys[d];
- if ((dataKey.type === types.dataKeyType.timeseries) || (dataKey.type === types.dataKeyType.attribute)) {
+ if ((dataKey.type === types.dataKeyType.timeseries) || (dataKey.type === types.dataKeyType.attribute) || (dataKey.type === types.dataKeyType.entityField)) {
dataKeys.push(dataKey);
} else if (dataKey.type === types.dataKeyType.alarm) {
alarmDataKeys.push(dataKey);
@@ -219,7 +219,7 @@ function DatasourceEntity($compile, $templateCache, $q, $mdDialog, $window, $doc
w.triggerHandler('resize');
}
}).then(function (newDataKey) {
- if ((newDataKey.type === types.dataKeyType.timeseries) || (newDataKey.type === types.dataKeyType.attribute)) {
+ if ((newDataKey.type === types.dataKeyType.timeseries) || (newDataKey.type === types.dataKeyType.attribute) || (newDataKey.type === types.dataKeyType.entityField)) {
let index = scope.dataKeys.indexOf(dataKey);
scope.dataKeys[index] = newDataKey;
} else if (newDataKey.type === types.dataKeyType.alarm) {
@@ -246,10 +246,16 @@ function DatasourceEntity($compile, $templateCache, $q, $mdDialog, $window, $doc
items.push({ name: dataKeys[i], type: types.dataKeyType.timeseries });
}
if (scope.widgetType == types.widgetType.latest.value) {
- scope.fetchEntityKeys({entityAliasId: scope.entityAlias.id, query: searchText, type: types.dataKeyType.attribute})
- .then(function (dataKeys) {
+ var keysType = [types.dataKeyType.attribute, types.dataKeyType.entityField];
+ var promises = [];
+ keysType.forEach((type) => {
+ promises.push(scope.fetchEntityKeys({entityAliasId: scope.entityAlias.id, query: searchText, type: type}));
+ });
+ $q.all(promises).then(function (dataKeys) {
for (var i = 0; i < dataKeys.length; i++) {
- items.push({ name: dataKeys[i], type: types.dataKeyType.attribute });
+ for (var j = 0; j < dataKeys[i].length; j++) {
+ items.push({name: dataKeys[i][j], type: keysType[i]});
+ }
}
deferred.resolve(items);
}, function (e) {
diff --git a/ui/src/app/components/datasource-entity.tpl.html b/ui/src/app/components/datasource-entity.tpl.html
index fe0d23eef7..a167d313ee 100644
--- a/ui/src/app/components/datasource-entity.tpl.html
+++ b/ui/src/app/components/datasource-entity.tpl.html
@@ -43,6 +43,10 @@
{{'datakey.attributes' | translate }}
+
+ {{'datakey.entityField' | translate }}
+
+
{{'datakey.timeseries' | translate }}
@@ -60,6 +64,10 @@
{{'datakey.attributes' | translate }}
+
+ {{'datakey.entityField' | translate }}
+
+
{{'datakey.timeseries' | translate }}
@@ -81,6 +89,10 @@
{{'datakey.attributes' | translate }}
+
+
+ {{'datakey.entityField' | translate }}
+
{{'datakey.timeseries' | translate }}
diff --git a/ui/src/app/components/widget/widget-config.directive.js b/ui/src/app/components/widget/widget-config.directive.js
index 470726a835..2fe97ce6d6 100644
--- a/ui/src/app/components/widget/widget-config.directive.js
+++ b/ui/src/app/components/widget/widget-config.directive.js
@@ -423,10 +423,10 @@ function WidgetConfig($compile, $templateCache, $rootScope, $translate, $timeout
}
var label = chip;
- if (type === types.dataKeyType.alarm) {
- var alarmField = types.alarmFields[chip];
- if (alarmField) {
- label = $translate.instant(alarmField.name)+'';
+ if (type === types.dataKeyType.alarm || type === types.dataKeyType.entityField) {
+ var keyField = type === types.dataKeyType.alarm ? types.alarmFields[chip] : types.entityField[chip];
+ if (keyField) {
+ label = $translate.instant(keyField.name)+'';
}
}
label = scope.genNextLabel(label);
diff --git a/ui/src/app/locale/locale.constant-el_GR.json b/ui/src/app/locale/locale.constant-el_GR.json
index b590c70e47..f3051e98c1 100644
--- a/ui/src/app/locale/locale.constant-el_GR.json
+++ b/ui/src/app/locale/locale.constant-el_GR.json
@@ -1102,6 +1102,22 @@
"copyId": "Αντιγραφή ID ομάδας οντοτήτων",
"idCopiedMessage": "Το ID της ομάδας οντοτήτων έχει αντιγραφεί στο πρόχειρο"
},
+ "entity-field": {
+ "created-time": "Δημιουργήθηκε",
+ "name": "Όνομα",
+ "type": "Τύπος",
+ "first-name": "Όνομα",
+ "last-name": "Επίθετο",
+ "email": "Email",
+ "title": "Τίτλος",
+ "country": "Χώρα",
+ "state": "Νομός",
+ "city": "Πόλη",
+ "address": "Διεύθυνση",
+ "address2": "Διεύθυνση 2",
+ "zip": "Τ.Κ.",
+ "phone": "Τηλέφωνο"
+ },
"entity-view": {
"entity-view": "Όψη Οντότητας",
"entity-view-required": "Απαιτείται προβολή οντότητας.",
@@ -2603,4 +2619,4 @@
"el_GR": "Ελληνικά"
}
}
-}
\ No newline at end of file
+}
diff --git a/ui/src/app/locale/locale.constant-en_US.json b/ui/src/app/locale/locale.constant-en_US.json
index 67f3fb09de..6310438128 100644
--- a/ui/src/app/locale/locale.constant-en_US.json
+++ b/ui/src/app/locale/locale.constant-en_US.json
@@ -815,6 +815,23 @@
"no-data": "No data to display",
"columns-to-display": "Columns to Display"
},
+ "entity-field": {
+ "created-time": "Created time",
+ "name": "Name",
+ "type": "Type",
+ "first-name": "First name",
+ "last-name": "Last name",
+ "email": "Email",
+ "title": "Title",
+ "country": "Country",
+ "state": "State",
+ "city": "City",
+ "address": "Address",
+ "address2": "Address 2",
+ "zip": "Zip",
+ "phone": "Phone",
+ "label": "Label"
+ },
"entity-view": {
"entity-view": "Entity View",
"entity-view-required": "Entity view is required.",
diff --git a/ui/src/app/locale/locale.constant-es_ES.json b/ui/src/app/locale/locale.constant-es_ES.json
index d3d1c4042f..5cebe22ef6 100644
--- a/ui/src/app/locale/locale.constant-es_ES.json
+++ b/ui/src/app/locale/locale.constant-es_ES.json
@@ -808,6 +808,22 @@
"no-data": "No hay datos para mostrar",
"columns-to-display": "Columnas a mostrar"
},
+ "entity-field": {
+ "created-time": "Tiempo de creación",
+ "name": "Nombre",
+ "type": "Tipo",
+ "first-name": "Nombre",
+ "last-name": "Apellido",
+ "email": "Correo electrónico",
+ "title": "Título",
+ "country": "País",
+ "state": "Estado",
+ "city": "Ciudad",
+ "address": "Dirección",
+ "address2": "Dirección 2",
+ "zip": "Código postal",
+ "phone": "Teléfono"
+ },
"entity-view": {
"entity-view": "Vista de entidad",
"entity-view-required": "Vista de entidad es requerido.",
diff --git a/ui/src/app/locale/locale.constant-fr_FR.json b/ui/src/app/locale/locale.constant-fr_FR.json
index b25a532927..5c922bfd49 100644
--- a/ui/src/app/locale/locale.constant-fr_FR.json
+++ b/ui/src/app/locale/locale.constant-fr_FR.json
@@ -809,6 +809,22 @@
"use-entity-name-filter": "Utiliser un filtre",
"user-name-starts-with": "Utilisateurs dont les noms commencent par '{{prefix}}'"
},
+ "entity-field": {
+ "address": "Adresse",
+ "address2": "Adresse 2",
+ "city": "Ville",
+ "country": "Pays",
+ "created-time": "Heure de création",
+ "email": "Email",
+ "first-name": "Prénom",
+ "last-name": "Nom de famille",
+ "name": "Nom",
+ "phone": "Téléphone",
+ "state": "Prov",
+ "title": "Titre",
+ "type": "Type",
+ "zip": "Code postal"
+ },
"entity-view": {
"add": "Ajouter une vue d'entité",
"add-alias": "Ajouter un alias de vue d'entité",
diff --git a/ui/src/app/locale/locale.constant-ru_RU.json b/ui/src/app/locale/locale.constant-ru_RU.json
index 3aaa3042c5..ca4570638a 100644
--- a/ui/src/app/locale/locale.constant-ru_RU.json
+++ b/ui/src/app/locale/locale.constant-ru_RU.json
@@ -814,6 +814,23 @@
"no-data": "Нет данных для отображения",
"columns-to-display": "Отобразить следующие колонки"
},
+ "entity-field": {
+ "created-time": "Время создания",
+ "name": "Название",
+ "type": "Тип",
+ "first-name": "Имя",
+ "last-name": "Фамилия",
+ "email": "Электронная почта",
+ "title": "Название",
+ "country": "Страна",
+ "state": "Штат/Область",
+ "city": "Город",
+ "address": "Адрес",
+ "address2": "Адрес 2",
+ "zip": "Индекс",
+ "phone": "Телефон",
+ "label": "Метка"
+ },
"entity-view": {
"entity-view": "Представление Объекта",
"entity-view-required": "Представление объекта обязательно.",
diff --git a/ui/src/app/locale/locale.constant-uk_UA.json b/ui/src/app/locale/locale.constant-uk_UA.json
index cbbaabd666..49fd45a409 100644
--- a/ui/src/app/locale/locale.constant-uk_UA.json
+++ b/ui/src/app/locale/locale.constant-uk_UA.json
@@ -956,6 +956,23 @@
"list-of-integrations": "{ count, plural, 1 {Одна інтеграція} other {Список # інтеграцій} }",
"integration-name-starts-with": "Інтеграції, імена яких починаються з '{{prefix}}'"
},
+ "entity-field": {
+ "created-time": "Час створення",
+ "name": "Ім'я",
+ "type": "Тип",
+ "first-name": "Ім'я",
+ "last-name": "Прізвище",
+ "email": "Електронна пошта",
+ "title": "Назва",
+ "country": "Країна",
+ "state": "Штат",
+ "city": "Місто",
+ "address": "Адреса",
+ "address2": "Адреса 2",
+ "zip": "Zip",
+ "phone": "Телефон",
+ "label": "Мітка"
+ },
"entity-group": {
"entity-group": "Група сутності",
"details": "Деталі",