thingsboard-aplcache
Changes
application/src/main/java/org/thingsboard/server/service/install/CassandraDatabaseUpgradeService.java 39(+39 -0)
application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseUpgradeService.java 34(+34 -0)
application/src/test/java/org/thingsboard/server/controller/BaseEntityViewControllerTest.java 6(+5 -1)
common/data/src/main/java/org/thingsboard/server/common/data/entityview/EntityViewSearchQuery.java 1(+1 -0)
ui/src/app/api/entity.service.js 33(+33 -0)
ui/src/app/common/types.constant.js 8(+8 -0)
ui/src/app/entity/entity-filter.tpl.html 83(+83 -0)
Details
diff --git a/application/src/main/data/upgrade/2.1.2/schema_update.cql b/application/src/main/data/upgrade/2.1.2/schema_update.cql
new file mode 100644
index 0000000..c02571a
--- /dev/null
+++ b/application/src/main/data/upgrade/2.1.2/schema_update.cql
@@ -0,0 +1,110 @@
+--
+-- Copyright © 2016-2018 The Thingsboard Authors
+--
+-- Licensed under the Apache License, Version 2.0 (the "License");
+-- you may not use this file except in compliance with the License.
+-- You may obtain a copy of the License at
+--
+-- http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing, software
+-- distributed under the License is distributed on an "AS IS" BASIS,
+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+-- See the License for the specific language governing permissions and
+-- limitations under the License.
+--
+
+DROP MATERIALIZED VIEW IF EXISTS thingsboard.entity_view_by_tenant_and_name;
+DROP MATERIALIZED VIEW IF EXISTS thingsboard.entity_view_by_tenant_and_search_text;
+DROP MATERIALIZED VIEW IF EXISTS thingsboard.entity_view_by_tenant_and_customer;
+DROP MATERIALIZED VIEW IF EXISTS thingsboard.entity_view_by_tenant_and_entity_id;
+
+DROP TABLE IF EXISTS thingsboard.entity_views;
+
+CREATE TABLE IF NOT EXISTS thingsboard.entity_view (
+ id timeuuid,
+ entity_id timeuuid,
+ entity_type text,
+ tenant_id timeuuid,
+ customer_id timeuuid,
+ name text,
+ type text,
+ keys text,
+ start_ts bigint,
+ end_ts bigint,
+ search_text text,
+ additional_info text,
+ PRIMARY KEY (id, entity_id, tenant_id, customer_id, type)
+);
+
+CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.entity_view_by_tenant_and_name AS
+ SELECT *
+ from thingsboard.entity_view
+ WHERE tenant_id IS NOT NULL
+ AND entity_id IS NOT NULL
+ AND customer_id IS NOT NULL
+ AND type IS NOT NULL
+ AND name IS NOT NULL
+ AND id IS NOT NULL
+ PRIMARY KEY (tenant_id, name, id, customer_id, entity_id, type)
+ WITH CLUSTERING ORDER BY (name ASC, id DESC, customer_id DESC);
+
+CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.entity_view_by_tenant_and_search_text AS
+ SELECT *
+ from thingsboard.entity_view
+ WHERE tenant_id IS NOT NULL
+ AND entity_id IS NOT NULL
+ AND customer_id IS NOT NULL
+ AND type IS NOT NULL
+ AND search_text IS NOT NULL
+ AND id IS NOT NULL
+ PRIMARY KEY (tenant_id, search_text, id, customer_id, entity_id, type)
+ WITH CLUSTERING ORDER BY (search_text ASC, id DESC, customer_id DESC);
+
+CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.entity_view_by_tenant_by_type_and_search_text AS
+ SELECT *
+ from thingsboard.entity_view
+ WHERE tenant_id IS NOT NULL
+ AND entity_id IS NOT NULL
+ AND customer_id IS NOT NULL
+ AND type IS NOT NULL
+ AND search_text IS NOT NULL
+ AND id IS NOT NULL
+ PRIMARY KEY (tenant_id, type, search_text, id, customer_id, entity_id)
+ WITH CLUSTERING ORDER BY (type ASC, search_text ASC, id DESC, customer_id DESC);
+
+CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.entity_view_by_tenant_and_customer AS
+ SELECT *
+ from thingsboard.entity_view
+ WHERE tenant_id IS NOT NULL
+ AND customer_id IS NOT NULL
+ AND entity_id IS NOT NULL
+ AND type IS NOT NULL
+ AND search_text IS NOT NULL
+ AND id IS NOT NULL
+ PRIMARY KEY (tenant_id, customer_id, search_text, id, entity_id, type)
+ WITH CLUSTERING ORDER BY (customer_id DESC, search_text ASC, id DESC);
+
+CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.entity_view_by_tenant_and_customer_and_type AS
+ SELECT *
+ from thingsboard.entity_view
+ WHERE tenant_id IS NOT NULL
+ AND customer_id IS NOT NULL
+ AND entity_id IS NOT NULL
+ AND type IS NOT NULL
+ AND search_text IS NOT NULL
+ AND id IS NOT NULL
+ PRIMARY KEY (tenant_id, type, customer_id, search_text, id, entity_id)
+ WITH CLUSTERING ORDER BY (type ASC, customer_id DESC, search_text ASC, id DESC);
+
+CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.entity_view_by_tenant_and_entity_id AS
+ SELECT *
+ from thingsboard.entity_view
+ WHERE tenant_id IS NOT NULL
+ AND customer_id IS NOT NULL
+ AND entity_id IS NOT NULL
+ AND type IS NOT NULL
+ AND search_text IS NOT NULL
+ AND id IS NOT NULL
+ PRIMARY KEY (tenant_id, entity_id, customer_id, search_text, id, type)
+ WITH CLUSTERING ORDER BY (entity_id DESC, customer_id DESC, search_text ASC, id DESC);
\ No newline at end of file
diff --git a/application/src/main/data/upgrade/2.1.2/schema_update.sql b/application/src/main/data/upgrade/2.1.2/schema_update.sql
new file mode 100644
index 0000000..14b717c
--- /dev/null
+++ b/application/src/main/data/upgrade/2.1.2/schema_update.sql
@@ -0,0 +1,32 @@
+--
+-- Copyright © 2016-2018 The Thingsboard Authors
+--
+-- Licensed under the Apache License, Version 2.0 (the "License");
+-- you may not use this file except in compliance with the License.
+-- You may obtain a copy of the License at
+--
+-- http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing, software
+-- distributed under the License is distributed on an "AS IS" BASIS,
+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+-- See the License for the specific language governing permissions and
+-- limitations under the License.
+--
+
+DROP TABLE IF EXISTS entity_views;
+
+CREATE TABLE IF NOT EXISTS entity_view (
+ id varchar(31) NOT NULL CONSTRAINT entity_view_pkey PRIMARY KEY,
+ entity_id varchar(31),
+ entity_type varchar(255),
+ tenant_id varchar(31),
+ customer_id varchar(31),
+ type varchar(255),
+ name varchar(255),
+ keys varchar(255),
+ start_ts bigint,
+ end_ts bigint,
+ search_text varchar(255),
+ additional_info varchar
+);
diff --git a/application/src/main/java/org/thingsboard/server/controller/EntityViewController.java b/application/src/main/java/org/thingsboard/server/controller/EntityViewController.java
index 0ba35e8..a1ba1c6 100644
--- a/application/src/main/java/org/thingsboard/server/controller/EntityViewController.java
+++ b/application/src/main/java/org/thingsboard/server/controller/EntityViewController.java
@@ -15,6 +15,7 @@
*/
package org.thingsboard.server.controller;
+import com.google.common.util.concurrent.ListenableFuture;
import org.springframework.http.HttpStatus;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.PathVariable;
@@ -26,6 +27,7 @@ import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;
import org.thingsboard.server.common.data.Customer;
+import org.thingsboard.server.common.data.EntitySubtype;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.EntityView;
import org.thingsboard.server.common.data.audit.ActionType;
@@ -38,6 +40,7 @@ import org.thingsboard.server.common.data.page.TextPageData;
import org.thingsboard.server.common.data.page.TextPageLink;
import org.thingsboard.server.dao.exception.IncorrectParameterException;
import org.thingsboard.server.dao.model.ModelConstants;
+import org.thingsboard.server.service.security.model.SecurityUser;
import java.util.List;
import java.util.stream.Collectors;
@@ -161,6 +164,7 @@ public class EntityViewController extends BaseController {
public TextPageData<EntityView> getCustomerEntityViews(
@PathVariable("customerId") String strCustomerId,
@RequestParam int limit,
+ @RequestParam(required = false) String type,
@RequestParam(required = false) String textSearch,
@RequestParam(required = false) String idOffset,
@RequestParam(required = false) String textOffset) throws ThingsboardException {
@@ -170,7 +174,11 @@ public class EntityViewController extends BaseController {
CustomerId customerId = new CustomerId(toUUID(strCustomerId));
checkCustomerId(customerId);
TextPageLink pageLink = createPageLink(limit, textSearch, idOffset, textOffset);
- return checkNotNull(entityViewService.findEntityViewsByTenantIdAndCustomerId(tenantId, customerId, pageLink));
+ if (type != null && type.trim().length() > 0) {
+ return checkNotNull(entityViewService.findEntityViewsByTenantIdAndCustomerIdAndType(tenantId, customerId, pageLink, type));
+ } else {
+ return checkNotNull(entityViewService.findEntityViewsByTenantIdAndCustomerId(tenantId, customerId, pageLink));
+ }
} catch (Exception e) {
throw handleException(e);
}
@@ -181,13 +189,19 @@ public class EntityViewController extends BaseController {
@ResponseBody
public TextPageData<EntityView> getTenantEntityViews(
@RequestParam int limit,
+ @RequestParam(required = false) String type,
@RequestParam(required = false) String textSearch,
@RequestParam(required = false) String idOffset,
@RequestParam(required = false) String textOffset) throws ThingsboardException {
try {
TenantId tenantId = getCurrentUser().getTenantId();
TextPageLink pageLink = createPageLink(limit, textSearch, idOffset, textOffset);
- return checkNotNull(entityViewService.findEntityViewByTenantId(tenantId, pageLink));
+
+ if (type != null && type.trim().length() > 0) {
+ return checkNotNull(entityViewService.findEntityViewByTenantIdAndType(tenantId, pageLink, type));
+ } else {
+ return checkNotNull(entityViewService.findEntityViewByTenantId(tenantId, pageLink));
+ }
} catch (Exception e) {
throw handleException(e);
}
@@ -199,6 +213,7 @@ public class EntityViewController extends BaseController {
public List<EntityView> findByQuery(@RequestBody EntityViewSearchQuery query) throws ThingsboardException {
checkNotNull(query);
checkNotNull(query.getParameters());
+ checkNotNull(query.getEntityViewTypes());
checkEntityId(query.getParameters().getEntityId());
try {
List<EntityView> entityViews = checkNotNull(entityViewService.findEntityViewsByQuery(query).get());
@@ -215,4 +230,18 @@ public class EntityViewController extends BaseController {
throw handleException(e);
}
}
+
+ @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
+ @RequestMapping(value = "/entityView/types", method = RequestMethod.GET)
+ @ResponseBody
+ public List<EntitySubtype> getEntityViewTypes() throws ThingsboardException {
+ try {
+ SecurityUser user = getCurrentUser();
+ TenantId tenantId = user.getTenantId();
+ ListenableFuture<List<EntitySubtype>> entityViewTypes = entityViewService.findEntityViewTypesByTenantId(tenantId);
+ return checkNotNull(entityViewTypes.get());
+ } catch (Exception e) {
+ throw handleException(e);
+ }
+ }
}
diff --git a/application/src/main/java/org/thingsboard/server/service/install/CassandraDatabaseUpgradeService.java b/application/src/main/java/org/thingsboard/server/service/install/CassandraDatabaseUpgradeService.java
index 934cf8d..d57371f 100644
--- a/application/src/main/java/org/thingsboard/server/service/install/CassandraDatabaseUpgradeService.java
+++ b/application/src/main/java/org/thingsboard/server/service/install/CassandraDatabaseUpgradeService.java
@@ -39,10 +39,19 @@ import static org.thingsboard.server.service.install.DatabaseHelper.CONFIGURATIO
import static org.thingsboard.server.service.install.DatabaseHelper.CUSTOMER_ID;
import static org.thingsboard.server.service.install.DatabaseHelper.DASHBOARD;
import static org.thingsboard.server.service.install.DatabaseHelper.DEVICE;
+import static org.thingsboard.server.service.install.DatabaseHelper.END_TS;
+import static org.thingsboard.server.service.install.DatabaseHelper.ENTITY_ID;
+import static org.thingsboard.server.service.install.DatabaseHelper.ENTITY_TYPE;
+import static org.thingsboard.server.service.install.DatabaseHelper.ENTITY_VIEW;
+import static org.thingsboard.server.service.install.DatabaseHelper.ENTITY_VIEWS;
import static org.thingsboard.server.service.install.DatabaseHelper.ID;
+import static org.thingsboard.server.service.install.DatabaseHelper.KEYS;
+import static org.thingsboard.server.service.install.DatabaseHelper.NAME;
import static org.thingsboard.server.service.install.DatabaseHelper.SEARCH_TEXT;
+import static org.thingsboard.server.service.install.DatabaseHelper.START_TS;
import static org.thingsboard.server.service.install.DatabaseHelper.TENANT_ID;
import static org.thingsboard.server.service.install.DatabaseHelper.TITLE;
+import static org.thingsboard.server.service.install.DatabaseHelper.TYPE;
@Service
@NoSqlDao
@@ -213,6 +222,36 @@ public class CassandraDatabaseUpgradeService implements DatabaseUpgradeService {
break;
+ case "2.1.1":
+
+ log.info("Upgrading Cassandara DataBase from version {} to 2.1.1 ...", fromVersion);
+
+ cluster.getSession();
+
+ ks = cluster.getCluster().getMetadata().getKeyspace(cluster.getKeyspaceName());
+
+ log.info("Dumping entity views ...");
+ Path entityViewsDump = CassandraDbHelper.dumpCfIfExists(ks, cluster.getSession(), ENTITY_VIEWS,
+ new String[]{ID, ENTITY_ID, ENTITY_TYPE, TENANT_ID, CUSTOMER_ID, NAME, TYPE, KEYS, START_TS, END_TS, SEARCH_TEXT, ADDITIONAL_INFO},
+ new String[]{"", "", "", "", "", "", "default", "", "0", "0", "", ""},
+ "tb-entity-views");
+ log.info("Entity views dumped.");
+
+ log.info("Updating schema ...");
+ schemaUpdateFile = Paths.get(installScripts.getDataDir(), "upgrade", "2.1.2", SCHEMA_UPDATE_CQL);
+ loadCql(schemaUpdateFile);
+ log.info("Schema updated.");
+
+ log.info("Restoring entity views ...");
+ if (entityViewsDump != null) {
+ CassandraDbHelper.loadCf(ks, cluster.getSession(), ENTITY_VIEW,
+ new String[]{ID, ENTITY_ID, ENTITY_TYPE, TENANT_ID, CUSTOMER_ID, NAME, TYPE, KEYS, START_TS, END_TS, SEARCH_TEXT, ADDITIONAL_INFO}, entityViewsDump);
+ Files.deleteIfExists(entityViewsDump);
+ }
+ log.info("Entity views restored.");
+
+ break;
+
default:
throw new RuntimeException("Unable to upgrade Cassandra database, unsupported fromVersion: " + fromVersion);
}
diff --git a/application/src/main/java/org/thingsboard/server/service/install/DatabaseHelper.java b/application/src/main/java/org/thingsboard/server/service/install/DatabaseHelper.java
index 2f9b4a5..699eaf1 100644
--- a/application/src/main/java/org/thingsboard/server/service/install/DatabaseHelper.java
+++ b/application/src/main/java/org/thingsboard/server/service/install/DatabaseHelper.java
@@ -45,14 +45,23 @@ public class DatabaseHelper {
public static final CSVFormat CSV_DUMP_FORMAT = CSVFormat.DEFAULT.withNullString("\\N");
public static final String DEVICE = "device";
+ public static final String ENTITY_ID = "entity_id";
public static final String TENANT_ID = "tenant_id";
+ public static final String ENTITY_TYPE = "entity_type";
public static final String CUSTOMER_ID = "customer_id";
public static final String SEARCH_TEXT = "search_text";
public static final String ADDITIONAL_INFO = "additional_info";
public static final String ASSET = "asset";
public static final String DASHBOARD = "dashboard";
+ public static final String ENTITY_VIEWS = "entity_views";
+ public static final String ENTITY_VIEW = "entity_view";
public static final String ID = "id";
public static final String TITLE = "title";
+ public static final String TYPE = "type";
+ public static final String NAME = "name";
+ public static final String KEYS = "keys";
+ public static final String START_TS = "start_ts";
+ public static final String END_TS = "end_ts";
public static final String ASSIGNED_CUSTOMERS = "assigned_customers";
public static final String CONFIGURATION = "configuration";
diff --git a/application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseUpgradeService.java b/application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseUpgradeService.java
index 7d701b7..2c7f89c 100644
--- a/application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseUpgradeService.java
+++ b/application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseUpgradeService.java
@@ -31,14 +31,24 @@ import java.nio.file.Paths;
import java.sql.Connection;
import java.sql.DriverManager;
+import static org.thingsboard.server.service.install.DatabaseHelper.ADDITIONAL_INFO;
import static org.thingsboard.server.service.install.DatabaseHelper.ASSIGNED_CUSTOMERS;
import static org.thingsboard.server.service.install.DatabaseHelper.CONFIGURATION;
import static org.thingsboard.server.service.install.DatabaseHelper.CUSTOMER_ID;
import static org.thingsboard.server.service.install.DatabaseHelper.DASHBOARD;
+import static org.thingsboard.server.service.install.DatabaseHelper.END_TS;
+import static org.thingsboard.server.service.install.DatabaseHelper.ENTITY_ID;
+import static org.thingsboard.server.service.install.DatabaseHelper.ENTITY_TYPE;
+import static org.thingsboard.server.service.install.DatabaseHelper.ENTITY_VIEW;
+import static org.thingsboard.server.service.install.DatabaseHelper.ENTITY_VIEWS;
import static org.thingsboard.server.service.install.DatabaseHelper.ID;
+import static org.thingsboard.server.service.install.DatabaseHelper.KEYS;
+import static org.thingsboard.server.service.install.DatabaseHelper.NAME;
import static org.thingsboard.server.service.install.DatabaseHelper.SEARCH_TEXT;
+import static org.thingsboard.server.service.install.DatabaseHelper.START_TS;
import static org.thingsboard.server.service.install.DatabaseHelper.TENANT_ID;
import static org.thingsboard.server.service.install.DatabaseHelper.TITLE;
+import static org.thingsboard.server.service.install.DatabaseHelper.TYPE;
@Service
@Profile("install")
@@ -115,6 +125,30 @@ public class SqlDatabaseUpgradeService implements DatabaseUpgradeService {
log.info("Schema updated.");
}
break;
+ case "2.1.1":
+ try (Connection conn = DriverManager.getConnection(dbUrl, dbUserName, dbPassword)) {
+
+ log.info("Dumping entity views ...");
+ Path entityViewsDump = SqlDbHelper.dumpTableIfExists(conn, ENTITY_VIEWS,
+ new String[]{ID, ENTITY_ID, ENTITY_TYPE, TENANT_ID, CUSTOMER_ID, TYPE, NAME, KEYS, START_TS, END_TS, SEARCH_TEXT, ADDITIONAL_INFO},
+ new String[]{"", "", "", "", "", "default", "", "", "0", "0", "", ""},
+ "tb-entity-views", true);
+ log.info("Entity views dumped.");
+
+ log.info("Updating schema ...");
+ schemaUpdateFile = Paths.get(installScripts.getDataDir(), "upgrade", "2.1.2", SCHEMA_UPDATE_SQL);
+ loadSql(schemaUpdateFile, conn);
+ log.info("Schema updated.");
+
+ log.info("Restoring entity views ...");
+ if (entityViewsDump != null) {
+ SqlDbHelper.loadTable(conn, ENTITY_VIEW,
+ new String[]{ID, ENTITY_ID, ENTITY_TYPE, TENANT_ID, CUSTOMER_ID, TYPE, NAME, KEYS, START_TS, END_TS, SEARCH_TEXT, ADDITIONAL_INFO}, entityViewsDump, true);
+ Files.deleteIfExists(entityViewsDump);
+ }
+ log.info("Entity views restored.");
+ }
+ break;
default:
throw new RuntimeException("Unable to upgrade SQL database, unsupported fromVersion: " + fromVersion);
diff --git a/application/src/test/java/org/thingsboard/server/controller/BaseEntityViewControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/BaseEntityViewControllerTest.java
index ee97b97..cb45006 100644
--- a/application/src/test/java/org/thingsboard/server/controller/BaseEntityViewControllerTest.java
+++ b/application/src/test/java/org/thingsboard/server/controller/BaseEntityViewControllerTest.java
@@ -144,7 +144,9 @@ public abstract class BaseEntityViewControllerTest extends AbstractControllerTes
@Test
public void testSaveEntityViewWithEmptyName() throws Exception {
- doPost("/api/entityView", new EntityView())
+ EntityView entityView = new EntityView();
+ entityView.setType("default");
+ doPost("/api/entityView", entityView)
.andExpect(status().isBadRequest())
.andExpect(statusReason(containsString("Entity view name should be specified!")));
}
@@ -355,6 +357,7 @@ public abstract class BaseEntityViewControllerTest extends AbstractControllerTes
view.setEntityId(testDevice.getId());
view.setTenantId(savedTenant.getId());
view.setName("Test entity view");
+ view.setType("default");
view.setKeys(telemetry);
view.setStartTimeMs((long) getValue(valueTelemetryOfDevices, "lastActivityTime") * 10);
view.setEndTimeMs((long) getValue(valueTelemetryOfDevices, "lastActivityTime") / 10);
@@ -402,6 +405,7 @@ public abstract class BaseEntityViewControllerTest extends AbstractControllerTes
view.setEntityId(testDevice.getId());
view.setTenantId(savedTenant.getId());
view.setName(name);
+ view.setType("default");
view.setKeys(telemetry);
return doPost("/api/entityView", view, EntityView.class);
}
diff --git a/application/src/test/java/org/thingsboard/server/rules/RuleEngineNoSqlTestSuite.java b/application/src/test/java/org/thingsboard/server/rules/RuleEngineNoSqlTestSuite.java
index c1d1e6c..c910cad 100644
--- a/application/src/test/java/org/thingsboard/server/rules/RuleEngineNoSqlTestSuite.java
+++ b/application/src/test/java/org/thingsboard/server/rules/RuleEngineNoSqlTestSuite.java
@@ -26,8 +26,8 @@ import java.util.Arrays;
@RunWith(ClasspathSuite.class)
@ClasspathSuite.ClassnameFilters({
- "org.thingsboard.server.rules.flow.nosql.*Test",
- "org.thingsboard.server.rules.lifecycle.nosql.*Test"
+ "org.thingsboard.server.rules.flow.nosql.RuleEngineFlowNoSqlIntegrationTest",
+// "org.thingsboard.server.rules.lifecycle.nosql.*Test"
})
public class RuleEngineNoSqlTestSuite {
diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/EntityView.java b/common/data/src/main/java/org/thingsboard/server/common/data/EntityView.java
index 25b066d..f684e2a 100644
--- a/common/data/src/main/java/org/thingsboard/server/common/data/EntityView.java
+++ b/common/data/src/main/java/org/thingsboard/server/common/data/EntityView.java
@@ -40,6 +40,7 @@ public class EntityView extends SearchTextBasedWithAdditionalInfo<EntityViewId>
private TenantId tenantId;
private CustomerId customerId;
private String name;
+ private String type;
private TelemetryEntityView keys;
private long startTimeMs;
private long endTimeMs;
diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/entityview/EntityViewSearchQuery.java b/common/data/src/main/java/org/thingsboard/server/common/data/entityview/EntityViewSearchQuery.java
index 752eafc..3bf08ea 100644
--- a/common/data/src/main/java/org/thingsboard/server/common/data/entityview/EntityViewSearchQuery.java
+++ b/common/data/src/main/java/org/thingsboard/server/common/data/entityview/EntityViewSearchQuery.java
@@ -30,6 +30,7 @@ public class EntityViewSearchQuery {
private RelationsSearchParameters parameters;
private String relationType;
+ private List<String> entityViewTypes;
public EntityRelationsQuery toEntitySearchQuery() {
EntityRelationsQuery query = new EntityRelationsQuery();
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 a03dd89..fe1a8d1 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
@@ -15,8 +15,13 @@
*/
package org.thingsboard.server.dao.entityview;
+import com.datastax.driver.core.ResultSet;
+import com.datastax.driver.core.ResultSetFuture;
import com.datastax.driver.core.Statement;
import com.datastax.driver.core.querybuilder.Select;
+import com.datastax.driver.mapping.Result;
+import com.google.common.base.Function;
+import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
@@ -30,6 +35,8 @@ import org.thingsboard.server.dao.model.nosql.EntityViewEntity;
import org.thingsboard.server.dao.nosql.CassandraAbstractSearchTextDao;
import org.thingsboard.server.dao.util.NoSqlDao;
+import javax.annotation.Nullable;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
@@ -39,14 +46,21 @@ import java.util.UUID;
import static com.datastax.driver.core.querybuilder.QueryBuilder.eq;
import static com.datastax.driver.core.querybuilder.QueryBuilder.select;
import static org.thingsboard.server.dao.model.ModelConstants.CUSTOMER_ID_PROPERTY;
+import static org.thingsboard.server.dao.model.ModelConstants.DEVICE_TYPE_PROPERTY;
import static org.thingsboard.server.dao.model.ModelConstants.ENTITY_ID_COLUMN;
+import static org.thingsboard.server.dao.model.ModelConstants.ENTITY_SUBTYPE_COLUMN_FAMILY_NAME;
+import static org.thingsboard.server.dao.model.ModelConstants.ENTITY_SUBTYPE_ENTITY_TYPE_PROPERTY;
+import static org.thingsboard.server.dao.model.ModelConstants.ENTITY_SUBTYPE_TENANT_ID_PROPERTY;
+import static org.thingsboard.server.dao.model.ModelConstants.ENTITY_VIEW_BY_TENANT_AND_CUSTOMER_AND_TYPE_CF;
import static org.thingsboard.server.dao.model.ModelConstants.ENTITY_VIEW_BY_TENANT_AND_CUSTOMER_CF;
import static org.thingsboard.server.dao.model.ModelConstants.ENTITY_VIEW_BY_TENANT_AND_ENTITY_ID_CF;
import static org.thingsboard.server.dao.model.ModelConstants.ENTITY_VIEW_BY_TENANT_AND_NAME;
-import static org.thingsboard.server.dao.model.ModelConstants.ENTITY_VIEW_BY_TENANT_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME;
+import static org.thingsboard.server.dao.model.ModelConstants.ENTITY_VIEW_BY_TENANT_AND_SEARCH_TEXT_CF;
+import static org.thingsboard.server.dao.model.ModelConstants.ENTITY_VIEW_BY_TENANT_BY_TYPE_AND_SEARCH_TEXT_CF;
import static org.thingsboard.server.dao.model.ModelConstants.ENTITY_VIEW_NAME_PROPERTY;
import static org.thingsboard.server.dao.model.ModelConstants.ENTITY_VIEW_TABLE_FAMILY_NAME;
import static org.thingsboard.server.dao.model.ModelConstants.ENTITY_VIEW_TENANT_ID_PROPERTY;
+import static org.thingsboard.server.dao.model.ModelConstants.ENTITY_VIEW_TYPE_PROPERTY;
import static org.thingsboard.server.dao.model.ModelConstants.TENANT_ID_PROPERTY;
/**
@@ -82,7 +96,7 @@ public class CassandraEntityViewDao extends CassandraAbstractSearchTextDao<Entit
public List<EntityView> findEntityViewsByTenantId(UUID tenantId, TextPageLink pageLink) {
log.debug("Try to find entity views by tenantId [{}] and pageLink [{}]", tenantId, pageLink);
List<EntityViewEntity> entityViewEntities =
- findPageWithTextSearch(ENTITY_VIEW_BY_TENANT_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME,
+ findPageWithTextSearch(ENTITY_VIEW_BY_TENANT_AND_SEARCH_TEXT_CF,
Collections.singletonList(eq(TENANT_ID_PROPERTY, tenantId)), pageLink);
log.trace("Found entity views [{}] by tenantId [{}] and pageLink [{}]",
entityViewEntities, tenantId, pageLink);
@@ -90,6 +104,18 @@ public class CassandraEntityViewDao extends CassandraAbstractSearchTextDao<Entit
}
@Override
+ public List<EntityView> findEntityViewsByTenantIdAndType(UUID tenantId, String type, TextPageLink pageLink) {
+ log.debug("Try to find entity views by tenantId [{}], type [{}] and pageLink [{}]", tenantId, type, pageLink);
+ List<EntityViewEntity> entityViewEntities =
+ findPageWithTextSearch(ENTITY_VIEW_BY_TENANT_BY_TYPE_AND_SEARCH_TEXT_CF,
+ Arrays.asList(eq(ENTITY_VIEW_TYPE_PROPERTY, type),
+ eq(TENANT_ID_PROPERTY, tenantId)), pageLink);
+ log.trace("Found entity views [{}] by tenantId [{}], type [{}] and pageLink [{}]",
+ entityViewEntities, tenantId, type, pageLink);
+ return DaoUtil.convertDataList(entityViewEntities);
+ }
+
+ @Override
public Optional<EntityView> findEntityViewByTenantIdAndName(UUID tenantId, String name) {
Select.Where query = select().from(ENTITY_VIEW_BY_TENANT_AND_NAME).where();
query.and(eq(ENTITY_VIEW_TENANT_ID_PROPERTY, tenantId));
@@ -111,6 +137,19 @@ public class CassandraEntityViewDao extends CassandraAbstractSearchTextDao<Entit
}
@Override
+ public List<EntityView> findEntityViewsByTenantIdAndCustomerIdAndType(UUID tenantId, UUID customerId, String type, TextPageLink pageLink) {
+ log.debug("Try to find entity views by tenantId [{}], customerId[{}], type [{}] and pageLink [{}]",
+ tenantId, customerId, type, pageLink);
+ List<EntityViewEntity> entityViewEntities = findPageWithTextSearch(
+ ENTITY_VIEW_BY_TENANT_AND_CUSTOMER_AND_TYPE_CF,
+ Arrays.asList(eq(DEVICE_TYPE_PROPERTY, type), eq(CUSTOMER_ID_PROPERTY, customerId), eq(TENANT_ID_PROPERTY, tenantId)),
+ pageLink);
+ log.trace("Found find entity views [{}] by tenantId [{}], customerId [{}], type [{}] and pageLink [{}]",
+ entityViewEntities, tenantId, customerId, type, pageLink);
+ return DaoUtil.convertDataList(entityViewEntities);
+ }
+
+ @Override
public ListenableFuture<List<EntityView>> findEntityViewsByTenantIdAndEntityIdAsync(UUID tenantId, UUID entityId) {
log.debug("Try to find entity views by tenantId [{}] and entityId [{}]", tenantId, entityId);
Select.Where query = select().from(ENTITY_VIEW_BY_TENANT_AND_ENTITY_ID_CF).where();
@@ -118,4 +157,30 @@ public class CassandraEntityViewDao extends CassandraAbstractSearchTextDao<Entit
query.and(eq(ENTITY_ID_COLUMN, entityId));
return findListByStatementAsync(query);
}
+
+ @Override
+ public ListenableFuture<List<EntitySubtype>> findTenantEntityViewTypesAsync(UUID tenantId) {
+ Select select = select().from(ENTITY_SUBTYPE_COLUMN_FAMILY_NAME);
+ Select.Where query = select.where();
+ query.and(eq(ENTITY_SUBTYPE_TENANT_ID_PROPERTY, tenantId));
+ query.and(eq(ENTITY_SUBTYPE_ENTITY_TYPE_PROPERTY, EntityType.ENTITY_VIEW));
+ query.setConsistencyLevel(cluster.getDefaultReadConsistencyLevel());
+ ResultSetFuture resultSetFuture = executeAsyncRead(query);
+ return Futures.transform(resultSetFuture, new Function<ResultSet, List<EntitySubtype>>() {
+ @Nullable
+ @Override
+ public List<EntitySubtype> apply(@Nullable ResultSet resultSet) {
+ Result<EntitySubtypeEntity> result = cluster.getMapper(EntitySubtypeEntity.class).map(resultSet);
+ if (result != null) {
+ List<EntitySubtype> entitySubtypes = new ArrayList<>();
+ result.all().forEach((entitySubtypeEntity) ->
+ entitySubtypes.add(entitySubtypeEntity.toEntitySubtype())
+ );
+ return entitySubtypes;
+ } else {
+ return Collections.emptyList();
+ }
+ }
+ });
+ }
}
diff --git a/dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewDao.java b/dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewDao.java
index ba43385..8147a07 100644
--- a/dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewDao.java
+++ b/dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewDao.java
@@ -17,6 +17,7 @@ package org.thingsboard.server.dao.entityview;
import com.google.common.util.concurrent.ListenableFuture;
import org.thingsboard.server.common.data.Device;
+import org.thingsboard.server.common.data.EntitySubtype;
import org.thingsboard.server.common.data.EntityView;
import org.thingsboard.server.common.data.page.TextPageLink;
import org.thingsboard.server.dao.Dao;
@@ -48,6 +49,16 @@ public interface EntityViewDao extends Dao<EntityView> {
List<EntityView> findEntityViewsByTenantId(UUID tenantId, TextPageLink pageLink);
/**
+ * Find entity views by tenantId, type and page link.
+ *
+ * @param tenantId the tenantId
+ * @param type the type
+ * @param pageLink the page link
+ * @return the list of entity view objects
+ */
+ List<EntityView> findEntityViewsByTenantIdAndType(UUID tenantId, String type, TextPageLink pageLink);
+
+ /**
* Find entity views by tenantId and entity view name.
*
* @param tenantId the tenantId
@@ -68,6 +79,27 @@ public interface EntityViewDao extends Dao<EntityView> {
UUID customerId,
TextPageLink pageLink);
+ /**
+ * Find entity views by tenantId, customerId, type and page link.
+ *
+ * @param tenantId the tenantId
+ * @param customerId the customerId
+ * @param type the type
+ * @param pageLink the page link
+ * @return the list of entity view objects
+ */
+ List<EntityView> findEntityViewsByTenantIdAndCustomerIdAndType(UUID tenantId,
+ UUID customerId,
+ String type,
+ TextPageLink pageLink);
ListenableFuture<List<EntityView>> findEntityViewsByTenantIdAndEntityIdAsync(UUID tenantId, UUID entityId);
+
+ /**
+ * Find tenants entity view types.
+ *
+ * @return the list of tenant entity view type objects
+ */
+ ListenableFuture<List<EntitySubtype>> findTenantEntityViewTypesAsync(UUID tenantId);
+
}
diff --git a/dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewService.java b/dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewService.java
index 19f326c..da87b44 100644
--- a/dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewService.java
+++ b/dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewService.java
@@ -16,6 +16,7 @@
package org.thingsboard.server.dao.entityview;
import com.google.common.util.concurrent.ListenableFuture;
+import org.thingsboard.server.common.data.EntitySubtype;
import org.thingsboard.server.common.data.EntityView;
import org.thingsboard.server.common.data.entityview.EntityViewSearchQuery;
import org.thingsboard.server.common.data.id.CustomerId;
@@ -44,8 +45,12 @@ public interface EntityViewService {
TextPageData<EntityView> findEntityViewByTenantId(TenantId tenantId, TextPageLink pageLink);
+ TextPageData<EntityView> findEntityViewByTenantIdAndType(TenantId tenantId, TextPageLink pageLink, String type);
+
TextPageData<EntityView> findEntityViewsByTenantIdAndCustomerId(TenantId tenantId, CustomerId customerId, TextPageLink pageLink);
+ TextPageData<EntityView> findEntityViewsByTenantIdAndCustomerIdAndType(TenantId tenantId, CustomerId customerId, TextPageLink pageLink, String type);
+
ListenableFuture<List<EntityView>> findEntityViewsByQuery(EntityViewSearchQuery query);
ListenableFuture<EntityView> findEntityViewByIdAsync(EntityViewId entityViewId);
@@ -55,4 +60,6 @@ public interface EntityViewService {
void deleteEntityView(EntityViewId entityViewId);
void deleteEntityViewsByTenantId(TenantId tenantId);
+
+ ListenableFuture<List<EntitySubtype>> findEntityViewTypesByTenantId(TenantId tenantId);
}
diff --git a/dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewServiceImpl.java
index 2c5ec75..6b4ffbc 100644
--- a/dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewServiceImpl.java
+++ b/dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewServiceImpl.java
@@ -15,6 +15,7 @@
*/
package org.thingsboard.server.dao.entityview;
+import com.google.common.base.Function;
import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
@@ -29,6 +30,8 @@ import org.springframework.cache.annotation.Caching;
import org.springframework.stereotype.Service;
import org.thingsboard.server.common.data.Customer;
import org.thingsboard.server.common.data.DataConstants;
+import org.thingsboard.server.common.data.Device;
+import org.thingsboard.server.common.data.EntitySubtype;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.EntityView;
import org.thingsboard.server.common.data.Tenant;
@@ -54,6 +57,8 @@ import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.stream.Collectors;
@@ -63,6 +68,7 @@ import static org.thingsboard.server.common.data.CacheConstants.RELATIONS_CACHE;
import static org.thingsboard.server.dao.model.ModelConstants.NULL_UUID;
import static org.thingsboard.server.dao.service.Validator.validateId;
import static org.thingsboard.server.dao.service.Validator.validatePageLink;
+import static org.thingsboard.server.dao.service.Validator.validateString;
/**
* Created by Victor Basanets on 8/28/2017.
@@ -158,6 +164,16 @@ public class EntityViewServiceImpl extends AbstractEntityService implements Enti
}
@Override
+ public TextPageData<EntityView> findEntityViewByTenantIdAndType(TenantId tenantId, TextPageLink pageLink, String type) {
+ log.trace("Executing findEntityViewByTenantIdAndType, tenantId [{}], pageLink [{}], type [{}]", tenantId, pageLink, type);
+ validateId(tenantId, INCORRECT_TENANT_ID + tenantId);
+ validatePageLink(pageLink, INCORRECT_PAGE_LINK + pageLink);
+ validateString(type, "Incorrect type " + type);
+ List<EntityView> entityViews = entityViewDao.findEntityViewsByTenantIdAndType(tenantId.getId(), type, pageLink);
+ return new TextPageData<>(entityViews, pageLink);
+ }
+
+ @Override
public TextPageData<EntityView> findEntityViewsByTenantIdAndCustomerId(TenantId tenantId, CustomerId customerId,
TextPageLink pageLink) {
log.trace("Executing findEntityViewByTenantIdAndCustomerId, tenantId [{}], customerId [{}]," +
@@ -171,6 +187,19 @@ public class EntityViewServiceImpl extends AbstractEntityService implements Enti
}
@Override
+ public TextPageData<EntityView> findEntityViewsByTenantIdAndCustomerIdAndType(TenantId tenantId, CustomerId customerId, TextPageLink pageLink, String type) {
+ log.trace("Executing findEntityViewsByTenantIdAndCustomerIdAndType, tenantId [{}], customerId [{}]," +
+ " pageLink [{}], type [{}]", tenantId, customerId, pageLink, type);
+ validateId(tenantId, INCORRECT_TENANT_ID + tenantId);
+ validateId(customerId, INCORRECT_CUSTOMER_ID + customerId);
+ validatePageLink(pageLink, INCORRECT_PAGE_LINK + pageLink);
+ validateString(type, "Incorrect type " + type);
+ List<EntityView> entityViews = entityViewDao.findEntityViewsByTenantIdAndCustomerIdAndType(tenantId.getId(),
+ customerId.getId(), type, pageLink);
+ return new TextPageData<>(entityViews, pageLink);
+ }
+
+ @Override
public ListenableFuture<List<EntityView>> findEntityViewsByQuery(EntityViewSearchQuery query) {
ListenableFuture<List<EntityRelation>> relations = relationService.findByQuery(query.toEntitySearchQuery());
ListenableFuture<List<EntityView>> entityViews = Futures.transformAsync(relations, r -> {
@@ -184,6 +213,15 @@ public class EntityViewServiceImpl extends AbstractEntityService implements Enti
}
return Futures.successfulAsList(futures);
});
+
+ entityViews = Futures.transform(entityViews, new Function<List<EntityView>, List<EntityView>>() {
+ @Nullable
+ @Override
+ public List<EntityView> apply(@Nullable List<EntityView> entityViewList) {
+ return entityViewList == null ? Collections.emptyList() : entityViewList.stream().filter(entityView -> query.getEntityViewTypes().contains(entityView.getType())).collect(Collectors.toList());
+ }
+ });
+
return entityViews;
}
@@ -216,6 +254,7 @@ public class EntityViewServiceImpl extends AbstractEntityService implements Enti
public void onSuccess(@Nullable List<EntityView> result) {
cache.putIfAbsent(tenantIdAndEntityId, result);
}
+
@Override
public void onFailure(Throwable t) {
log.error("Error while finding entity views by tenantId and entityId", t);
@@ -243,6 +282,18 @@ public class EntityViewServiceImpl extends AbstractEntityService implements Enti
tenantEntityViewRemover.removeEntities(tenantId);
}
+ @Override
+ public ListenableFuture<List<EntitySubtype>> findEntityViewTypesByTenantId(TenantId tenantId) {
+ log.trace("Executing findEntityViewTypesByTenantId, tenantId [{}]", tenantId);
+ validateId(tenantId, INCORRECT_TENANT_ID + tenantId);
+ ListenableFuture<List<EntitySubtype>> tenantEntityViewTypes = entityViewDao.findTenantEntityViewTypesAsync(tenantId.getId());
+ return Futures.transform(tenantEntityViewTypes,
+ entityViewTypes -> {
+ entityViewTypes.sort(Comparator.comparing(EntitySubtype::getType));
+ return entityViewTypes;
+ });
+ }
+
private ListenableFuture<List<Void>> copyAttributesFromEntityToEntityView(EntityView entityView, String scope, Collection<String> keys) {
if (keys != null && !keys.isEmpty()) {
ListenableFuture<List<AttributeKvEntry>> getAttrFuture = attributesService.find(entityView.getEntityId(), scope, keys);
@@ -296,6 +347,9 @@ public class EntityViewServiceImpl extends AbstractEntityService implements Enti
@Override
protected void validateDataImpl(EntityView entityView) {
+ if (StringUtils.isEmpty(entityView.getType())) {
+ throw new DataValidationException("Entity View type should be specified!");
+ }
if (StringUtils.isEmpty(entityView.getName())) {
throw new DataValidationException("Entity view name should be specified!");
}
diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/ModelConstants.java b/dao/src/main/java/org/thingsboard/server/dao/model/ModelConstants.java
index a487ede..86ba594 100644
--- a/dao/src/main/java/org/thingsboard/server/dao/model/ModelConstants.java
+++ b/dao/src/main/java/org/thingsboard/server/dao/model/ModelConstants.java
@@ -145,18 +145,21 @@ public class ModelConstants {
/**
* Cassandra entityView constants.
*/
- public static final String ENTITY_VIEW_TABLE_FAMILY_NAME = "entity_views";
+ public static final String ENTITY_VIEW_TABLE_FAMILY_NAME = "entity_view";
public static final String ENTITY_VIEW_ENTITY_ID_PROPERTY = ENTITY_ID_COLUMN;
public static final String ENTITY_VIEW_TENANT_ID_PROPERTY = TENANT_ID_PROPERTY;
public static final String ENTITY_VIEW_CUSTOMER_ID_PROPERTY = CUSTOMER_ID_PROPERTY;
public static final String ENTITY_VIEW_NAME_PROPERTY = DEVICE_NAME_PROPERTY;
public static final String ENTITY_VIEW_BY_TENANT_AND_CUSTOMER_CF = "entity_view_by_tenant_and_customer";
+ public static final String ENTITY_VIEW_BY_TENANT_AND_CUSTOMER_AND_TYPE_CF = "entity_view_by_tenant_and_customer_and_type";
public static final String ENTITY_VIEW_BY_TENANT_AND_ENTITY_ID_CF = "entity_view_by_tenant_and_entity_id";
public static final String ENTITY_VIEW_KEYS_PROPERTY = "keys";
+ public static final String ENTITY_VIEW_TYPE_PROPERTY = "type";
public static final String ENTITY_VIEW_START_TS_PROPERTY = "start_ts";
public static final String ENTITY_VIEW_END_TS_PROPERTY = "end_ts";
public static final String ENTITY_VIEW_ADDITIONAL_INFO_PROPERTY = ADDITIONAL_INFO_PROPERTY;
- public static final String ENTITY_VIEW_BY_TENANT_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME = "entity_view_by_tenant_and_search_text";
+ public static final String ENTITY_VIEW_BY_TENANT_AND_SEARCH_TEXT_CF = "entity_view_by_tenant_and_search_text";
+ public static final String ENTITY_VIEW_BY_TENANT_BY_TYPE_AND_SEARCH_TEXT_CF = "entity_view_by_tenant_by_type_and_search_text";
public static final String ENTITY_VIEW_BY_TENANT_AND_NAME = "entity_view_by_tenant_and_name";
/**
diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/nosql/EntityViewEntity.java b/dao/src/main/java/org/thingsboard/server/dao/model/nosql/EntityViewEntity.java
index eb7f4fe..cda4217 100644
--- a/dao/src/main/java/org/thingsboard/server/dao/model/nosql/EntityViewEntity.java
+++ b/dao/src/main/java/org/thingsboard/server/dao/model/nosql/EntityViewEntity.java
@@ -41,6 +41,7 @@ import javax.persistence.Enumerated;
import java.io.IOException;
import java.util.UUID;
+import static org.thingsboard.server.dao.model.ModelConstants.DEVICE_TYPE_PROPERTY;
import static org.thingsboard.server.dao.model.ModelConstants.ENTITY_TYPE_PROPERTY;
import static org.thingsboard.server.dao.model.ModelConstants.ENTITY_VIEW_TABLE_FAMILY_NAME;
import static org.thingsboard.server.dao.model.ModelConstants.ID_PROPERTY;
@@ -71,6 +72,10 @@ public class EntityViewEntity implements SearchTextEntity<EntityView> {
@Column(name = ModelConstants.ENTITY_VIEW_CUSTOMER_ID_PROPERTY)
private UUID customerId;
+ @PartitionKey(value = 3)
+ @Column(name = DEVICE_TYPE_PROPERTY)
+ private String type;
+
@Column(name = ModelConstants.ENTITY_VIEW_ENTITY_ID_PROPERTY)
private UUID entityId;
@@ -113,6 +118,7 @@ public class EntityViewEntity implements SearchTextEntity<EntityView> {
if (entityView.getCustomerId() != null) {
this.customerId = entityView.getCustomerId().getId();
}
+ this.type = entityView.getType();
this.name = entityView.getName();
try {
this.keys = mapper.writeValueAsString(entityView.getKeys());
@@ -143,6 +149,7 @@ public class EntityViewEntity implements SearchTextEntity<EntityView> {
if (customerId != null) {
entityView.setCustomerId(new CustomerId(customerId));
}
+ entityView.setType(type);
entityView.setName(name);
try {
entityView.setKeys(mapper.readValue(keys, TelemetryEntityView.class));
diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/sql/EntityViewEntity.java b/dao/src/main/java/org/thingsboard/server/dao/model/sql/EntityViewEntity.java
index 60f6951..6999c0c 100644
--- a/dao/src/main/java/org/thingsboard/server/dao/model/sql/EntityViewEntity.java
+++ b/dao/src/main/java/org/thingsboard/server/dao/model/sql/EntityViewEntity.java
@@ -69,6 +69,9 @@ public class EntityViewEntity extends BaseSqlEntity<EntityView> implements Searc
@Column(name = ModelConstants.ENTITY_VIEW_CUSTOMER_ID_PROPERTY)
private String customerId;
+ @Column(name = ModelConstants.DEVICE_TYPE_PROPERTY)
+ private String type;
+
@Column(name = ModelConstants.ENTITY_VIEW_NAME_PROPERTY)
private String name;
@@ -108,6 +111,7 @@ public class EntityViewEntity extends BaseSqlEntity<EntityView> implements Searc
if (entityView.getCustomerId() != null) {
this.customerId = toString(entityView.getCustomerId().getId());
}
+ this.type = entityView.getType();
this.name = entityView.getName();
try {
this.keys = mapper.writeValueAsString(entityView.getKeys());
@@ -144,6 +148,7 @@ public class EntityViewEntity extends BaseSqlEntity<EntityView> implements Searc
if (customerId != null) {
entityView.setCustomerId(new CustomerId(toUUID(customerId)));
}
+ entityView.setType(type);
entityView.setName(name);
try {
entityView.setKeys(mapper.readValue(keys, TelemetryEntityView.class));
diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/entityview/EntityViewRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/entityview/EntityViewRepository.java
index 0f5fdf5..efd1bd9 100644
--- a/dao/src/main/java/org/thingsboard/server/dao/sql/entityview/EntityViewRepository.java
+++ b/dao/src/main/java/org/thingsboard/server/dao/sql/entityview/EntityViewRepository.java
@@ -19,8 +19,6 @@ import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.CrudRepository;
import org.springframework.data.repository.query.Param;
-import org.thingsboard.server.common.data.EntityView;
-import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.dao.model.sql.EntityViewEntity;
import org.thingsboard.server.dao.util.SqlDao;
@@ -36,21 +34,46 @@ public interface EntityViewRepository extends CrudRepository<EntityViewEntity, S
"AND LOWER(e.searchText) LIKE LOWER(CONCAT(:textSearch, '%')) " +
"AND e.id > :idOffset ORDER BY e.id")
List<EntityViewEntity> findByTenantId(@Param("tenantId") String tenantId,
- @Param("textSearch") String textSearch,
- @Param("idOffset") String idOffset,
- Pageable pageable);
+ @Param("textSearch") String textSearch,
+ @Param("idOffset") String idOffset,
+ Pageable pageable);
+
+ @Query("SELECT e FROM EntityViewEntity e WHERE e.tenantId = :tenantId " +
+ "AND e.type = :type " +
+ "AND LOWER(e.searchText) LIKE LOWER(CONCAT(:textSearch, '%')) " +
+ "AND e.id > :idOffset ORDER BY e.id")
+ List<EntityViewEntity> findByTenantIdAndType(@Param("tenantId") String tenantId,
+ @Param("type") String type,
+ @Param("textSearch") String textSearch,
+ @Param("idOffset") String idOffset,
+ Pageable pageable);
@Query("SELECT e FROM EntityViewEntity e WHERE e.tenantId = :tenantId " +
"AND e.customerId = :customerId " +
"AND LOWER(e.searchText) LIKE LOWER(CONCAT(:searchText, '%')) " +
"AND e.id > :idOffset ORDER BY e.id")
List<EntityViewEntity> findByTenantIdAndCustomerId(@Param("tenantId") String tenantId,
- @Param("customerId") String customerId,
- @Param("searchText") String searchText,
- @Param("idOffset") String idOffset,
- Pageable pageable);
+ @Param("customerId") String customerId,
+ @Param("searchText") String searchText,
+ @Param("idOffset") String idOffset,
+ Pageable pageable);
+
+ @Query("SELECT e FROM EntityViewEntity e WHERE e.tenantId = :tenantId " +
+ "AND e.customerId = :customerId " +
+ "AND e.type = :type " +
+ "AND LOWER(e.searchText) LIKE LOWER(CONCAT(:searchText, '%')) " +
+ "AND e.id > :idOffset ORDER BY e.id")
+ List<EntityViewEntity> findByTenantIdAndCustomerIdAndType(@Param("tenantId") String tenantId,
+ @Param("customerId") String customerId,
+ @Param("type") String type,
+ @Param("searchText") String searchText,
+ @Param("idOffset") String idOffset,
+ Pageable pageable);
EntityViewEntity findByTenantIdAndName(String tenantId, String name);
List<EntityViewEntity> findAllByTenantIdAndEntityId(String tenantId, String entityId);
+
+ @Query("SELECT DISTINCT ev.type FROM EntityViewEntity ev WHERE ev.tenantId = :tenantId")
+ List<String> findTenantEntityViewTypes(@Param("tenantId") String tenantId);
}
diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/entityview/JpaEntityViewDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/entityview/JpaEntityViewDao.java
index 912c9d5..1ba9b9e 100644
--- a/dao/src/main/java/org/thingsboard/server/dao/sql/entityview/JpaEntityViewDao.java
+++ b/dao/src/main/java/org/thingsboard/server/dao/sql/entityview/JpaEntityViewDao.java
@@ -24,7 +24,6 @@ import org.thingsboard.server.common.data.EntitySubtype;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.EntityView;
import org.thingsboard.server.common.data.UUIDConverter;
-import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.page.TextPageLink;
import org.thingsboard.server.dao.DaoUtil;
@@ -41,7 +40,6 @@ import java.util.Optional;
import java.util.UUID;
import static org.thingsboard.server.common.data.UUIDConverter.fromTimeUUID;
-import static org.thingsboard.server.common.data.UUIDConverter.fromTimeUUIDs;
import static org.thingsboard.server.dao.model.ModelConstants.NULL_UUID_STR;
/**
@@ -76,6 +74,17 @@ public class JpaEntityViewDao extends JpaAbstractSearchTextDao<EntityViewEntity,
}
@Override
+ public List<EntityView> findEntityViewsByTenantIdAndType(UUID tenantId, String type, TextPageLink pageLink) {
+ return DaoUtil.convertDataList(
+ entityViewRepository.findByTenantIdAndType(
+ fromTimeUUID(tenantId),
+ type,
+ Objects.toString(pageLink.getTextSearch(), ""),
+ pageLink.getIdOffset() == null ? NULL_UUID_STR : fromTimeUUID(pageLink.getIdOffset()),
+ new PageRequest(0, pageLink.getLimit())));
+ }
+
+ @Override
public Optional<EntityView> findEntityViewByTenantIdAndName(UUID tenantId, String name) {
return Optional.ofNullable(
DaoUtil.getData(entityViewRepository.findByTenantIdAndName(fromTimeUUID(tenantId), name)));
@@ -96,8 +105,37 @@ public class JpaEntityViewDao extends JpaAbstractSearchTextDao<EntityViewEntity,
}
@Override
+ public List<EntityView> findEntityViewsByTenantIdAndCustomerIdAndType(UUID tenantId, UUID customerId, String type, TextPageLink pageLink) {
+ return DaoUtil.convertDataList(
+ entityViewRepository.findByTenantIdAndCustomerIdAndType(
+ fromTimeUUID(tenantId),
+ fromTimeUUID(customerId),
+ type,
+ Objects.toString(pageLink.getTextSearch(), ""),
+ pageLink.getIdOffset() == null ? NULL_UUID_STR : fromTimeUUID(pageLink.getIdOffset()),
+ new PageRequest(0, pageLink.getLimit())
+ ));
+ }
+
+ @Override
public ListenableFuture<List<EntityView>> findEntityViewsByTenantIdAndEntityIdAsync(UUID tenantId, UUID entityId) {
return service.submit(() -> DaoUtil.convertDataList(
entityViewRepository.findAllByTenantIdAndEntityId(UUIDConverter.fromTimeUUID(tenantId), UUIDConverter.fromTimeUUID(entityId))));
}
+
+ @Override
+ public ListenableFuture<List<EntitySubtype>> findTenantEntityViewTypesAsync(UUID tenantId) {
+ return service.submit(() -> convertTenantEntityViewTypesToDto(tenantId, entityViewRepository.findTenantEntityViewTypes(fromTimeUUID(tenantId))));
+ }
+
+ private List<EntitySubtype> convertTenantEntityViewTypesToDto(UUID tenantId, List<String> types) {
+ List<EntitySubtype> list = Collections.emptyList();
+ if (types != null && !types.isEmpty()) {
+ list = new ArrayList<>();
+ for (String type : types) {
+ list.add(new EntitySubtype(new TenantId(tenantId), EntityType.ENTITY_VIEW, type));
+ }
+ }
+ return list;
+ }
}
diff --git a/dao/src/main/resources/cassandra/schema-entities.cql b/dao/src/main/resources/cassandra/schema-entities.cql
index 7ccd41f..ef27c70 100644
--- a/dao/src/main/resources/cassandra/schema-entities.cql
+++ b/dao/src/main/resources/cassandra/schema-entities.cql
@@ -624,61 +624,90 @@ CREATE TABLE IF NOT EXISTS thingsboard.rule_node (
PRIMARY KEY (id)
);
-CREATE TABLE IF NOT EXISTS thingsboard.entity_views (
+CREATE TABLE IF NOT EXISTS thingsboard.entity_view (
id timeuuid,
entity_id timeuuid,
entity_type text,
tenant_id timeuuid,
customer_id timeuuid,
name text,
+ type text,
keys text,
start_ts bigint,
end_ts bigint,
search_text text,
additional_info text,
- PRIMARY KEY (id, entity_id, tenant_id, customer_id)
+ PRIMARY KEY (id, entity_id, tenant_id, customer_id, type)
);
CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.entity_view_by_tenant_and_name AS
SELECT *
- from thingsboard.entity_views
+ from thingsboard.entity_view
WHERE tenant_id IS NOT NULL
AND entity_id IS NOT NULL
AND customer_id IS NOT NULL
+ AND type IS NOT NULL
AND name IS NOT NULL
AND id IS NOT NULL
- PRIMARY KEY (tenant_id, name, id, customer_id, entity_id)
+ PRIMARY KEY (tenant_id, name, id, customer_id, entity_id, type)
WITH CLUSTERING ORDER BY (name ASC, id DESC, customer_id DESC);
CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.entity_view_by_tenant_and_search_text AS
SELECT *
- from thingsboard.entity_views
+ from thingsboard.entity_view
WHERE tenant_id IS NOT NULL
AND entity_id IS NOT NULL
AND customer_id IS NOT NULL
+ AND type IS NOT NULL
AND search_text IS NOT NULL
AND id IS NOT NULL
- PRIMARY KEY (tenant_id, search_text, id, customer_id, entity_id)
+ PRIMARY KEY (tenant_id, search_text, id, customer_id, entity_id, type)
WITH CLUSTERING ORDER BY (search_text ASC, id DESC, customer_id DESC);
+CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.entity_view_by_tenant_by_type_and_search_text AS
+ SELECT *
+ from thingsboard.entity_view
+ WHERE tenant_id IS NOT NULL
+ AND entity_id IS NOT NULL
+ AND customer_id IS NOT NULL
+ AND type IS NOT NULL
+ AND search_text IS NOT NULL
+ AND id IS NOT NULL
+ PRIMARY KEY (tenant_id, type, search_text, id, customer_id, entity_id)
+ WITH CLUSTERING ORDER BY (type ASC, search_text ASC, id DESC, customer_id DESC);
+
CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.entity_view_by_tenant_and_customer AS
SELECT *
- from thingsboard.entity_views
+ from thingsboard.entity_view
WHERE tenant_id IS NOT NULL
AND customer_id IS NOT NULL
AND entity_id IS NOT NULL
+ AND type IS NOT NULL
AND search_text IS NOT NULL
AND id IS NOT NULL
- PRIMARY KEY (tenant_id, customer_id, search_text, id, entity_id)
+ PRIMARY KEY (tenant_id, customer_id, search_text, id, entity_id, type)
WITH CLUSTERING ORDER BY (customer_id DESC, search_text ASC, id DESC);
+CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.entity_view_by_tenant_and_customer_and_type AS
+ SELECT *
+ from thingsboard.entity_view
+ WHERE tenant_id IS NOT NULL
+ AND customer_id IS NOT NULL
+ AND entity_id IS NOT NULL
+ AND type IS NOT NULL
+ AND search_text IS NOT NULL
+ AND id IS NOT NULL
+ PRIMARY KEY (tenant_id, type, customer_id, search_text, id, entity_id)
+ WITH CLUSTERING ORDER BY (type ASC, customer_id DESC, search_text ASC, id DESC);
+
CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.entity_view_by_tenant_and_entity_id AS
SELECT *
- from thingsboard.entity_views
+ from thingsboard.entity_view
WHERE tenant_id IS NOT NULL
AND customer_id IS NOT NULL
AND entity_id IS NOT NULL
+ AND type IS NOT NULL
AND search_text IS NOT NULL
AND id IS NOT NULL
- PRIMARY KEY (tenant_id, entity_id, customer_id, search_text, id)
+ PRIMARY KEY (tenant_id, entity_id, customer_id, search_text, id, type)
WITH CLUSTERING ORDER BY (entity_id DESC, customer_id DESC, search_text ASC, id DESC);
\ No newline at end of file
diff --git a/dao/src/main/resources/sql/schema-entities.sql b/dao/src/main/resources/sql/schema-entities.sql
index abd20ab..0b9c853 100644
--- a/dao/src/main/resources/sql/schema-entities.sql
+++ b/dao/src/main/resources/sql/schema-entities.sql
@@ -228,12 +228,13 @@ CREATE TABLE IF NOT EXISTS rule_node (
search_text varchar(255)
);
-CREATE TABLE IF NOT EXISTS entity_views (
+CREATE TABLE IF NOT EXISTS entity_view (
id varchar(31) NOT NULL CONSTRAINT entity_view_pkey PRIMARY KEY,
entity_id varchar(31),
entity_type varchar(255),
tenant_id varchar(31),
customer_id varchar(31),
+ type varchar(255),
name varchar(255),
keys varchar(255),
start_ts bigint,
diff --git a/dao/src/test/resources/sql/drop-all-tables.sql b/dao/src/test/resources/sql/drop-all-tables.sql
index b1fb72c..1bdc1a7 100644
--- a/dao/src/test/resources/sql/drop-all-tables.sql
+++ b/dao/src/test/resources/sql/drop-all-tables.sql
@@ -19,4 +19,4 @@ DROP TABLE IF EXISTS widget_type;
DROP TABLE IF EXISTS widgets_bundle;
DROP TABLE IF EXISTS rule_node;
DROP TABLE IF EXISTS rule_chain;
-DROP TABLE IF EXISTS entity_views;
+DROP TABLE IF EXISTS entity_view;
ui/src/app/api/entity.service.js 33(+33 -0)
diff --git a/ui/src/app/api/entity.service.js b/ui/src/app/api/entity.service.js
index ce4dc42..205abc9 100644
--- a/ui/src/app/api/entity.service.js
+++ b/ui/src/app/api/entity.service.js
@@ -533,6 +533,21 @@ function EntityService($http, $q, $filter, $translate, $log, userService, device
}
);
break;
+ case types.aliasFilterType.entityViewType.value:
+ getEntitiesByNameFilter(types.entityType.entityView, filter.entityViewNameFilter, maxItems, {ignoreLoading: true}, filter.entityViewType).then(
+ function success(entities) {
+ if (entities && entities.length || !failOnEmpty) {
+ result.entities = entitiesToEntitiesInfo(entities);
+ deferred.resolve(result);
+ } else {
+ deferred.reject();
+ }
+ },
+ function fail() {
+ deferred.reject();
+ }
+ );
+ break;
case types.aliasFilterType.relationsQuery.value:
result.stateEntity = filter.rootStateEntity;
var rootEntityType;
@@ -578,6 +593,7 @@ function EntityService($http, $q, $filter, $translate, $log, userService, device
break;
case types.aliasFilterType.assetSearchQuery.value:
case types.aliasFilterType.deviceSearchQuery.value:
+ case types.aliasFilterType.entityViewSearchQuery.value:
result.stateEntity = filter.rootStateEntity;
if (result.stateEntity && stateEntityId) {
rootEntityType = stateEntityId.entityType;
@@ -604,6 +620,9 @@ function EntityService($http, $q, $filter, $translate, $log, userService, device
} else if (filter.type == types.aliasFilterType.deviceSearchQuery.value) {
searchQuery.deviceTypes = filter.deviceTypes;
findByQueryPromise = deviceService.findByQuery(searchQuery, false, {ignoreLoading: true});
+ } else if (filter.type == types.aliasFilterType.entityViewSearchQuery.value) {
+ searchQuery.entityViewTypes = filter.entityViewTypes;
+ findByQueryPromise = entityViewService.findByQuery(searchQuery, false, {ignoreLoading: true});
}
findByQueryPromise.then(
function success(entities) {
@@ -646,6 +665,8 @@ function EntityService($http, $q, $filter, $translate, $log, userService, device
return entityTypes.indexOf(types.entityType.asset) > -1 ? true : false;
case types.aliasFilterType.deviceType.value:
return entityTypes.indexOf(types.entityType.device) > -1 ? true : false;
+ case types.aliasFilterType.entityViewType.value:
+ return entityTypes.indexOf(types.entityType.entityView) > -1 ? true : false;
case types.aliasFilterType.relationsQuery.value:
if (filter.filters && filter.filters.length) {
var match = false;
@@ -671,6 +692,8 @@ function EntityService($http, $q, $filter, $translate, $log, userService, device
return entityTypes.indexOf(types.entityType.asset) > -1 ? true : false;
case types.aliasFilterType.deviceSearchQuery.value:
return entityTypes.indexOf(types.entityType.device) > -1 ? true : false;
+ case types.aliasFilterType.entityViewSearchQuery.value:
+ return entityTypes.indexOf(types.entityType.entityView) > -1 ? true : false;
}
}
return false;
@@ -690,12 +713,16 @@ function EntityService($http, $q, $filter, $translate, $log, userService, device
return entityType === types.entityType.asset;
case types.aliasFilterType.deviceType.value:
return entityType === types.entityType.device;
+ case types.aliasFilterType.entityViewType.value:
+ return entityType === types.entityType.entityView;
case types.aliasFilterType.relationsQuery.value:
return true;
case types.aliasFilterType.assetSearchQuery.value:
return entityType === types.entityType.asset;
case types.aliasFilterType.deviceSearchQuery.value:
return entityType === types.entityType.device;
+ case types.aliasFilterType.entityViewSearchQuery.value:
+ return entityType === types.entityType.entityView;
}
return false;
}
@@ -1046,6 +1073,8 @@ function EntityService($http, $q, $filter, $translate, $log, userService, device
return assetService.deleteAsset(entityId.id);
} else if (entityId.entityType == types.entityType.device) {
return deviceService.deleteDevice(entityId.id);
+ } else if (entityId.entityType == types.entityType.entityView) {
+ return entityViewService.deleteEntityView(entityId.id);
}
}
@@ -1151,6 +1180,8 @@ function EntityService($http, $q, $filter, $translate, $log, userService, device
return assetService.saveAsset(entity);
} else if (entityType == types.entityType.device) {
return deviceService.saveDevice(entity);
+ } else if (entityType == types.entityType.entityView) {
+ return entityViewService.saveEntityView(entity);
}
}
@@ -1279,6 +1310,8 @@ function EntityService($http, $q, $filter, $translate, $log, userService, device
searchQuery.assetTypes = entitySubTypes;
} else if (entityType == types.entityType.device) {
searchQuery.deviceTypes = entitySubTypes;
+ } else if (entityType == types.entityType.entityView) {
+ searchQuery.entityViewTypes = entitySubTypes;
} else {
return null; //Not supported
}
ui/src/app/common/types.constant.js 8(+8 -0)
diff --git a/ui/src/app/common/types.constant.js b/ui/src/app/common/types.constant.js
index 15da584..506ef1d 100644
--- a/ui/src/app/common/types.constant.js
+++ b/ui/src/app/common/types.constant.js
@@ -253,6 +253,10 @@ export default angular.module('thingsboard.types', [])
value: 'deviceType',
name: 'alias.filter-type-device-type'
},
+ entityViewType: {
+ value: 'entityViewType',
+ name: 'alias.filter-type-entity-view-type'
+ },
relationsQuery: {
value: 'relationsQuery',
name: 'alias.filter-type-relations-query'
@@ -264,6 +268,10 @@ export default angular.module('thingsboard.types', [])
deviceSearchQuery: {
value: 'deviceSearchQuery',
name: 'alias.filter-type-device-search-query'
+ },
+ entityViewSearchQuery: {
+ value: 'entityViewSearchQuery',
+ name: 'alias.filter-type-entity-view-search-query'
}
},
position: {
diff --git a/ui/src/app/entity/entity-filter.directive.js b/ui/src/app/entity/entity-filter.directive.js
index 0c8f646..38641fb 100644
--- a/ui/src/app/entity/entity-filter.directive.js
+++ b/ui/src/app/entity/entity-filter.directive.js
@@ -69,9 +69,14 @@ export default function EntityFilterDirective($compile, $templateCache, $q, $doc
filter.deviceType = null;
filter.deviceNameFilter = '';
break;
+ case types.aliasFilterType.entityViewType.value:
+ filter.entityViewType = null;
+ filter.entityViewNameFilter = '';
+ break;
case types.aliasFilterType.relationsQuery.value:
case types.aliasFilterType.assetSearchQuery.value:
case types.aliasFilterType.deviceSearchQuery.value:
+ case types.aliasFilterType.entityViewSearchQuery.value:
filter.rootStateEntity = false;
filter.stateEntityParamName = null;
filter.defaultStateEntity = null;
@@ -86,6 +91,9 @@ export default function EntityFilterDirective($compile, $templateCache, $q, $doc
} else if (filter.type === types.aliasFilterType.deviceSearchQuery.value) {
filter.relationType = null;
filter.deviceTypes = [];
+ } else if (filter.type === types.aliasFilterType.entityViewSearchQuery.value) {
+ filter.relationType = null;
+ filter.entityViewTypes = [];
}
break;
}
ui/src/app/entity/entity-filter.tpl.html 83(+83 -0)
diff --git a/ui/src/app/entity/entity-filter.tpl.html b/ui/src/app/entity/entity-filter.tpl.html
index f9aac3c..95193f2 100644
--- a/ui/src/app/entity/entity-filter.tpl.html
+++ b/ui/src/app/entity/entity-filter.tpl.html
@@ -112,6 +112,20 @@
aria-label="{{ 'device.name-starts-with' | translate }}">
</md-input-container>
</section>
+ <section layout="column" ng-if="filter.type == types.aliasFilterType.entityViewType.value" id="entityViewTypeFilter">
+ <tb-entity-subtype-autocomplete
+ tb-required="true"
+ the-form="theForm"
+ ng-model="filter.entityViewType"
+ entity-type="types.entityType.entityView">
+ </tb-entity-subtype-autocomplete>
+ <md-input-container class="md-block">
+ <label translate>entity-view.name-starts-with</label>
+ <input name="entityViewNameFilter"
+ ng-model="filter.entityViewNameFilter"
+ aria-label="{{ 'entity-view.name-starts-with' | translate }}">
+ </md-input-container>
+ </section>
<section layout="column" ng-if="filter.type == types.aliasFilterType.relationsQuery.value" id="relationsQueryFilter">
<label class="tb-small">{{ 'alias.root-entity' | translate }}</label>
<section class="tb-root-state-entity-switch" layout="row" layout-align="start center" style="padding-left: 0px;">
@@ -311,4 +325,73 @@
ng-model="filter.deviceTypes">
</tb-entity-subtype-list>
</section>
+ <section layout="column" ng-if="filter.type == types.aliasFilterType.entityViewSearchQuery.value" id="entityViewSearchQueryFilter">
+ <label class="tb-small">{{ 'alias.root-entity' | translate }}</label>
+ <section class="tb-root-state-entity-switch" layout="row" layout-align="start center" style="padding-left: 0px;">
+ <md-switch class="root-state-entity-switch" ng-model="filter.rootStateEntity"
+ aria-label="{{ 'alias.root-state-entity' | translate }}">
+ </md-switch>
+ <label class="tb-small root-state-entity-label" translate>alias.root-state-entity</label>
+ </section>
+ <div flex layout="row" ng-if="!filter.rootStateEntity">
+ <tb-entity-select flex
+ the-form="theForm"
+ tb-required="!filter.rootStateEntity"
+ ng-disabled="filter.rootStateEntity"
+ use-alias-entity-types="true"
+ ng-model="filter.rootEntity">
+ </tb-entity-select>
+ </div>
+ <div flex layout="row" ng-if="filter.rootStateEntity">
+ <md-input-container class="md-block" style="margin-top: 32px;">
+ <label translate>alias.state-entity-parameter-name</label>
+ <input name="stateEntityParamName"
+ placeholder="{{ 'alias.default-entity-parameter-name' | translate }}"
+ ng-model="filter.stateEntityParamName"
+ aria-label="{{ 'alias.state-entity-parameter-name' | translate }}">
+ </md-input-container>
+ <div flex layout="column">
+ <label class="tb-small">{{ 'alias.default-state-entity' | translate }}</label>
+ <tb-entity-select flex
+ the-form="theForm"
+ tb-required="false"
+ use-alias-entity-types="true"
+ ng-model="filter.defaultStateEntity">
+ </tb-entity-select>
+ </div>
+ </div>
+ <div flex layout="row">
+ <md-input-container class="md-block" style="min-width: 100px;">
+ <label translate>relation.direction</label>
+ <md-select required ng-model="filter.direction">
+ <md-option ng-repeat="direction in types.entitySearchDirection" ng-value="direction">
+ {{ ('relation.search-direction.' + direction) | translate}}
+ </md-option>
+ </md-select>
+ </md-input-container>
+ <md-input-container flex class="md-block">
+ <label translate>alias.max-relation-level</label>
+ <input name="maxRelationLevel"
+ type="number"
+ min="1"
+ step="1"
+ placeholder="{{ 'alias.unlimited-level' | translate }}"
+ ng-model="filter.maxLevel"
+ aria-label="{{ 'alias.max-relation-level' | translate }}">
+ </md-input-container>
+ </div>
+ <div class="md-caption" style="color: rgba(0,0,0,0.57);" translate>relation.relation-type</div>
+ <tb-relation-type-autocomplete flex
+ hide-label
+ the-form="theForm"
+ ng-model="filter.relationType"
+ tb-required="false">
+ </tb-relation-type-autocomplete>
+ <div class="md-caption tb-required" style="color: rgba(0,0,0,0.57);" translate>entity-view.entity-view-types</div>
+ <tb-entity-subtype-list
+ tb-required="true"
+ entity-type="types.entityType.entityView"
+ ng-model="filter.entityViewTypes">
+ </tb-entity-subtype-list>
+ </section>
</div>
diff --git a/ui/src/app/entity/entity-filter-view.directive.js b/ui/src/app/entity/entity-filter-view.directive.js
index 8bd3422..5b34107 100644
--- a/ui/src/app/entity/entity-filter-view.directive.js
+++ b/ui/src/app/entity/entity-filter-view.directive.js
@@ -77,6 +77,15 @@ export default function EntityFilterViewDirective($compile, $templateCache, $q,
scope.filterDisplayValue = $translate.instant('alias.filter-type-device-type-description', {deviceType: deviceType});
}
break;
+ case types.aliasFilterType.entityViewType.value:
+ var entityViewType = scope.filter.entityViewType;
+ prefix = scope.filter.entityViewNameFilter;
+ if (prefix && prefix.length) {
+ scope.filterDisplayValue = $translate.instant('alias.filter-type-entity-view-type-and-name-description', {entityViewType: entityViewType, prefix: prefix});
+ } else {
+ scope.filterDisplayValue = $translate.instant('alias.filter-type-entity-view-type-description', {entityViewType: entityViewType});
+ }
+ break;
case types.aliasFilterType.relationsQuery.value:
var rootEntityText;
var directionText;
@@ -134,6 +143,7 @@ export default function EntityFilterViewDirective($compile, $templateCache, $q,
break;
case types.aliasFilterType.assetSearchQuery.value:
case types.aliasFilterType.deviceSearchQuery.value:
+ case types.aliasFilterType.entityViewSearchQuery.value:
allEntitiesText = $translate.instant('alias.all-entities');
anyRelationText = $translate.instant('alias.any-relation');
if (scope.filter.rootStateEntity) {
@@ -165,7 +175,7 @@ export default function EntityFilterViewDirective($compile, $templateCache, $q,
scope.filterDisplayValue = $translate.instant('alias.filter-type-asset-search-query-description',
translationValues
);
- } else {
+ } else if (scope.filter.type == types.aliasFilterType.deviceSearchQuery.value) {
var deviceTypesQuoted = [];
scope.filter.deviceTypes.forEach(function(deviceType) {
deviceTypesQuoted.push("'"+deviceType+"'");
@@ -175,6 +185,16 @@ export default function EntityFilterViewDirective($compile, $templateCache, $q,
scope.filterDisplayValue = $translate.instant('alias.filter-type-device-search-query-description',
translationValues
);
+ } else if (scope.filter.type == types.aliasFilterType.entityViewSearchQuery.value) {
+ var entityViewTypesQuoted = [];
+ scope.filter.entityViewTypes.forEach(function(entityViewType) {
+ entityViewTypesQuoted.push("'"+entityViewType+"'");
+ });
+ var entityViewTypesText = entityViewTypesQuoted.join(', ');
+ translationValues.entityViewTypes = entityViewTypesText;
+ scope.filterDisplayValue = $translate.instant('alias.filter-type-entity-view-search-query-description',
+ translationValues
+ );
}
break;
default:
diff --git a/ui/src/app/entity/entity-subtype-autocomplete.directive.js b/ui/src/app/entity/entity-subtype-autocomplete.directive.js
index 5812715..6848b5f 100644
--- a/ui/src/app/entity/entity-subtype-autocomplete.directive.js
+++ b/ui/src/app/entity/entity-subtype-autocomplete.directive.js
@@ -96,6 +96,8 @@ export default function EntitySubtypeAutocomplete($compile, $templateCache, $q,
entitySubtypesPromise = assetService.getAssetTypes({ignoreLoading: true});
} else if (scope.entityType == types.entityType.device) {
entitySubtypesPromise = deviceService.getDeviceTypes({ignoreLoading: true});
+ } else if (scope.entityType == types.entityType.entityView) {
+ entitySubtypesPromise = entityViewService.getEntityViewTypes({ignoreLoading: true});
}
if (entitySubtypesPromise) {
entitySubtypesPromise.then(
diff --git a/ui/src/app/entity/entity-subtype-list.directive.js b/ui/src/app/entity/entity-subtype-list.directive.js
index d74a7b0..a0ab15a 100644
--- a/ui/src/app/entity/entity-subtype-list.directive.js
+++ b/ui/src/app/entity/entity-subtype-list.directive.js
@@ -97,6 +97,8 @@ export default function EntitySubtypeListDirective($compile, $templateCache, $q,
entitySubtypesPromise = assetService.getAssetTypes({ignoreLoading: true});
} else if (scope.entityType == types.entityType.device) {
entitySubtypesPromise = deviceService.getDeviceTypes({ignoreLoading: true});
+ } else if (scope.entityType == types.entityType.entityView) {
+ entitySubtypesPromise = entityViewService.getEntityViewTypes({ignoreLoading: true});
}
if (entitySubtypesPromise) {
entitySubtypesPromise.then(
diff --git a/ui/src/app/entity/entity-subtype-select.directive.js b/ui/src/app/entity/entity-subtype-select.directive.js
index b86e944..33e0a17 100644
--- a/ui/src/app/entity/entity-subtype-select.directive.js
+++ b/ui/src/app/entity/entity-subtype-select.directive.js
@@ -75,6 +75,8 @@ export default function EntitySubtypeSelect($compile, $templateCache, $translate
entitySubtypesPromise = assetService.getAssetTypes({ignoreLoading: true});
} else if (scope.entityType == types.entityType.device) {
entitySubtypesPromise = deviceService.getDeviceTypes({ignoreLoading: true});
+ } else if (scope.entityType == types.entityType.entityView) {
+ entitySubtypesPromise = entityViewService.getEntityViewTypes({ignoreLoading: true});
}
if (entitySubtypesPromise) {
entitySubtypesPromise.then(
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 3894eb9..82ecb55 100644
--- a/ui/src/app/entity-view/entity-view-fieldset.tpl.html
+++ b/ui/src/app/entity-view/entity-view-fieldset.tpl.html
@@ -52,6 +52,13 @@
<div translate ng-message="required">entity-view.name-required</div>
</div>
</md-input-container>
+ <tb-entity-subtype-autocomplete
+ ng-disabled="$root.loading || !isEdit"
+ tb-required="true"
+ the-form="theForm"
+ ng-model="entityView.type"
+ entity-type="types.entityType.entityView">
+ </tb-entity-subtype-autocomplete>
<tb-entity-select flex ng-disabled="!isEdit"
the-form="theForm"
tb-required="true"
diff --git a/ui/src/app/locale/locale.constant-en_US.json b/ui/src/app/locale/locale.constant-en_US.json
index 481d677..276b432 100644
--- a/ui/src/app/locale/locale.constant-en_US.json
+++ b/ui/src/app/locale/locale.constant-en_US.json
@@ -158,12 +158,17 @@
"filter-type-device-type": "Device type",
"filter-type-device-type-description": "Devices of type '{{deviceType}}'",
"filter-type-device-type-and-name-description": "Devices of type '{{deviceType}}' and with name starting with '{{prefix}}'",
+ "filter-type-entity-view-type": "Entity View type",
+ "filter-type-entity-view-type-description": "Entity Views of type '{{entityView}}'",
+ "filter-type-entity-view-type-and-name-description": "Entity Views of type '{{entityView}}' and with name starting with '{{prefix}}'",
"filter-type-relations-query": "Relations query",
"filter-type-relations-query-description": "{{entities}} that have {{relationType}} relation {{direction}} {{rootEntity}}",
"filter-type-asset-search-query": "Asset search query",
"filter-type-asset-search-query-description": "Assets with types {{assetTypes}} that have {{relationType}} relation {{direction}} {{rootEntity}}",
"filter-type-device-search-query": "Device search query",
"filter-type-device-search-query-description": "Devices with types {{deviceTypes}} that have {{relationType}} relation {{direction}} {{rootEntity}}",
+ "filter-type-entity-view-search-query": "Entity view search query",
+ "filter-type-entity-view-search-query-description": "Entity views with types {{entityViewTypes}} that have {{relationType}} relation {{direction}} {{rootEntity}}",
"entity-filter": "Entity filter",
"resolve-multiple": "Resolve as multiple entities",
"filter-type": "Filter type",
@@ -839,7 +844,7 @@
"client-attributes": "Client attributes",
"shared-attributes": "Shared attributes",
"server-attributes": "Server attributes",
- "latest-timeseries": "Latest timeseries"
+ "latest-timeseries": "Latest timeseries",
},
"event": {
"event-type": "Event type",