diff --git a/application/pom.xml b/application/pom.xml index 72e7e7d7c2..c6503ef248 100644 --- a/application/pom.xml +++ b/application/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 2.1.2 + 2.1.3-SNAPSHOT thingsboard application diff --git a/application/src/main/resources/thingsboard.yml b/application/src/main/resources/thingsboard.yml index 5eef1bdda0..b889143122 100644 --- a/application/src/main/resources/thingsboard.yml +++ b/application/src/main/resources/thingsboard.yml @@ -165,9 +165,9 @@ quota: database: entities: - type: "${DATABASE_ENTITIES_TYPE:sql}" # cassandra OR sql + type: "${DATABASE_ENTITIES_TYPE:cassandra}" # cassandra OR sql ts: - type: "${DATABASE_TS_TYPE:sql}" # cassandra OR sql (for hybrid mode, only this value should be cassandra) + type: "${DATABASE_TS_TYPE:cassandra}" # cassandra OR sql (for hybrid mode, only this value should be cassandra) # Cassandra driver configuration parameters diff --git a/common/data/pom.xml b/common/data/pom.xml index aa68b1adf6..f25e78de0e 100644 --- a/common/data/pom.xml +++ b/common/data/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 2.1.2 + 2.1.3-SNAPSHOT common org.thingsboard.common diff --git a/common/message/pom.xml b/common/message/pom.xml index 4da27e28f6..67648e9c4d 100644 --- a/common/message/pom.xml +++ b/common/message/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 2.1.2 + 2.1.3-SNAPSHOT common org.thingsboard.common diff --git a/common/pom.xml b/common/pom.xml index 4ee5937e7a..aba6d7f3a9 100644 --- a/common/pom.xml +++ b/common/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 2.1.2 + 2.1.3-SNAPSHOT thingsboard org.thingsboard diff --git a/common/transport/pom.xml b/common/transport/pom.xml index efd63b5240..583fcd28f7 100644 --- a/common/transport/pom.xml +++ b/common/transport/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 2.1.2 + 2.1.3-SNAPSHOT common org.thingsboard.common diff --git a/dao/pom.xml b/dao/pom.xml index 8cc83e9393..e7d6783911 100644 --- a/dao/pom.xml +++ b/dao/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 2.1.2 + 2.1.3-SNAPSHOT thingsboard dao diff --git a/dao/src/main/java/org/thingsboard/server/dao/entityview/CassandraEntityViewDao.java b/dao/src/main/java/org/thingsboard/server/dao/entityview/CassandraEntityViewDao.java index fe1a8d1f8d..6ddc18d463 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/entityview/CassandraEntityViewDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/entityview/CassandraEntityViewDao.java @@ -84,8 +84,7 @@ public class CassandraEntityViewDao extends CassandraAbstractSearchTextDao>> futures = new ArrayList<>(); - if (savedEntityView.getKeys() != null) { + if (savedEntityView.getKeys() != null && savedEntityView.getKeys().getAttributes() != null) { futures.add(copyAttributesFromEntityToEntityView(savedEntityView, DataConstants.CLIENT_SCOPE, savedEntityView.getKeys().getAttributes().getCs())); futures.add(copyAttributesFromEntityToEntityView(savedEntityView, DataConstants.SERVER_SCOPE, savedEntityView.getKeys().getAttributes().getSs())); futures.add(copyAttributesFromEntityToEntityView(savedEntityView, DataConstants.SHARED_SCOPE, savedEntityView.getKeys().getAttributes().getSh())); diff --git a/dao/src/main/java/org/thingsboard/server/dao/timeseries/BaseTimeseriesService.java b/dao/src/main/java/org/thingsboard/server/dao/timeseries/BaseTimeseriesService.java index 4a09bb7a23..4658cbe490 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/timeseries/BaseTimeseriesService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/timeseries/BaseTimeseriesService.java @@ -79,12 +79,16 @@ public class BaseTimeseriesService implements TimeseriesService { if (entityId.getEntityType().equals(EntityType.ENTITY_VIEW)) { EntityView entityView = entityViewService.findEntityViewById((EntityViewId) entityId); List filteredKeys = new ArrayList<>(keys); - if (!entityView.getKeys().getTimeseries().isEmpty()) { + if (entityView.getKeys() != null && entityView.getKeys().getTimeseries() != null && + !entityView.getKeys().getTimeseries().isEmpty()) { filteredKeys.retainAll(entityView.getKeys().getTimeseries()); } List queries = filteredKeys.stream() - .map(key -> new BaseReadTsKvQuery(key, entityView.getStartTimeMs(), entityView.getEndTimeMs(), 1, "ASC")) + .map(key -> { + long endTs = entityView.getEndTimeMs() != 0 ? entityView.getEndTimeMs() : Long.MAX_VALUE; + return new BaseReadTsKvQuery(key, entityView.getStartTimeMs(), endTs, 1, "DESC"); + }) .collect(Collectors.toList()); if (queries.size() > 0) { @@ -100,7 +104,17 @@ public class BaseTimeseriesService implements TimeseriesService { @Override public ListenableFuture> findAllLatest(EntityId entityId) { validate(entityId); - return timeseriesDao.findAllLatest(entityId); + if (entityId.getEntityType().equals(EntityType.ENTITY_VIEW)) { + EntityView entityView = entityViewService.findEntityViewById((EntityViewId) entityId); + if (entityView.getKeys() != null && entityView.getKeys().getTimeseries() != null && + !entityView.getKeys().getTimeseries().isEmpty()) { + return findLatest(entityId, entityView.getKeys().getTimeseries()); + } else { + return Futures.immediateFuture(new ArrayList<>()); + } + } else { + return timeseriesDao.findAllLatest(entityId); + } } @Override diff --git a/dao/src/test/java/org/thingsboard/server/dao/SqlDaoServiceTestSuite.java b/dao/src/test/java/org/thingsboard/server/dao/SqlDaoServiceTestSuite.java index 9e56d64aba..0eaebfbbdc 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/SqlDaoServiceTestSuite.java +++ b/dao/src/test/java/org/thingsboard/server/dao/SqlDaoServiceTestSuite.java @@ -24,7 +24,7 @@ import java.util.Arrays; @RunWith(ClasspathSuite.class) @ClassnameFilters({ - "org.thingsboard.server.dao.service.*ServiceSqlTest" + "org.thingsboard.server.dao.service.*.TimeseriesServiceSqlTest" }) public class SqlDaoServiceTestSuite { diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/AbstractServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/AbstractServiceTest.java index 1e1f15daff..f49c357caa 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/AbstractServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/AbstractServiceTest.java @@ -45,6 +45,7 @@ import org.thingsboard.server.dao.customer.CustomerService; import org.thingsboard.server.dao.dashboard.DashboardService; import org.thingsboard.server.dao.device.DeviceCredentialsService; import org.thingsboard.server.dao.device.DeviceService; +import org.thingsboard.server.dao.entityview.EntityViewService; import org.thingsboard.server.dao.event.EventService; import org.thingsboard.server.dao.relation.RelationService; import org.thingsboard.server.dao.rule.RuleChainService; @@ -88,6 +89,9 @@ public abstract class AbstractServiceTest { @Autowired protected AssetService assetService; + @Autowired + protected EntityViewService entityViewService; + @Autowired protected DeviceCredentialsService deviceCredentialsService; diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/timeseries/BaseTimeseriesServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/timeseries/BaseTimeseriesServiceTest.java index 4528d9afb1..88f4d84eb6 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/timeseries/BaseTimeseriesServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/timeseries/BaseTimeseriesServiceTest.java @@ -17,9 +17,15 @@ package org.thingsboard.server.dao.service.timeseries; import com.datastax.driver.core.utils.UUIDs; import lombok.extern.slf4j.Slf4j; +import org.junit.After; import org.junit.Assert; +import org.junit.Before; import org.junit.Test; +import org.thingsboard.server.common.data.EntityView; +import org.thingsboard.server.common.data.Tenant; import org.thingsboard.server.common.data.id.DeviceId; +import org.thingsboard.server.common.data.id.EntityId; +import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.kv.Aggregation; import org.thingsboard.server.common.data.kv.BaseDeleteTsKvQuery; import org.thingsboard.server.common.data.kv.BaseReadTsKvQuery; @@ -30,6 +36,7 @@ import org.thingsboard.server.common.data.kv.KvEntry; import org.thingsboard.server.common.data.kv.LongDataEntry; import org.thingsboard.server.common.data.kv.StringDataEntry; import org.thingsboard.server.common.data.kv.TsKvEntry; +import org.thingsboard.server.common.data.objects.TelemetryEntityView; import org.thingsboard.server.dao.service.AbstractServiceTest; import java.util.ArrayList; @@ -61,6 +68,22 @@ public abstract class BaseTimeseriesServiceTest extends AbstractServiceTest { KvEntry doubleKvEntry = new DoubleDataEntry(DOUBLE_KEY, Double.MAX_VALUE); KvEntry booleanKvEntry = new BooleanDataEntry(BOOLEAN_KEY, Boolean.TRUE); + private TenantId tenantId; + + @Before + public void before() { + Tenant tenant = new Tenant(); + tenant.setTitle("My tenant"); + Tenant savedTenant = tenantService.saveTenant(tenant); + Assert.assertNotNull(savedTenant); + tenantId = savedTenant.getId(); + } + + @After + public void after() { + tenantService.deleteTenant(tenantId); + } + @Test public void testFindAllLatest() throws Exception { DeviceId deviceId = new DeviceId(UUIDs.timeBased()); @@ -69,7 +92,15 @@ public abstract class BaseTimeseriesServiceTest extends AbstractServiceTest { saveEntries(deviceId, TS - 1); saveEntries(deviceId, TS); - List tsList = tsService.findAllLatest(deviceId).get(); + testLatestTsAndVerify(deviceId); + + EntityView entityView = saveAndCreateEntityView(deviceId, Arrays.asList(STRING_KEY, DOUBLE_KEY, LONG_KEY, BOOLEAN_KEY)); + + testLatestTsAndVerify(entityView.getId()); + } + + private void testLatestTsAndVerify(EntityId entityId) throws ExecutionException, InterruptedException { + List tsList = tsService.findAllLatest(entityId).get(); assertNotNull(tsList); assertEquals(4, tsList.size()); @@ -89,6 +120,18 @@ public abstract class BaseTimeseriesServiceTest extends AbstractServiceTest { assertEquals(expected, tsList); } + private EntityView saveAndCreateEntityView(DeviceId deviceId, List timeseries) { + EntityView entityView = new EntityView(); + entityView.setName("entity_view_name"); + entityView.setType("default"); + entityView.setTenantId(tenantId); + TelemetryEntityView keys = new TelemetryEntityView(); + keys.setTimeseries(timeseries); + entityView.setKeys(keys); + entityView.setEntityId(deviceId); + return entityViewService.saveEntityView(entityView); + } + @Test public void testFindLatest() throws Exception { DeviceId deviceId = new DeviceId(UUIDs.timeBased()); @@ -100,6 +143,12 @@ public abstract class BaseTimeseriesServiceTest extends AbstractServiceTest { List entries = tsService.findLatest(deviceId, Collections.singleton(STRING_KEY)).get(); Assert.assertEquals(1, entries.size()); Assert.assertEquals(toTsEntry(TS, stringKvEntry), entries.get(0)); + + EntityView entityView = saveAndCreateEntityView(deviceId, Arrays.asList(STRING_KEY)); + + entries = tsService.findLatest(entityView.getId(), Collections.singleton(STRING_KEY)).get(); + Assert.assertEquals(1, entries.size()); + Assert.assertEquals(toTsEntry(TS, stringKvEntry), entries.get(0)); } @Test diff --git a/netty-mqtt/pom.xml b/netty-mqtt/pom.xml index f7e32b53e7..0b1ea1e35e 100644 --- a/netty-mqtt/pom.xml +++ b/netty-mqtt/pom.xml @@ -19,12 +19,12 @@ 4.0.0 org.thingsboard - 2.1.2 + 2.1.3-SNAPSHOT thingsboard org.thingsboard netty-mqtt - 2.1.2 + 2.1.3-SNAPSHOT jar Netty MQTT Client diff --git a/pom.xml b/pom.xml index 981482b35a..05ab0d6f39 100755 --- a/pom.xml +++ b/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard thingsboard - 2.1.2 + 2.1.3-SNAPSHOT pom Thingsboard diff --git a/rule-engine/pom.xml b/rule-engine/pom.xml index 5c5fe56075..3847120030 100644 --- a/rule-engine/pom.xml +++ b/rule-engine/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 2.1.2 + 2.1.3-SNAPSHOT thingsboard rule-engine diff --git a/rule-engine/rule-engine-api/pom.xml b/rule-engine/rule-engine-api/pom.xml index 4b4f33624f..4e79b11056 100644 --- a/rule-engine/rule-engine-api/pom.xml +++ b/rule-engine/rule-engine-api/pom.xml @@ -22,7 +22,7 @@ 4.0.0 org.thingsboard - 2.1.2 + 2.1.3-SNAPSHOT rule-engine org.thingsboard.rule-engine diff --git a/rule-engine/rule-engine-components/pom.xml b/rule-engine/rule-engine-components/pom.xml index ebab903190..6e7cfdc6a7 100644 --- a/rule-engine/rule-engine-components/pom.xml +++ b/rule-engine/rule-engine-components/pom.xml @@ -22,7 +22,7 @@ 4.0.0 org.thingsboard - 2.1.2 + 2.1.3-SNAPSHOT rule-engine org.thingsboard.rule-engine diff --git a/tools/pom.xml b/tools/pom.xml index 8a9481d0b9..af4c53b4a1 100644 --- a/tools/pom.xml +++ b/tools/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 2.1.2 + 2.1.3-SNAPSHOT thingsboard org.thingsboard diff --git a/transport/coap/pom.xml b/transport/coap/pom.xml index 537a9bee06..bcb45236c1 100644 --- a/transport/coap/pom.xml +++ b/transport/coap/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 2.1.2 + 2.1.3-SNAPSHOT transport org.thingsboard.transport diff --git a/transport/http/pom.xml b/transport/http/pom.xml index 24e4ff94af..d73692f260 100644 --- a/transport/http/pom.xml +++ b/transport/http/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 2.1.2 + 2.1.3-SNAPSHOT transport org.thingsboard.transport diff --git a/transport/mqtt/pom.xml b/transport/mqtt/pom.xml index f5c1104b6a..e89bba42b1 100644 --- a/transport/mqtt/pom.xml +++ b/transport/mqtt/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 2.1.2 + 2.1.3-SNAPSHOT transport org.thingsboard.transport diff --git a/transport/pom.xml b/transport/pom.xml index 7858383d82..22ec9be255 100644 --- a/transport/pom.xml +++ b/transport/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 2.1.2 + 2.1.3-SNAPSHOT thingsboard org.thingsboard diff --git a/ui/pom.xml b/ui/pom.xml index a2eadb5445..c219a22e6b 100644 --- a/ui/pom.xml +++ b/ui/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 2.1.2 + 2.1.3-SNAPSHOT thingsboard org.thingsboard diff --git a/ui/src/app/entity-view/entity-view-fieldset.tpl.html b/ui/src/app/entity-view/entity-view-fieldset.tpl.html index 66dc116cc8..74d1e3397c 100644 --- a/ui/src/app/entity-view/entity-view-fieldset.tpl.html +++ b/ui/src/app/entity-view/entity-view-fieldset.tpl.html @@ -78,31 +78,79 @@ ng-required="false" readonly="!isEdit" ng-model="entityView.keys.attributes.cs" - placeholder="{{'entity-view.client-attributes' | translate}}" + placeholder="{{'entity-view.client-attributes-placeholder' | translate}}" md-separator-keys="separatorKeys"> + + {{item}} + + + {{item}} + + + {{item}} + - + + + {{item}} +
diff --git a/ui/src/app/entity-view/entity-view.directive.js b/ui/src/app/entity-view/entity-view.directive.js index e1ae82fa6a..d183053f47 100644 --- a/ui/src/app/entity-view/entity-view.directive.js +++ b/ui/src/app/entity-view/entity-view.directive.js @@ -20,8 +20,8 @@ import entityViewFieldsetTemplate from './entity-view-fieldset.tpl.html'; /* eslint-enable import/no-unresolved, import/default */ /*@ngInject*/ -export default function EntityViewDirective($compile, $templateCache, $filter, toast, $translate, $mdConstant, - types, clipboardService, entityViewService, customerService) { +export default function EntityViewDirective($q, $compile, $templateCache, $filter, toast, $translate, $mdConstant, + types, clipboardService, entityViewService, customerService, entityService) { var linker = function (scope, element) { var template = $templateCache.get(entityViewFieldsetTemplate); element.html(template); @@ -53,9 +53,13 @@ export default function EntityViewDirective($compile, $templateCache, $filter, t } if (scope.entityView.startTimeMs > 0) { scope.startTimeMs = new Date(scope.entityView.startTimeMs); + } else { + scope.startTimeMs = null; } if (scope.entityView.endTimeMs > 0) { scope.endTimeMs = new Date(scope.entityView.endTimeMs); + } else { + scope.endTimeMs = null; } if (!scope.entityView.keys) { scope.entityView.keys = {}; @@ -68,6 +72,19 @@ export default function EntityViewDirective($compile, $templateCache, $filter, t } }); + scope.dataKeysSearch = function (searchText, type) { + var deferred = $q.defer(); + entityService.getEntityKeys(scope.entityView.entityId.entityType, scope.entityView.entityId.id, searchText, type, {ignoreLoading: true}).then( + function success(keys) { + deferred.resolve(keys); + }, + function fail() { + deferred.resolve([]); + } + ); + return deferred.promise; + + }; scope.$watch('startTimeMs', function (newDate) { if (newDate) { diff --git a/ui/src/app/locale/locale.constant-en_US.json b/ui/src/app/locale/locale.constant-en_US.json index 6c6ea438af..ccfcf659ac 100644 --- a/ui/src/app/locale/locale.constant-en_US.json +++ b/ui/src/app/locale/locale.constant-en_US.json @@ -844,7 +844,11 @@ "client-attributes": "Client attributes", "shared-attributes": "Shared attributes", "server-attributes": "Server attributes", - "latest-timeseries": "Latest timeseries", + "timeseries": "Timeseries", + "client-attributes-placeholder": "Client attributes", + "shared-attributes-placeholder": "Shared attributes", + "server-attributes-placeholder": "Server attributes", + "timeseries-placeholder": "Timeseries", "related-entity": "Related entity" }, "event": { diff --git a/ui/src/app/locale/locale.constant-es_ES.json b/ui/src/app/locale/locale.constant-es_ES.json index 285c589bd6..1b0a16939b 100644 --- a/ui/src/app/locale/locale.constant-es_ES.json +++ b/ui/src/app/locale/locale.constant-es_ES.json @@ -839,7 +839,7 @@ "client-attributes": "Client attributes", "shared-attributes": "Shared attributes", "server-attributes": "Server attributes", - "latest-timeseries": "Latest timeseries" + "timeseries": "Timeseries" }, "event": { "event-type": "Tipo de evento",