Entity relations management.
This commit is contained in:
parent
90ef91e3a1
commit
a708509aac
@ -21,6 +21,7 @@ import org.springframework.web.bind.annotation.*;
|
||||
import org.thingsboard.server.common.data.id.EntityId;
|
||||
import org.thingsboard.server.common.data.id.EntityIdFactory;
|
||||
import org.thingsboard.server.common.data.relation.EntityRelation;
|
||||
import org.thingsboard.server.common.data.relation.EntityRelationInfo;
|
||||
import org.thingsboard.server.dao.relation.EntityRelationsQuery;
|
||||
import org.thingsboard.server.exception.ThingsboardErrorCode;
|
||||
import org.thingsboard.server.exception.ThingsboardException;
|
||||
@ -127,6 +128,21 @@ public class EntityRelationController extends BaseController {
|
||||
}
|
||||
}
|
||||
|
||||
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
|
||||
@RequestMapping(value = "/relations/info", method = RequestMethod.GET, params = {"fromId", "fromType"})
|
||||
@ResponseBody
|
||||
public List<EntityRelationInfo> findInfoByFrom(@RequestParam("fromId") String strFromId, @RequestParam("fromType") String strFromType) throws ThingsboardException {
|
||||
checkParameter("fromId", strFromId);
|
||||
checkParameter("fromType", strFromType);
|
||||
EntityId entityId = EntityIdFactory.getByTypeAndId(strFromType, strFromId);
|
||||
checkEntityId(entityId);
|
||||
try {
|
||||
return checkNotNull(relationService.findInfoByFrom(entityId).get());
|
||||
} catch (Exception e) {
|
||||
throw handleException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
|
||||
@RequestMapping(value = "/relations", method = RequestMethod.GET, params = {"fromId", "fromType", "relationType"})
|
||||
@ResponseBody
|
||||
|
||||
@ -20,7 +20,7 @@ import org.thingsboard.server.common.data.id.TenantId;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
|
||||
public class Customer extends ContactBased<CustomerId>{
|
||||
public class Customer extends ContactBased<CustomerId> implements HasName {
|
||||
|
||||
private static final long serialVersionUID = -1599722990298929275L;
|
||||
|
||||
@ -59,6 +59,11 @@ public class Customer extends ContactBased<CustomerId>{
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return title;
|
||||
}
|
||||
|
||||
public JsonNode getAdditionalInfo() {
|
||||
return additionalInfo;
|
||||
}
|
||||
|
||||
@ -19,7 +19,7 @@ import org.thingsboard.server.common.data.id.CustomerId;
|
||||
import org.thingsboard.server.common.data.id.DashboardId;
|
||||
import org.thingsboard.server.common.data.id.TenantId;
|
||||
|
||||
public class DashboardInfo extends SearchTextBased<DashboardId> {
|
||||
public class DashboardInfo extends SearchTextBased<DashboardId> implements HasName {
|
||||
|
||||
private TenantId tenantId;
|
||||
private CustomerId customerId;
|
||||
@ -64,6 +64,11 @@ public class DashboardInfo extends SearchTextBased<DashboardId> {
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return title;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSearchText() {
|
||||
return title;
|
||||
|
||||
@ -21,7 +21,7 @@ import org.thingsboard.server.common.data.id.TenantId;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
|
||||
public class Device extends SearchTextBased<DeviceId> {
|
||||
public class Device extends SearchTextBased<DeviceId> implements HasName {
|
||||
|
||||
private static final long serialVersionUID = 2807343040519543363L;
|
||||
|
||||
@ -64,6 +64,7 @@ public class Device extends SearchTextBased<DeviceId> {
|
||||
this.customerId = customerId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@ -0,0 +1,22 @@
|
||||
/**
|
||||
* Copyright © 2016-2017 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.
|
||||
*/
|
||||
package org.thingsboard.server.common.data;
|
||||
|
||||
public interface HasName {
|
||||
|
||||
String getName();
|
||||
|
||||
}
|
||||
@ -19,7 +19,7 @@ import org.thingsboard.server.common.data.id.TenantId;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
|
||||
public class Tenant extends ContactBased<TenantId>{
|
||||
public class Tenant extends ContactBased<TenantId> implements HasName {
|
||||
|
||||
private static final long serialVersionUID = 8057243243859922101L;
|
||||
|
||||
@ -50,6 +50,11 @@ public class Tenant extends ContactBased<TenantId>{
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return title;
|
||||
}
|
||||
|
||||
public String getRegion() {
|
||||
return region;
|
||||
}
|
||||
|
||||
@ -22,7 +22,7 @@ import org.thingsboard.server.common.data.security.Authority;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
|
||||
public class User extends SearchTextBased<UserId> {
|
||||
public class User extends SearchTextBased<UserId> implements HasName {
|
||||
|
||||
private static final long serialVersionUID = 8250339805336035966L;
|
||||
|
||||
@ -77,6 +77,11 @@ public class User extends SearchTextBased<UserId> {
|
||||
this.email = email;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return email;
|
||||
}
|
||||
|
||||
public Authority getAuthority() {
|
||||
return authority;
|
||||
}
|
||||
|
||||
@ -18,13 +18,14 @@ package org.thingsboard.server.common.data.alarm;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import lombok.Data;
|
||||
import org.thingsboard.server.common.data.BaseData;
|
||||
import org.thingsboard.server.common.data.HasName;
|
||||
import org.thingsboard.server.common.data.id.EntityId;
|
||||
|
||||
/**
|
||||
* Created by ashvayka on 11.05.17.
|
||||
*/
|
||||
@Data
|
||||
public class Alarm extends BaseData<AlarmId> {
|
||||
public class Alarm extends BaseData<AlarmId> implements HasName {
|
||||
|
||||
private long startTs;
|
||||
private long endTs;
|
||||
@ -37,4 +38,8 @@ public class Alarm extends BaseData<AlarmId> {
|
||||
private JsonNode details;
|
||||
private boolean propagate;
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return type;
|
||||
}
|
||||
}
|
||||
|
||||
@ -16,12 +16,13 @@
|
||||
package org.thingsboard.server.common.data.asset;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import org.thingsboard.server.common.data.HasName;
|
||||
import org.thingsboard.server.common.data.SearchTextBased;
|
||||
import org.thingsboard.server.common.data.id.AssetId;
|
||||
import org.thingsboard.server.common.data.id.CustomerId;
|
||||
import org.thingsboard.server.common.data.id.TenantId;
|
||||
|
||||
public class Asset extends SearchTextBased<AssetId> {
|
||||
public class Asset extends SearchTextBased<AssetId> implements HasName {
|
||||
|
||||
private static final long serialVersionUID = 2807343040519543363L;
|
||||
|
||||
@ -64,6 +65,7 @@ public class Asset extends SearchTextBased<AssetId> {
|
||||
this.customerId = customerId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@ -15,13 +15,14 @@
|
||||
*/
|
||||
package org.thingsboard.server.common.data.plugin;
|
||||
|
||||
import org.thingsboard.server.common.data.HasName;
|
||||
import org.thingsboard.server.common.data.SearchTextBased;
|
||||
import org.thingsboard.server.common.data.id.PluginId;
|
||||
import org.thingsboard.server.common.data.id.TenantId;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
|
||||
public class PluginMetaData extends SearchTextBased<PluginId> {
|
||||
public class PluginMetaData extends SearchTextBased<PluginId> implements HasName {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@ -75,6 +76,7 @@ public class PluginMetaData extends SearchTextBased<PluginId> {
|
||||
this.tenantId = tenantId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@ -47,11 +47,11 @@ public class EntityRelation {
|
||||
this.additionalInfo = additionalInfo;
|
||||
}
|
||||
|
||||
public EntityRelation(EntityRelation device) {
|
||||
this.from = device.getFrom();
|
||||
this.to = device.getTo();
|
||||
this.type = device.getType();
|
||||
this.additionalInfo = device.getAdditionalInfo();
|
||||
public EntityRelation(EntityRelation entityRelation) {
|
||||
this.from = entityRelation.getFrom();
|
||||
this.to = entityRelation.getTo();
|
||||
this.type = entityRelation.getType();
|
||||
this.additionalInfo = entityRelation.getAdditionalInfo();
|
||||
}
|
||||
|
||||
public EntityId getFrom() {
|
||||
|
||||
@ -0,0 +1,59 @@
|
||||
/**
|
||||
* Copyright © 2016-2017 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.
|
||||
*/
|
||||
|
||||
package org.thingsboard.server.common.data.relation;
|
||||
|
||||
public class EntityRelationInfo extends EntityRelation {
|
||||
|
||||
private static final long serialVersionUID = 2807343097519543363L;
|
||||
|
||||
private String toName;
|
||||
|
||||
public EntityRelationInfo() {
|
||||
super();
|
||||
}
|
||||
|
||||
public EntityRelationInfo(EntityRelation entityRelation) {
|
||||
super(entityRelation);
|
||||
}
|
||||
|
||||
public String getToName() {
|
||||
return toName;
|
||||
}
|
||||
|
||||
public void setToName(String toName) {
|
||||
this.toName = toName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
if (!super.equals(o)) return false;
|
||||
|
||||
EntityRelationInfo that = (EntityRelationInfo) o;
|
||||
|
||||
return toName != null ? toName.equals(that.toName) : that.toName == null;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = super.hashCode();
|
||||
result = 31 * result + (toName != null ? toName.hashCode() : 0);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@ -17,6 +17,7 @@ package org.thingsboard.server.common.data.rule;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.ToString;
|
||||
import org.thingsboard.server.common.data.HasName;
|
||||
import org.thingsboard.server.common.data.SearchTextBased;
|
||||
import org.thingsboard.server.common.data.id.CustomerId;
|
||||
import org.thingsboard.server.common.data.id.RuleId;
|
||||
@ -26,7 +27,7 @@ import com.fasterxml.jackson.databind.JsonNode;
|
||||
import org.thingsboard.server.common.data.plugin.ComponentLifecycleState;
|
||||
|
||||
@Data
|
||||
public class RuleMetaData extends SearchTextBased<RuleId> {
|
||||
public class RuleMetaData extends SearchTextBased<RuleId> implements HasName {
|
||||
|
||||
private static final long serialVersionUID = -5656679015122935465L;
|
||||
|
||||
@ -66,4 +67,9 @@ public class RuleMetaData extends SearchTextBased<RuleId> {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -28,6 +28,10 @@ import java.util.Optional;
|
||||
*/
|
||||
public interface AlarmService {
|
||||
|
||||
Alarm findAlarmById(AlarmId alarmId);
|
||||
|
||||
ListenableFuture<Alarm> findAlarmByIdAsync(AlarmId alarmId);
|
||||
|
||||
Optional<Alarm> saveIfNotExists(Alarm alarm);
|
||||
|
||||
ListenableFuture<Boolean> updateAlarm(Alarm alarm);
|
||||
|
||||
@ -0,0 +1,66 @@
|
||||
/**
|
||||
* Copyright © 2016-2017 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.
|
||||
*/
|
||||
package org.thingsboard.server.dao.alarm;
|
||||
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.thingsboard.server.common.data.alarm.Alarm;
|
||||
import org.thingsboard.server.common.data.alarm.AlarmId;
|
||||
import org.thingsboard.server.common.data.alarm.AlarmQuery;
|
||||
import org.thingsboard.server.common.data.page.TimePageData;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
@Service
|
||||
@Slf4j
|
||||
public class BaseAlarmService implements AlarmService {
|
||||
|
||||
@Override
|
||||
public Alarm findAlarmById(AlarmId alarmId) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListenableFuture<Alarm> findAlarmByIdAsync(AlarmId alarmId) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Alarm> saveIfNotExists(Alarm alarm) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListenableFuture<Boolean> updateAlarm(Alarm alarm) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListenableFuture<Boolean> ackAlarm(Alarm alarm) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListenableFuture<Boolean> clearAlarm(AlarmId alarmId) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListenableFuture<TimePageData<Alarm>> findAlarms(AlarmQuery query) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@ -35,7 +35,7 @@ import org.thingsboard.server.common.data.page.TextPageData;
|
||||
import org.thingsboard.server.common.data.page.TextPageLink;
|
||||
import org.thingsboard.server.common.data.relation.EntityRelation;
|
||||
import org.thingsboard.server.dao.customer.CustomerDao;
|
||||
import org.thingsboard.server.dao.entity.BaseEntityService;
|
||||
import org.thingsboard.server.dao.entity.AbstractEntityService;
|
||||
import org.thingsboard.server.dao.exception.DataValidationException;
|
||||
import org.thingsboard.server.dao.model.*;
|
||||
import org.thingsboard.server.dao.relation.EntitySearchDirection;
|
||||
@ -55,7 +55,7 @@ import static org.thingsboard.server.dao.service.Validator.*;
|
||||
|
||||
@Service
|
||||
@Slf4j
|
||||
public class BaseAssetService extends BaseEntityService implements AssetService {
|
||||
public class BaseAssetService extends AbstractEntityService implements AssetService {
|
||||
|
||||
@Autowired
|
||||
private AssetDao assetDao;
|
||||
|
||||
@ -31,17 +31,15 @@ import com.google.common.util.concurrent.ListenableFuture;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.thingsboard.server.common.data.Customer;
|
||||
import org.thingsboard.server.common.data.asset.Asset;
|
||||
import org.thingsboard.server.common.data.id.CustomerId;
|
||||
import org.thingsboard.server.common.data.id.TenantId;
|
||||
import org.thingsboard.server.common.data.page.TextPageData;
|
||||
import org.thingsboard.server.common.data.page.TextPageLink;
|
||||
import org.thingsboard.server.dao.dashboard.DashboardService;
|
||||
import org.thingsboard.server.dao.device.DeviceService;
|
||||
import org.thingsboard.server.dao.entity.BaseEntityService;
|
||||
import org.thingsboard.server.dao.entity.AbstractEntityService;
|
||||
import org.thingsboard.server.dao.exception.DataValidationException;
|
||||
import org.thingsboard.server.dao.exception.IncorrectParameterException;
|
||||
import org.thingsboard.server.dao.model.AssetEntity;
|
||||
import org.thingsboard.server.dao.model.CustomerEntity;
|
||||
import org.thingsboard.server.dao.model.TenantEntity;
|
||||
import org.thingsboard.server.dao.service.DataValidator;
|
||||
@ -53,7 +51,7 @@ import org.springframework.stereotype.Service;
|
||||
import org.thingsboard.server.dao.service.Validator;
|
||||
@Service
|
||||
@Slf4j
|
||||
public class CustomerServiceImpl extends BaseEntityService implements CustomerService {
|
||||
public class CustomerServiceImpl extends AbstractEntityService implements CustomerService {
|
||||
|
||||
private static final String PUBLIC_CUSTOMER_TITLE = "Public";
|
||||
|
||||
|
||||
@ -15,6 +15,7 @@
|
||||
*/
|
||||
package org.thingsboard.server.dao.dashboard;
|
||||
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
import org.thingsboard.server.common.data.Dashboard;
|
||||
import org.thingsboard.server.common.data.DashboardInfo;
|
||||
import org.thingsboard.server.common.data.id.CustomerId;
|
||||
@ -27,8 +28,12 @@ public interface DashboardService {
|
||||
|
||||
public Dashboard findDashboardById(DashboardId dashboardId);
|
||||
|
||||
public ListenableFuture<Dashboard> findDashboardByIdAsync(DashboardId dashboardId);
|
||||
|
||||
public DashboardInfo findDashboardInfoById(DashboardId dashboardId);
|
||||
|
||||
public ListenableFuture<DashboardInfo> findDashboardInfoByIdAsync(DashboardId dashboardId);
|
||||
|
||||
public Dashboard saveDashboard(Dashboard dashboard);
|
||||
|
||||
public Dashboard assignDashboardToCustomer(DashboardId dashboardId, CustomerId customerId);
|
||||
|
||||
@ -17,9 +17,13 @@ package org.thingsboard.server.dao.dashboard;
|
||||
|
||||
import static org.thingsboard.server.dao.DaoUtil.convertDataList;
|
||||
import static org.thingsboard.server.dao.DaoUtil.getData;
|
||||
import static org.thingsboard.server.dao.service.Validator.validateId;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
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.apache.commons.lang3.StringUtils;
|
||||
import org.thingsboard.server.common.data.Dashboard;
|
||||
@ -30,7 +34,7 @@ import org.thingsboard.server.common.data.id.TenantId;
|
||||
import org.thingsboard.server.common.data.page.TextPageData;
|
||||
import org.thingsboard.server.common.data.page.TextPageLink;
|
||||
import org.thingsboard.server.dao.customer.CustomerDao;
|
||||
import org.thingsboard.server.dao.entity.BaseEntityService;
|
||||
import org.thingsboard.server.dao.entity.AbstractEntityService;
|
||||
import org.thingsboard.server.dao.exception.DataValidationException;
|
||||
import org.thingsboard.server.dao.model.*;
|
||||
import org.thingsboard.server.dao.service.DataValidator;
|
||||
@ -42,7 +46,7 @@ import org.thingsboard.server.dao.service.Validator;
|
||||
|
||||
@Service
|
||||
@Slf4j
|
||||
public class DashboardServiceImpl extends BaseEntityService implements DashboardService {
|
||||
public class DashboardServiceImpl extends AbstractEntityService implements DashboardService {
|
||||
|
||||
@Autowired
|
||||
private DashboardDao dashboardDao;
|
||||
@ -64,6 +68,14 @@ public class DashboardServiceImpl extends BaseEntityService implements Dashboard
|
||||
return getData(dashboardEntity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListenableFuture<Dashboard> findDashboardByIdAsync(DashboardId dashboardId) {
|
||||
log.trace("Executing findDashboardByIdAsync [{}]", dashboardId);
|
||||
validateId(dashboardId, "Incorrect dashboardId " + dashboardId);
|
||||
ListenableFuture<DashboardEntity> dashboardEntity = dashboardDao.findByIdAsync(dashboardId.getId());
|
||||
return Futures.transform(dashboardEntity, (Function<? super DashboardEntity, ? extends Dashboard>) input -> getData(input));
|
||||
}
|
||||
|
||||
@Override
|
||||
public DashboardInfo findDashboardInfoById(DashboardId dashboardId) {
|
||||
log.trace("Executing findDashboardInfoById [{}]", dashboardId);
|
||||
@ -72,6 +84,14 @@ public class DashboardServiceImpl extends BaseEntityService implements Dashboard
|
||||
return getData(dashboardInfoEntity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListenableFuture<DashboardInfo> findDashboardInfoByIdAsync(DashboardId dashboardId) {
|
||||
log.trace("Executing findDashboardInfoByIdAsync [{}]", dashboardId);
|
||||
validateId(dashboardId, "Incorrect dashboardId " + dashboardId);
|
||||
ListenableFuture<DashboardInfoEntity> dashboardInfoEntity = dashboardInfoDao.findByIdAsync(dashboardId.getId());
|
||||
return Futures.transform(dashboardInfoEntity, (Function<? super DashboardInfoEntity, ? extends DashboardInfo>) input -> getData(input));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dashboard saveDashboard(Dashboard dashboard) {
|
||||
log.trace("Executing saveDashboard [{}]", dashboard);
|
||||
|
||||
@ -37,7 +37,7 @@ import org.thingsboard.server.common.data.relation.EntityRelation;
|
||||
import org.thingsboard.server.common.data.security.DeviceCredentials;
|
||||
import org.thingsboard.server.common.data.security.DeviceCredentialsType;
|
||||
import org.thingsboard.server.dao.customer.CustomerDao;
|
||||
import org.thingsboard.server.dao.entity.BaseEntityService;
|
||||
import org.thingsboard.server.dao.entity.AbstractEntityService;
|
||||
import org.thingsboard.server.dao.exception.DataValidationException;
|
||||
import org.thingsboard.server.dao.model.CustomerEntity;
|
||||
import org.thingsboard.server.dao.model.DeviceEntity;
|
||||
@ -58,7 +58,7 @@ import static org.thingsboard.server.dao.service.Validator.*;
|
||||
|
||||
@Service
|
||||
@Slf4j
|
||||
public class DeviceServiceImpl extends BaseEntityService implements DeviceService {
|
||||
public class DeviceServiceImpl extends AbstractEntityService implements DeviceService {
|
||||
|
||||
@Autowired
|
||||
private DeviceDao deviceDao;
|
||||
|
||||
@ -0,0 +1,36 @@
|
||||
/**
|
||||
* Copyright © 2016-2017 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.
|
||||
*/
|
||||
|
||||
package org.thingsboard.server.dao.entity;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.thingsboard.server.common.data.id.EntityId;
|
||||
import org.thingsboard.server.dao.relation.RelationService;
|
||||
|
||||
@Slf4j
|
||||
public abstract class AbstractEntityService {
|
||||
|
||||
@Autowired
|
||||
protected RelationService relationService;
|
||||
|
||||
protected void deleteEntityRelations(EntityId entityId) {
|
||||
log.trace("Executing deleteEntityRelations [{}]", entityId);
|
||||
relationService.deleteEntityRelations(entityId);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@ -15,23 +15,102 @@
|
||||
*/
|
||||
package org.thingsboard.server.dao.entity;
|
||||
|
||||
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.beans.factory.annotation.Autowired;
|
||||
import org.thingsboard.server.common.data.id.EntityId;
|
||||
import org.thingsboard.server.dao.relation.RelationService;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.thingsboard.server.common.data.*;
|
||||
import org.thingsboard.server.common.data.alarm.AlarmId;
|
||||
import org.thingsboard.server.common.data.id.*;
|
||||
import org.thingsboard.server.dao.alarm.AlarmService;
|
||||
import org.thingsboard.server.dao.asset.AssetService;
|
||||
import org.thingsboard.server.dao.customer.CustomerService;
|
||||
import org.thingsboard.server.dao.dashboard.DashboardService;
|
||||
import org.thingsboard.server.dao.device.DeviceService;
|
||||
import org.thingsboard.server.dao.plugin.PluginService;
|
||||
import org.thingsboard.server.dao.rule.RuleService;
|
||||
import org.thingsboard.server.dao.tenant.TenantService;
|
||||
import org.thingsboard.server.dao.user.UserService;
|
||||
|
||||
/**
|
||||
* Created by ashvayka on 04.05.17.
|
||||
*/
|
||||
@Service
|
||||
@Slf4j
|
||||
public class BaseEntityService {
|
||||
public class BaseEntityService extends AbstractEntityService implements EntityService {
|
||||
|
||||
@Autowired
|
||||
protected RelationService relationService;
|
||||
private AssetService assetService;
|
||||
|
||||
protected void deleteEntityRelations(EntityId entityId) {
|
||||
log.trace("Executing deleteEntityRelations [{}]", entityId);
|
||||
relationService.deleteEntityRelations(entityId);
|
||||
@Autowired
|
||||
private DeviceService deviceService;
|
||||
|
||||
@Autowired
|
||||
private RuleService ruleService;
|
||||
|
||||
@Autowired
|
||||
private PluginService pluginService;
|
||||
|
||||
@Autowired
|
||||
private TenantService tenantService;
|
||||
|
||||
@Autowired
|
||||
private CustomerService customerService;
|
||||
|
||||
@Autowired
|
||||
private UserService userService;
|
||||
|
||||
@Autowired
|
||||
private DashboardService dashboardService;
|
||||
|
||||
@Autowired
|
||||
private AlarmService alarmService;
|
||||
|
||||
@Override
|
||||
public void deleteEntityRelations(EntityId entityId) {
|
||||
super.deleteEntityRelations(entityId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListenableFuture<String> fetchEntityNameAsync(EntityId entityId) {
|
||||
log.trace("Executing fetchEntityNameAsync [{}]", entityId);
|
||||
ListenableFuture<String> entityName;
|
||||
ListenableFuture<? extends HasName> hasName;
|
||||
switch (entityId.getEntityType()) {
|
||||
case ASSET:
|
||||
hasName = assetService.findAssetByIdAsync(new AssetId(entityId.getId()));
|
||||
break;
|
||||
case DEVICE:
|
||||
hasName = deviceService.findDeviceByIdAsync(new DeviceId(entityId.getId()));
|
||||
break;
|
||||
case RULE:
|
||||
hasName = ruleService.findRuleByIdAsync(new RuleId(entityId.getId()));
|
||||
break;
|
||||
case PLUGIN:
|
||||
hasName = pluginService.findPluginByIdAsync(new PluginId(entityId.getId()));
|
||||
break;
|
||||
case TENANT:
|
||||
hasName = tenantService.findTenantByIdAsync(new TenantId(entityId.getId()));
|
||||
break;
|
||||
case CUSTOMER:
|
||||
hasName = customerService.findCustomerByIdAsync(new CustomerId(entityId.getId()));
|
||||
break;
|
||||
case USER:
|
||||
hasName = userService.findUserByIdAsync(new UserId(entityId.getId()));
|
||||
break;
|
||||
case DASHBOARD:
|
||||
hasName = dashboardService.findDashboardInfoByIdAsync(new DashboardId(entityId.getId()));
|
||||
break;
|
||||
case ALARM:
|
||||
hasName = alarmService.findAlarmByIdAsync(new AlarmId(entityId.getId()));
|
||||
break;
|
||||
default:
|
||||
throw new IllegalStateException("Not Implemented!");
|
||||
}
|
||||
entityName = Futures.transform(hasName, (Function<HasName, String>) hasName1 -> hasName1.getName() );
|
||||
return entityName;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -0,0 +1,28 @@
|
||||
/**
|
||||
* Copyright © 2016-2017 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.
|
||||
*/
|
||||
|
||||
package org.thingsboard.server.dao.entity;
|
||||
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
import org.thingsboard.server.common.data.id.EntityId;
|
||||
|
||||
public interface EntityService {
|
||||
|
||||
ListenableFuture<String> fetchEntityNameAsync(EntityId entityId);
|
||||
|
||||
void deleteEntityRelations(EntityId entityId);
|
||||
|
||||
}
|
||||
@ -22,7 +22,6 @@ import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.thingsboard.server.common.data.id.PluginId;
|
||||
import org.thingsboard.server.common.data.id.RuleId;
|
||||
import org.thingsboard.server.common.data.id.TenantId;
|
||||
import org.thingsboard.server.common.data.page.TextPageData;
|
||||
import org.thingsboard.server.common.data.page.TextPageLink;
|
||||
@ -30,9 +29,8 @@ import org.thingsboard.server.common.data.plugin.ComponentDescriptor;
|
||||
import org.thingsboard.server.common.data.plugin.ComponentLifecycleState;
|
||||
import org.thingsboard.server.common.data.plugin.ComponentType;
|
||||
import org.thingsboard.server.common.data.plugin.PluginMetaData;
|
||||
import org.thingsboard.server.common.data.rule.RuleMetaData;
|
||||
import org.thingsboard.server.dao.component.ComponentDescriptorService;
|
||||
import org.thingsboard.server.dao.entity.BaseEntityService;
|
||||
import org.thingsboard.server.dao.entity.AbstractEntityService;
|
||||
import org.thingsboard.server.dao.exception.DataValidationException;
|
||||
import org.thingsboard.server.dao.exception.DatabaseException;
|
||||
import org.thingsboard.server.dao.exception.IncorrectParameterException;
|
||||
@ -55,7 +53,7 @@ import static org.thingsboard.server.dao.service.Validator.validateId;
|
||||
|
||||
@Service
|
||||
@Slf4j
|
||||
public class BasePluginService extends BaseEntityService implements PluginService {
|
||||
public class BasePluginService extends AbstractEntityService implements PluginService {
|
||||
|
||||
//TODO: move to a better place.
|
||||
public static final TenantId SYSTEM_TENANT = new TenantId(ModelConstants.NULL_UUID);
|
||||
|
||||
@ -23,9 +23,24 @@ import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.thingsboard.server.common.data.BaseData;
|
||||
import org.thingsboard.server.common.data.Device;
|
||||
import org.thingsboard.server.common.data.EntityType;
|
||||
import org.thingsboard.server.common.data.asset.Asset;
|
||||
import org.thingsboard.server.common.data.id.AssetId;
|
||||
import org.thingsboard.server.common.data.id.DeviceId;
|
||||
import org.thingsboard.server.common.data.id.EntityId;
|
||||
import org.thingsboard.server.common.data.id.UUIDBased;
|
||||
import org.thingsboard.server.common.data.relation.EntityRelation;
|
||||
import org.thingsboard.server.common.data.relation.EntityRelationInfo;
|
||||
import org.thingsboard.server.dao.asset.AssetService;
|
||||
import org.thingsboard.server.dao.customer.CustomerService;
|
||||
import org.thingsboard.server.dao.device.DeviceService;
|
||||
import org.thingsboard.server.dao.entity.EntityService;
|
||||
import org.thingsboard.server.dao.exception.DataValidationException;
|
||||
import org.thingsboard.server.dao.plugin.PluginService;
|
||||
import org.thingsboard.server.dao.rule.RuleService;
|
||||
import org.thingsboard.server.dao.tenant.TenantService;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.*;
|
||||
@ -41,6 +56,9 @@ public class BaseRelationService implements RelationService {
|
||||
@Autowired
|
||||
private RelationDao relationDao;
|
||||
|
||||
@Autowired
|
||||
private EntityService entityService;
|
||||
|
||||
@Override
|
||||
public ListenableFuture<Boolean> checkRelation(EntityId from, EntityId to, String relationType) {
|
||||
log.trace("Executing checkRelation [{}][{}][{}]", from, to, relationType);
|
||||
@ -99,6 +117,31 @@ public class BaseRelationService implements RelationService {
|
||||
return relationDao.findAllByFrom(from);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListenableFuture<List<EntityRelationInfo>> findInfoByFrom(EntityId from) {
|
||||
log.trace("Executing findInfoByFrom [{}]", from);
|
||||
validate(from);
|
||||
ListenableFuture<List<EntityRelation>> relations = relationDao.findAllByFrom(from);
|
||||
ListenableFuture<List<EntityRelationInfo>> relationsInfo = Futures.transform(relations,
|
||||
(AsyncFunction<List<EntityRelation>, List<EntityRelationInfo>>) relations1 -> {
|
||||
List<ListenableFuture<EntityRelationInfo>> futures = new ArrayList<>();
|
||||
relations1.stream().forEach(relation -> futures.add(fetchRelationInfoAsync(relation)));
|
||||
return Futures.successfulAsList(futures);
|
||||
});
|
||||
return relationsInfo;
|
||||
}
|
||||
|
||||
private ListenableFuture<EntityRelationInfo> fetchRelationInfoAsync(EntityRelation relation) {
|
||||
ListenableFuture<String> entityName = entityService.fetchEntityNameAsync(relation.getTo());
|
||||
ListenableFuture<EntityRelationInfo> entityRelationInfo =
|
||||
Futures.transform(entityName, (Function<String, EntityRelationInfo>) entityName1 -> {
|
||||
EntityRelationInfo entityRelationInfo1 = new EntityRelationInfo(relation);
|
||||
entityRelationInfo1.setToName(entityName1);
|
||||
return entityRelationInfo1;
|
||||
});
|
||||
return entityRelationInfo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListenableFuture<List<EntityRelation>> findByFromAndType(EntityId from, String relationType) {
|
||||
log.trace("Executing findByFromAndType [{}][{}]", from, relationType);
|
||||
|
||||
@ -18,6 +18,7 @@ package org.thingsboard.server.dao.relation;
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
import org.thingsboard.server.common.data.id.EntityId;
|
||||
import org.thingsboard.server.common.data.relation.EntityRelation;
|
||||
import org.thingsboard.server.common.data.relation.EntityRelationInfo;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@ -38,6 +39,8 @@ public interface RelationService {
|
||||
|
||||
ListenableFuture<List<EntityRelation>> findByFrom(EntityId from);
|
||||
|
||||
ListenableFuture<List<EntityRelationInfo>> findInfoByFrom(EntityId from);
|
||||
|
||||
ListenableFuture<List<EntityRelation>> findByFromAndType(EntityId from, String relationType);
|
||||
|
||||
ListenableFuture<List<EntityRelation>> findByTo(EntityId to);
|
||||
|
||||
@ -23,7 +23,6 @@ import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.thingsboard.server.common.data.asset.Asset;
|
||||
import org.thingsboard.server.common.data.id.RuleId;
|
||||
import org.thingsboard.server.common.data.id.TenantId;
|
||||
import org.thingsboard.server.common.data.page.TextPageData;
|
||||
@ -34,11 +33,10 @@ import org.thingsboard.server.common.data.plugin.ComponentType;
|
||||
import org.thingsboard.server.common.data.plugin.PluginMetaData;
|
||||
import org.thingsboard.server.common.data.rule.RuleMetaData;
|
||||
import org.thingsboard.server.dao.component.ComponentDescriptorService;
|
||||
import org.thingsboard.server.dao.entity.BaseEntityService;
|
||||
import org.thingsboard.server.dao.entity.AbstractEntityService;
|
||||
import org.thingsboard.server.dao.exception.DataValidationException;
|
||||
import org.thingsboard.server.dao.exception.DatabaseException;
|
||||
import org.thingsboard.server.dao.exception.IncorrectParameterException;
|
||||
import org.thingsboard.server.dao.model.AssetEntity;
|
||||
import org.thingsboard.server.dao.model.RuleMetaDataEntity;
|
||||
import org.thingsboard.server.dao.plugin.PluginService;
|
||||
import org.thingsboard.server.dao.service.DataValidator;
|
||||
@ -58,7 +56,7 @@ import static org.thingsboard.server.dao.service.Validator.validatePageLink;
|
||||
|
||||
@Service
|
||||
@Slf4j
|
||||
public class BaseRuleService extends BaseEntityService implements RuleService {
|
||||
public class BaseRuleService extends AbstractEntityService implements RuleService {
|
||||
|
||||
private final TenantId systemTenantId = new TenantId(NULL_UUID);
|
||||
|
||||
|
||||
@ -26,7 +26,6 @@ import com.google.common.util.concurrent.Futures;
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.thingsboard.server.common.data.Customer;
|
||||
import org.thingsboard.server.common.data.Tenant;
|
||||
import org.thingsboard.server.common.data.id.TenantId;
|
||||
import org.thingsboard.server.common.data.page.TextPageData;
|
||||
@ -34,9 +33,8 @@ import org.thingsboard.server.common.data.page.TextPageLink;
|
||||
import org.thingsboard.server.dao.customer.CustomerService;
|
||||
import org.thingsboard.server.dao.dashboard.DashboardService;
|
||||
import org.thingsboard.server.dao.device.DeviceService;
|
||||
import org.thingsboard.server.dao.entity.BaseEntityService;
|
||||
import org.thingsboard.server.dao.entity.AbstractEntityService;
|
||||
import org.thingsboard.server.dao.exception.DataValidationException;
|
||||
import org.thingsboard.server.dao.model.CustomerEntity;
|
||||
import org.thingsboard.server.dao.model.TenantEntity;
|
||||
import org.thingsboard.server.dao.plugin.PluginService;
|
||||
import org.thingsboard.server.dao.rule.RuleService;
|
||||
@ -50,7 +48,7 @@ import org.thingsboard.server.dao.widget.WidgetsBundleService;
|
||||
|
||||
@Service
|
||||
@Slf4j
|
||||
public class TenantServiceImpl extends BaseEntityService implements TenantService {
|
||||
public class TenantServiceImpl extends AbstractEntityService implements TenantService {
|
||||
|
||||
private static final String DEFAULT_TENANT_REGION = "Global";
|
||||
|
||||
|
||||
@ -15,6 +15,7 @@
|
||||
*/
|
||||
package org.thingsboard.server.dao.user;
|
||||
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
import org.thingsboard.server.common.data.User;
|
||||
import org.thingsboard.server.common.data.id.CustomerId;
|
||||
import org.thingsboard.server.common.data.id.TenantId;
|
||||
@ -27,6 +28,8 @@ public interface UserService {
|
||||
|
||||
public User findUserById(UserId userId);
|
||||
|
||||
public ListenableFuture<User> findUserByIdAsync(UserId userId);
|
||||
|
||||
public User findUserByEmail(String email);
|
||||
|
||||
public User saveUser(User user);
|
||||
|
||||
@ -23,6 +23,9 @@ import static org.thingsboard.server.dao.service.Validator.validateString;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
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.apache.commons.lang3.RandomStringUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
@ -35,7 +38,7 @@ import org.thingsboard.server.common.data.page.TextPageLink;
|
||||
import org.thingsboard.server.common.data.security.Authority;
|
||||
import org.thingsboard.server.common.data.security.UserCredentials;
|
||||
import org.thingsboard.server.dao.customer.CustomerDao;
|
||||
import org.thingsboard.server.dao.entity.BaseEntityService;
|
||||
import org.thingsboard.server.dao.entity.AbstractEntityService;
|
||||
import org.thingsboard.server.dao.exception.DataValidationException;
|
||||
import org.thingsboard.server.dao.exception.IncorrectParameterException;
|
||||
import org.thingsboard.server.dao.model.*;
|
||||
@ -47,7 +50,7 @@ import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
@Slf4j
|
||||
public class UserServiceImpl extends BaseEntityService implements UserService {
|
||||
public class UserServiceImpl extends AbstractEntityService implements UserService {
|
||||
|
||||
@Autowired
|
||||
private UserDao userDao;
|
||||
@ -77,6 +80,14 @@ public class UserServiceImpl extends BaseEntityService implements UserService {
|
||||
return getData(userEntity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListenableFuture<User> findUserByIdAsync(UserId userId) {
|
||||
log.trace("Executing findUserByIdAsync [{}]", userId);
|
||||
validateId(userId, "Incorrect userId " + userId);
|
||||
ListenableFuture<UserEntity> userEntity = userDao.findByIdAsync(userId.getId());
|
||||
return Futures.transform(userEntity, (Function<? super UserEntity, ? extends User>) input -> getData(input));
|
||||
}
|
||||
|
||||
@Override
|
||||
public User saveUser(User user) {
|
||||
log.trace("Executing saveUser [{}]", user);
|
||||
|
||||
@ -25,6 +25,7 @@ function EntityRelationService($http, $q) {
|
||||
deleteRelation: deleteRelation,
|
||||
deleteRelations: deleteRelations,
|
||||
findByFrom: findByFrom,
|
||||
findInfoByFrom: findInfoByFrom,
|
||||
findByFromAndType: findByFromAndType,
|
||||
findByTo: findByTo,
|
||||
findByToAndType: findByToAndType,
|
||||
@ -84,6 +85,18 @@ function EntityRelationService($http, $q) {
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function findInfoByFrom(fromId, fromType) {
|
||||
var deferred = $q.defer();
|
||||
var url = '/api/relations/info?fromId=' + fromId;
|
||||
url += '&fromType=' + fromType;
|
||||
$http.get(url, null).then(function success(response) {
|
||||
deferred.resolve(response.data);
|
||||
}, function fail() {
|
||||
deferred.reject();
|
||||
});
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function findByFromAndType(fromId, fromType, relationType) {
|
||||
var deferred = $q.defer();
|
||||
var url = '/api/relations?fromId=' + fromId;
|
||||
|
||||
@ -20,14 +20,13 @@ export default angular.module('thingsboard.api.entity', [thingsboardTypes])
|
||||
.name;
|
||||
|
||||
/*@ngInject*/
|
||||
function EntityService($http, $q, $filter, $translate, userService, deviceService,
|
||||
function EntityService($http, $q, $filter, $translate, $log, userService, deviceService,
|
||||
assetService, tenantService, customerService,
|
||||
ruleService, pluginService, entityRelationService, attributeService, types, utils) {
|
||||
ruleService, pluginService, dashboardService, entityRelationService, attributeService, types, utils) {
|
||||
var service = {
|
||||
getEntity: getEntity,
|
||||
getEntities: getEntities,
|
||||
getEntitiesByNameFilter: getEntitiesByNameFilter,
|
||||
entityName: entityName,
|
||||
processEntityAliases: processEntityAliases,
|
||||
getEntityKeys: getEntityKeys,
|
||||
checkEntityAlias: checkEntityAlias,
|
||||
@ -63,6 +62,15 @@ function EntityService($http, $q, $filter, $translate, userService, deviceServic
|
||||
case types.entityType.plugin:
|
||||
promise = pluginService.getPlugin(entityId);
|
||||
break;
|
||||
case types.entityType.dashboard:
|
||||
promise = dashboardService.getDashboardInfo(entityId);
|
||||
break;
|
||||
case types.entityType.user:
|
||||
promise = userService.getUser(entityId);
|
||||
break;
|
||||
case types.entityType.alarm:
|
||||
$log.error('Get Alarm Entity is not implemented!');
|
||||
break;
|
||||
}
|
||||
return promise;
|
||||
}
|
||||
@ -134,6 +142,15 @@ function EntityService($http, $q, $filter, $translate, userService, deviceServic
|
||||
case types.entityType.plugin:
|
||||
promise = getEntitiesByIdsPromise(pluginService.getPlugin, entityIds);
|
||||
break;
|
||||
case types.entityType.dashboard:
|
||||
promise = getEntitiesByIdsPromise(dashboardService.getDashboardInfo, entityIds);
|
||||
break;
|
||||
case types.entityType.user:
|
||||
promise = getEntitiesByIdsPromise(userService.getUser, entityIds);
|
||||
break;
|
||||
case types.entityType.alarm:
|
||||
$log.error('Get Alarm Entity is not implemented!');
|
||||
break;
|
||||
}
|
||||
return promise;
|
||||
}
|
||||
@ -141,34 +158,38 @@ function EntityService($http, $q, $filter, $translate, userService, deviceServic
|
||||
function getEntities(entityType, entityIds, config) {
|
||||
var deferred = $q.defer();
|
||||
var promise = getEntitiesPromise(entityType, entityIds, config);
|
||||
promise.then(
|
||||
function success(result) {
|
||||
deferred.resolve(result);
|
||||
},
|
||||
function fail() {
|
||||
deferred.reject();
|
||||
}
|
||||
);
|
||||
if (promise) {
|
||||
promise.then(
|
||||
function success(result) {
|
||||
deferred.resolve(result);
|
||||
},
|
||||
function fail() {
|
||||
deferred.reject();
|
||||
}
|
||||
);
|
||||
} else {
|
||||
deferred.reject();
|
||||
}
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function getEntitiesByPageLinkPromise(entityType, pageLink, config) {
|
||||
function getEntitiesByPageLinkPromise(entityType, pageLink, config, subType) {
|
||||
var promise;
|
||||
var user = userService.getCurrentUser();
|
||||
var customerId = user.customerId;
|
||||
switch (entityType) {
|
||||
case types.entityType.device:
|
||||
if (user.authority === 'CUSTOMER_USER') {
|
||||
promise = deviceService.getCustomerDevices(customerId, pageLink, false, config);
|
||||
promise = deviceService.getCustomerDevices(customerId, pageLink, false, config, subType);
|
||||
} else {
|
||||
promise = deviceService.getTenantDevices(pageLink, false, config);
|
||||
promise = deviceService.getTenantDevices(pageLink, false, config, subType);
|
||||
}
|
||||
break;
|
||||
case types.entityType.asset:
|
||||
if (user.authority === 'CUSTOMER_USER') {
|
||||
promise = assetService.getCustomerAssets(customerId, pageLink, false, config);
|
||||
promise = assetService.getCustomerAssets(customerId, pageLink, false, config, subType);
|
||||
} else {
|
||||
promise = assetService.getTenantAssets(pageLink, false, config);
|
||||
promise = assetService.getTenantAssets(pageLink, false, config, subType);
|
||||
}
|
||||
break;
|
||||
case types.entityType.tenant:
|
||||
@ -183,48 +204,48 @@ function EntityService($http, $q, $filter, $translate, userService, deviceServic
|
||||
case types.entityType.plugin:
|
||||
promise = pluginService.getAllPlugins(pageLink);
|
||||
break;
|
||||
case types.entityType.dashboard:
|
||||
if (user.authority === 'CUSTOMER_USER') {
|
||||
promise = dashboardService.getCustomerDashboards(customerId, pageLink);
|
||||
} else {
|
||||
promise = dashboardService.getTenantDashboards(pageLink);
|
||||
}
|
||||
break;
|
||||
case types.entityType.user:
|
||||
$log.error('Get User Entities is not implemented!');
|
||||
break;
|
||||
case types.entityType.alarm:
|
||||
$log.error('Get Alarm Entities is not implemented!');
|
||||
break;
|
||||
}
|
||||
return promise;
|
||||
}
|
||||
|
||||
function getEntitiesByNameFilter(entityType, entityNameFilter, limit, config) {
|
||||
function getEntitiesByNameFilter(entityType, entityNameFilter, limit, config, subType) {
|
||||
var deferred = $q.defer();
|
||||
var pageLink = {limit: limit, textSearch: entityNameFilter};
|
||||
var promise = getEntitiesByPageLinkPromise(entityType, pageLink, config);
|
||||
promise.then(
|
||||
function success(result) {
|
||||
if (result.data && result.data.length > 0) {
|
||||
deferred.resolve(result.data);
|
||||
} else {
|
||||
var promise = getEntitiesByPageLinkPromise(entityType, pageLink, config, subType);
|
||||
if (promise) {
|
||||
promise.then(
|
||||
function success(result) {
|
||||
if (result.data && result.data.length > 0) {
|
||||
deferred.resolve(result.data);
|
||||
} else {
|
||||
deferred.resolve(null);
|
||||
}
|
||||
},
|
||||
function fail() {
|
||||
deferred.resolve(null);
|
||||
}
|
||||
},
|
||||
function fail() {
|
||||
deferred.resolve(null);
|
||||
}
|
||||
);
|
||||
);
|
||||
} else {
|
||||
deferred.resolve(null);
|
||||
}
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function entityName(entityType, entity) {
|
||||
var name = '';
|
||||
switch (entityType) {
|
||||
case types.entityType.device:
|
||||
case types.entityType.asset:
|
||||
case types.entityType.rule:
|
||||
case types.entityType.plugin:
|
||||
name = entity.name;
|
||||
break;
|
||||
case types.entityType.tenant:
|
||||
case types.entityType.customer:
|
||||
name = entity.title;
|
||||
break;
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
function entityToEntityInfo(entityType, entity) {
|
||||
return { name: entityName(entityType, entity), entityType: entityType, id: entity.id.id };
|
||||
return { name: entity.name, entityType: entityType, id: entity.id.id };
|
||||
}
|
||||
|
||||
function entitiesToEntitiesInfo(entityType, entities) {
|
||||
|
||||
@ -55,4 +55,10 @@
|
||||
default-event-type="{{vm.types.eventType.alarm.value}}">
|
||||
</tb-event-table>
|
||||
</md-tab>
|
||||
<md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode" label="{{ 'relation.relations' | translate }}">
|
||||
<tb-relation-table flex
|
||||
entity-id="vm.grid.operatingItem().id.id"
|
||||
entity-type="{{vm.types.entityType.asset}}">
|
||||
</tb-relation-table>
|
||||
</md-tab>
|
||||
</tb-grid>
|
||||
|
||||
@ -98,7 +98,10 @@ export default angular.module('thingsboard.types', [])
|
||||
rule: "RULE",
|
||||
plugin: "PLUGIN",
|
||||
tenant: "TENANT",
|
||||
customer: "CUSTOMER"
|
||||
customer: "CUSTOMER",
|
||||
user: "USER",
|
||||
dashboard: "DASHBOARD",
|
||||
alarm: "ALARM"
|
||||
},
|
||||
entitySearchDirection: {
|
||||
from: "FROM",
|
||||
|
||||
@ -108,7 +108,8 @@ function Utils($mdColorPalette, $rootScope, $window, types) {
|
||||
guid: guid,
|
||||
isLocalUrl: isLocalUrl,
|
||||
validateDatasources: validateDatasources,
|
||||
createKey: createKey
|
||||
createKey: createKey,
|
||||
entityTypeName: entityTypeName
|
||||
}
|
||||
|
||||
return service;
|
||||
@ -346,4 +347,27 @@ function Utils($mdColorPalette, $rootScope, $window, types) {
|
||||
return dataKey;
|
||||
}
|
||||
|
||||
function entityTypeName (type) {
|
||||
switch (type) {
|
||||
case types.entityType.device:
|
||||
return 'entity.type-device';
|
||||
case types.entityType.asset:
|
||||
return 'entity.type-asset';
|
||||
case types.entityType.rule:
|
||||
return 'entity.type-rule';
|
||||
case types.entityType.plugin:
|
||||
return 'entity.type-plugin';
|
||||
case types.entityType.tenant:
|
||||
return 'entity.type-tenant';
|
||||
case types.entityType.customer:
|
||||
return 'entity.type-customer';
|
||||
case types.entityType.user:
|
||||
return 'entity.type-user';
|
||||
case types.entityType.dashboard:
|
||||
return 'entity.type-dashboard';
|
||||
case types.entityType.alarm:
|
||||
return 'entity.type-alarm';
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -34,7 +34,7 @@
|
||||
</md-item-template>
|
||||
<md-not-found>
|
||||
<div class="tb-not-found">
|
||||
<span translate translate-values='{ dashboard: dashboardSearchText }'>dashboard.no-dashboards-matching</span>
|
||||
<span translate translate-values='{ entity: dashboardSearchText }'>dashboard.no-dashboards-matching</span>
|
||||
</div>
|
||||
</md-not-found>
|
||||
<div ng-messages="theForm.dashboard.$error">
|
||||
|
||||
@ -34,7 +34,7 @@
|
||||
</md-item-template>
|
||||
<md-not-found>
|
||||
<div class="tb-not-found">
|
||||
<span translate translate-values='{ plugin: pluginSearchText }'>plugin.no-plugins-matching</span>
|
||||
<span translate translate-values='{ entity: pluginSearchText }'>plugin.no-plugins-matching</span>
|
||||
</div>
|
||||
</md-not-found>
|
||||
</md-autocomplete>
|
||||
|
||||
@ -109,7 +109,7 @@ export default function EntityStateController($scope, $location, $state, $stateP
|
||||
if (params && params.entityId && params.entityId.id && params.entityId.entityType) {
|
||||
entityService.getEntity(params.entityId.entityType, params.entityId.id, {ignoreLoading: true, ignoreErrors: true}).then(
|
||||
function success(entity) {
|
||||
var entityName = entityService.entityName(params.entityId.entityType, entity);
|
||||
var entityName = entity.name;
|
||||
deferred.resolve(entityName);
|
||||
},
|
||||
function fail() {
|
||||
|
||||
@ -128,9 +128,9 @@
|
||||
<table md-table md-row-select multiple="" ng-model="selectedAttributes" md-progress="attributesDeferred.promise">
|
||||
<thead md-head md-order="query.order" md-on-reorder="onReorder">
|
||||
<tr md-row>
|
||||
<th md-column md-order-by="lastUpdateTs"><span>Last update time</span></th>
|
||||
<th md-column md-order-by="key"><span>Key</span></th>
|
||||
<th md-column>Value</th>
|
||||
<th md-column md-order-by="lastUpdateTs"><span translate>attribute.last-update-time</span></th>
|
||||
<th md-column md-order-by="key"><span translate>attribute.key</span></th>
|
||||
<th md-column><span translate>attribute.value</span></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody md-body>
|
||||
|
||||
@ -110,7 +110,7 @@ export default function EntityAliasesController(utils, entityService, toast, $sc
|
||||
entityAlias.changed = false;
|
||||
}
|
||||
if (!entityAlias.changed && entity && entityAlias.entityType) {
|
||||
entityAlias.alias = entityService.entityName(entityAlias.entityType, entity);
|
||||
entityAlias.alias = entity.name;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
171
ui/src/app/entity/entity-autocomplete.directive.js
Normal file
171
ui/src/app/entity/entity-autocomplete.directive.js
Normal file
@ -0,0 +1,171 @@
|
||||
/*
|
||||
* Copyright © 2016-2017 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.
|
||||
*/
|
||||
import './entity-autocomplete.scss';
|
||||
|
||||
/* eslint-disable import/no-unresolved, import/default */
|
||||
|
||||
import entityAutocompleteTemplate from './entity-autocomplete.tpl.html';
|
||||
|
||||
/* eslint-enable import/no-unresolved, import/default */
|
||||
|
||||
/*@ngInject*/
|
||||
export default function EntityAutocomplete($compile, $templateCache, $q, $filter, entityService, types) {
|
||||
|
||||
var linker = function (scope, element, attrs, ngModelCtrl) {
|
||||
var template = $templateCache.get(entityAutocompleteTemplate);
|
||||
element.html(template);
|
||||
|
||||
scope.tbRequired = angular.isDefined(scope.tbRequired) ? scope.tbRequired : false;
|
||||
scope.entity = null;
|
||||
scope.entitySearchText = '';
|
||||
|
||||
scope.fetchEntities = function(searchText) {
|
||||
var deferred = $q.defer();
|
||||
entityService.getEntitiesByNameFilter(scope.entityType, searchText, 50, null, scope.entitySubtype).then(function success(result) {
|
||||
if (result) {
|
||||
deferred.resolve(result);
|
||||
} else {
|
||||
deferred.resolve([]);
|
||||
}
|
||||
}, function fail() {
|
||||
deferred.reject();
|
||||
});
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
scope.entitySearchTextChanged = function() {
|
||||
}
|
||||
|
||||
scope.updateView = function () {
|
||||
if (!scope.disabled) {
|
||||
ngModelCtrl.$setViewValue(scope.entity ? scope.entity.id.id : null);
|
||||
}
|
||||
}
|
||||
|
||||
ngModelCtrl.$render = function () {
|
||||
if (ngModelCtrl.$viewValue) {
|
||||
entityService.getEntity(scope.entityType, ngModelCtrl.$viewValue).then(
|
||||
function success(entity) {
|
||||
scope.entity = entity;
|
||||
},
|
||||
function fail() {
|
||||
scope.entity = null;
|
||||
}
|
||||
);
|
||||
} else {
|
||||
scope.entity = null;
|
||||
}
|
||||
}
|
||||
|
||||
scope.$watch('entityType', function () {
|
||||
load();
|
||||
});
|
||||
|
||||
scope.$watch('entitySubtype', function () {
|
||||
if (scope.entity && scope.entity.type != scope.entitySubtype) {
|
||||
scope.entity = null;
|
||||
scope.updateView();
|
||||
}
|
||||
});
|
||||
|
||||
scope.$watch('entity', function () {
|
||||
scope.updateView();
|
||||
});
|
||||
|
||||
scope.$watch('disabled', function () {
|
||||
scope.updateView();
|
||||
});
|
||||
|
||||
|
||||
function load() {
|
||||
switch (scope.entityType) {
|
||||
case types.entityType.asset:
|
||||
scope.selectEntityText = 'asset.select-asset';
|
||||
scope.entityText = 'asset.asset';
|
||||
scope.noEntitiesMatchingText = 'asset.no-assets-matching';
|
||||
scope.entityRequiredText = 'asset.asset-required'
|
||||
break;
|
||||
case types.entityType.device:
|
||||
scope.selectEntityText = 'device.select-device';
|
||||
scope.entityText = 'device.device';
|
||||
scope.noEntitiesMatchingText = 'device.no-devices-matching';
|
||||
scope.entityRequiredText = 'device.device-required'
|
||||
break;
|
||||
case types.entityType.rule:
|
||||
scope.selectEntityText = 'rule.select-rule';
|
||||
scope.entityText = 'rule.rule';
|
||||
scope.noEntitiesMatchingText = 'rule.no-rules-matching';
|
||||
scope.entityRequiredText = 'rule.rule-required'
|
||||
break;
|
||||
case types.entityType.plugin:
|
||||
scope.selectEntityText = 'plugin.select-plugin';
|
||||
scope.entityText = 'plugin.plugin';
|
||||
scope.noEntitiesMatchingText = 'plugin.no-plugins-matching';
|
||||
scope.entityRequiredText = 'plugin.plugin-required'
|
||||
break;
|
||||
case types.entityType.tenant:
|
||||
scope.selectEntityText = 'tenant.select-tenant';
|
||||
scope.entityText = 'tenant.tenant';
|
||||
scope.noEntitiesMatchingText = 'tenant.no-tenants-matching';
|
||||
scope.entityRequiredText = 'tenant.tenant-required'
|
||||
break;
|
||||
case types.entityType.customer:
|
||||
scope.selectEntityText = 'customer.select-customer';
|
||||
scope.entityText = 'customer.customer';
|
||||
scope.noEntitiesMatchingText = 'customer.no-customers-matching';
|
||||
scope.entityRequiredText = 'customer.customer-required'
|
||||
break;
|
||||
case types.entityType.user:
|
||||
scope.selectEntityText = 'user.select-user';
|
||||
scope.entityText = 'user.user';
|
||||
scope.noEntitiesMatchingText = 'user.no-users-matching';
|
||||
scope.entityRequiredText = 'user.user-required'
|
||||
break;
|
||||
case types.entityType.dashboard:
|
||||
scope.selectEntityText = 'dashboard.select-dashboard';
|
||||
scope.entityText = 'dashboard.dashboard';
|
||||
scope.noEntitiesMatchingText = 'dashboard.no-dashboards-matching';
|
||||
scope.entityRequiredText = 'dashboard.dashboard-required'
|
||||
break;
|
||||
case types.entityType.alarm:
|
||||
scope.selectEntityText = 'alarm.select-alarm';
|
||||
scope.entityText = 'alarm.alarm';
|
||||
scope.noEntitiesMatchingText = 'alarm.no-alarms-matching';
|
||||
scope.entityRequiredText = 'alarm.alarm-required'
|
||||
break;
|
||||
}
|
||||
if (scope.entity && scope.entity.id.entityType != scope.entityType) {
|
||||
scope.entity = null;
|
||||
scope.updateView();
|
||||
}
|
||||
}
|
||||
|
||||
$compile(element.contents())(scope);
|
||||
}
|
||||
|
||||
return {
|
||||
restrict: "E",
|
||||
require: "^ngModel",
|
||||
link: linker,
|
||||
scope: {
|
||||
theForm: '=?',
|
||||
tbRequired: '=?',
|
||||
disabled:'=ngDisabled',
|
||||
entityType: '=',
|
||||
entitySubtype: '=?'
|
||||
}
|
||||
};
|
||||
}
|
||||
25
ui/src/app/entity/entity-autocomplete.scss
Normal file
25
ui/src/app/entity/entity-autocomplete.scss
Normal file
@ -0,0 +1,25 @@
|
||||
/**
|
||||
* Copyright © 2016-2017 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.
|
||||
*/
|
||||
.tb-entity-autocomplete {
|
||||
.tb-entity-item {
|
||||
display: block;
|
||||
height: 48px;
|
||||
}
|
||||
li {
|
||||
height: auto !important;
|
||||
white-space: normal !important;
|
||||
}
|
||||
}
|
||||
45
ui/src/app/entity/entity-autocomplete.tpl.html
Normal file
45
ui/src/app/entity/entity-autocomplete.tpl.html
Normal file
@ -0,0 +1,45 @@
|
||||
<!--
|
||||
|
||||
Copyright © 2016-2017 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.
|
||||
|
||||
-->
|
||||
<md-autocomplete ng-required="tbRequired"
|
||||
ng-disabled="disabled"
|
||||
md-no-cache="true"
|
||||
md-input-name="entity"
|
||||
ng-model="entity"
|
||||
md-selected-item="entity"
|
||||
md-search-text="entitySearchText"
|
||||
md-search-text-change="entitySearchTextChanged()"
|
||||
md-items="item in fetchEntities(entitySearchText)"
|
||||
md-item-text="item.name"
|
||||
md-min-length="0"
|
||||
md-floating-label="{{ entityText | translate }}"
|
||||
md-select-on-match="true"
|
||||
md-menu-class="tb-entity-autocomplete">
|
||||
<md-item-template>
|
||||
<div class="tb-entity-item">
|
||||
<span md-highlight-text="entitySearchText" md-highlight-flags="^i">{{item.name}}</span>
|
||||
</div>
|
||||
</md-item-template>
|
||||
<md-not-found>
|
||||
<div class="tb-not-found">
|
||||
<span translate translate-values='{ entity: entitySearchText }'>{{ noEntitiesMatchingText }}</span>
|
||||
</div>
|
||||
</md-not-found>
|
||||
<div ng-messages="theForm.entity.$error">
|
||||
<div translate ng-message="required">{{ entityRequiredText }}</div>
|
||||
</div>
|
||||
</md-autocomplete>
|
||||
@ -32,14 +32,6 @@ export default function EntityFilterDirective($compile, $templateCache, $q, enti
|
||||
|
||||
scope.ngModelCtrl = ngModelCtrl;
|
||||
|
||||
scope.itemName = function(item) {
|
||||
if (item) {
|
||||
return entityService.entityName(scope.entityType, item);
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
scope.fetchEntities = function(searchText, limit) {
|
||||
var deferred = $q.defer();
|
||||
entityService.getEntitiesByNameFilter(scope.entityType, searchText, limit).then(function success(result) {
|
||||
|
||||
@ -33,7 +33,7 @@
|
||||
md-min-length="0"
|
||||
placeholder="{{ 'entity.entity-list' | translate }}">
|
||||
<md-item-template>
|
||||
<span md-highlight-text="entitySearchText" md-highlight-flags="^i">{{itemName(item)}}</span>
|
||||
<span md-highlight-text="entitySearchText" md-highlight-flags="^i">{{item.name}}</span>
|
||||
</md-item-template>
|
||||
<md-not-found>
|
||||
<span translate translate-values='{ entity: entitySearchText }'>entity.no-entities-matching</span>
|
||||
|
||||
86
ui/src/app/entity/entity-select.directive.js
Normal file
86
ui/src/app/entity/entity-select.directive.js
Normal file
@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Copyright © 2016-2017 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.
|
||||
*/
|
||||
import './entity-select.scss';
|
||||
|
||||
/* eslint-disable import/no-unresolved, import/default */
|
||||
|
||||
import entitySelectTemplate from './entity-select.tpl.html';
|
||||
|
||||
/* eslint-enable import/no-unresolved, import/default */
|
||||
|
||||
/*@ngInject*/
|
||||
export default function EntitySelect($compile, $templateCache) {
|
||||
|
||||
var linker = function (scope, element, attrs, ngModelCtrl) {
|
||||
var template = $templateCache.get(entitySelectTemplate);
|
||||
element.html(template);
|
||||
|
||||
scope.tbRequired = angular.isDefined(scope.tbRequired) ? scope.tbRequired : false;
|
||||
scope.model = null;
|
||||
|
||||
scope.updateView = function () {
|
||||
if (!scope.disabled) {
|
||||
var value = ngModelCtrl.$viewValue;
|
||||
if (scope.model && scope.model.entityType && scope.model.entityId) {
|
||||
if (!value) {
|
||||
value = {};
|
||||
}
|
||||
value.entityType = scope.model.entityType;
|
||||
value.id = scope.model.entityId;
|
||||
ngModelCtrl.$setViewValue(value);
|
||||
} else {
|
||||
ngModelCtrl.$setViewValue(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ngModelCtrl.$render = function () {
|
||||
if (ngModelCtrl.$viewValue) {
|
||||
var value = ngModelCtrl.$viewValue;
|
||||
scope.model = {};
|
||||
scope.model.entityType = value.entityType;
|
||||
scope.model.entityId = value.id;
|
||||
} else {
|
||||
scope.model = null;
|
||||
}
|
||||
}
|
||||
|
||||
scope.$watch('model.entityType', function () {
|
||||
scope.updateView();
|
||||
});
|
||||
|
||||
scope.$watch('model.entityId', function () {
|
||||
scope.updateView();
|
||||
});
|
||||
|
||||
scope.$watch('disabled', function () {
|
||||
scope.updateView();
|
||||
});
|
||||
|
||||
$compile(element.contents())(scope);
|
||||
}
|
||||
|
||||
return {
|
||||
restrict: "E",
|
||||
require: "^ngModel",
|
||||
link: linker,
|
||||
scope: {
|
||||
theForm: '=?',
|
||||
tbRequired: '=?',
|
||||
disabled:'=ngDisabled'
|
||||
}
|
||||
};
|
||||
}
|
||||
19
ui/src/app/entity/entity-select.scss
Normal file
19
ui/src/app/entity/entity-select.scss
Normal file
@ -0,0 +1,19 @@
|
||||
/**
|
||||
* Copyright © 2016-2017 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.
|
||||
*/
|
||||
|
||||
.tb-entity-select {
|
||||
|
||||
}
|
||||
29
ui/src/app/entity/entity-select.tpl.html
Normal file
29
ui/src/app/entity/entity-select.tpl.html
Normal file
@ -0,0 +1,29 @@
|
||||
<!--
|
||||
|
||||
Copyright © 2016-2017 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.
|
||||
|
||||
-->
|
||||
<div layout='row' class="tb-entity-select">
|
||||
<tb-entity-type-select style="min-width: 100px;"
|
||||
ng-model="model.entityType">
|
||||
</tb-entity-type-select>
|
||||
<tb-entity-autocomplete flex
|
||||
the-form="theForm"
|
||||
ng-disabled="disabled"
|
||||
tb-required="tbRequired"
|
||||
entity-type="model.entityType"
|
||||
ng-model="model.entityId">
|
||||
</tb-entity-autocomplete>
|
||||
</div>
|
||||
@ -23,7 +23,7 @@ import entityTypeSelectTemplate from './entity-type-select.tpl.html';
|
||||
/* eslint-enable import/no-unresolved, import/default */
|
||||
|
||||
/*@ngInject*/
|
||||
export default function EntityTypeSelect($compile, $templateCache, userService, types) {
|
||||
export default function EntityTypeSelect($compile, $templateCache, utils, userService, types) {
|
||||
|
||||
var linker = function (scope, element, attrs, ngModelCtrl) {
|
||||
var template = $templateCache.get(entityTypeSelectTemplate);
|
||||
@ -51,10 +51,12 @@ export default function EntityTypeSelect($compile, $templateCache, userService,
|
||||
scope.entityTypes.customer = types.entityType.customer;
|
||||
scope.entityTypes.rule = types.entityType.rule;
|
||||
scope.entityTypes.plugin = types.entityType.plugin;
|
||||
scope.entityTypes.dashboard = types.entityType.dashboard;
|
||||
break;
|
||||
case 'CUSTOMER_USER':
|
||||
scope.entityTypes.device = types.entityType.device;
|
||||
scope.entityTypes.asset = types.entityType.asset;
|
||||
scope.entityTypes.dashboard = types.entityType.dashboard;
|
||||
break;
|
||||
}
|
||||
|
||||
@ -67,20 +69,7 @@ export default function EntityTypeSelect($compile, $templateCache, userService,
|
||||
}
|
||||
|
||||
scope.typeName = function(type) {
|
||||
switch (type) {
|
||||
case types.entityType.device:
|
||||
return 'entity.type-device';
|
||||
case types.entityType.asset:
|
||||
return 'entity.type-asset';
|
||||
case types.entityType.rule:
|
||||
return 'entity.type-rule';
|
||||
case types.entityType.plugin:
|
||||
return 'entity.type-plugin';
|
||||
case types.entityType.tenant:
|
||||
return 'entity.type-tenant';
|
||||
case types.entityType.customer:
|
||||
return 'entity.type-customer';
|
||||
}
|
||||
return utils.entityTypeName(type);
|
||||
}
|
||||
|
||||
scope.updateValidity = function () {
|
||||
|
||||
@ -18,12 +18,15 @@ import EntityAliasesController from './entity-aliases.controller';
|
||||
import EntityTypeSelectDirective from './entity-type-select.directive';
|
||||
import EntitySubtypeSelectDirective from './entity-subtype-select.directive';
|
||||
import EntitySubtypeAutocompleteDirective from './entity-subtype-autocomplete.directive';
|
||||
import EntityAutocompleteDirective from './entity-autocomplete.directive';
|
||||
import EntitySelectDirective from './entity-select.directive';
|
||||
import EntityFilterDirective from './entity-filter.directive';
|
||||
import AliasesEntitySelectPanelController from './aliases-entity-select-panel.controller';
|
||||
import AliasesEntitySelectDirective from './aliases-entity-select.directive';
|
||||
import AddAttributeDialogController from './attribute/add-attribute-dialog.controller';
|
||||
import AddWidgetToDashboardDialogController from './attribute/add-widget-to-dashboard-dialog.controller';
|
||||
import AttributeTableDirective from './attribute/attribute-table.directive';
|
||||
import RelationTableDirective from './relation/relation-table.directive';
|
||||
|
||||
export default angular.module('thingsboard.entity', [])
|
||||
.controller('EntityAliasesController', EntityAliasesController)
|
||||
@ -33,7 +36,10 @@ export default angular.module('thingsboard.entity', [])
|
||||
.directive('tbEntityTypeSelect', EntityTypeSelectDirective)
|
||||
.directive('tbEntitySubtypeSelect', EntitySubtypeSelectDirective)
|
||||
.directive('tbEntitySubtypeAutocomplete', EntitySubtypeAutocompleteDirective)
|
||||
.directive('tbEntityAutocomplete', EntityAutocompleteDirective)
|
||||
.directive('tbEntitySelect', EntitySelectDirective)
|
||||
.directive('tbEntityFilter', EntityFilterDirective)
|
||||
.directive('tbAliasesEntitySelect', AliasesEntitySelectDirective)
|
||||
.directive('tbAttributeTable', AttributeTableDirective)
|
||||
.directive('tbRelationTable', RelationTableDirective)
|
||||
.name;
|
||||
|
||||
43
ui/src/app/entity/relation/add-relation-dialog.controller.js
Normal file
43
ui/src/app/entity/relation/add-relation-dialog.controller.js
Normal file
@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright © 2016-2017 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.
|
||||
*/
|
||||
/*@ngInject*/
|
||||
export default function AddRelationDialogController($scope, $mdDialog, types, entityRelationService, from) {
|
||||
|
||||
var vm = this;
|
||||
|
||||
vm.types = types;
|
||||
|
||||
vm.relation = {};
|
||||
vm.relation.from = from;
|
||||
vm.relation.type = types.entityRelationType.contains;
|
||||
|
||||
vm.add = add;
|
||||
vm.cancel = cancel;
|
||||
|
||||
function cancel() {
|
||||
$mdDialog.cancel();
|
||||
}
|
||||
|
||||
function add() {
|
||||
$scope.theForm.$setPristine();
|
||||
entityRelationService.saveRelation(vm.relation).then(
|
||||
function success() {
|
||||
$mdDialog.hide();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
64
ui/src/app/entity/relation/add-relation-dialog.tpl.html
Normal file
64
ui/src/app/entity/relation/add-relation-dialog.tpl.html
Normal file
@ -0,0 +1,64 @@
|
||||
<!--
|
||||
|
||||
Copyright © 2016-2017 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.
|
||||
|
||||
-->
|
||||
<md-dialog aria-label="{{ 'relation.add' | translate }}" style="min-width: 400px;">
|
||||
<form name="theForm" ng-submit="vm.add()">
|
||||
<md-toolbar>
|
||||
<div class="md-toolbar-tools">
|
||||
<h2 translate>relation.add</h2>
|
||||
<span flex></span>
|
||||
<md-button class="md-icon-button" ng-click="vm.cancel()">
|
||||
<ng-md-icon icon="close" aria-label="{{ 'dialog.close' | translate }}"></ng-md-icon>
|
||||
</md-button>
|
||||
</div>
|
||||
</md-toolbar>
|
||||
<md-progress-linear class="md-warn" md-mode="indeterminate" ng-disabled="!loading" ng-show="loading"></md-progress-linear>
|
||||
<span style="min-height: 5px;" flex="" ng-show="!loading"></span>
|
||||
<md-dialog-content>
|
||||
<div class="md-dialog-content">
|
||||
<md-content class="md-padding" layout="column">
|
||||
<fieldset ng-disabled="loading">
|
||||
<md-input-container class="md-block">
|
||||
<label translate>relation.relation-type</label>
|
||||
<md-select required ng-model="vm.relation.type" ng-disabled="loading">
|
||||
<md-option ng-repeat="type in vm.types.entityRelationType" ng-value="type">
|
||||
<span>{{('relation.relation-types.' + type) | translate}}</span>
|
||||
</md-option>
|
||||
</md-select>
|
||||
</md-input-container>
|
||||
<span class="tb-small">{{'entity.entity' | translate }}</span>
|
||||
<tb-entity-select flex
|
||||
the-form="theForm"
|
||||
tb-required="true"
|
||||
ng-model="vm.relation.to">
|
||||
</tb-entity-select>
|
||||
</fieldset>
|
||||
</md-content>
|
||||
</div>
|
||||
</md-dialog-content>
|
||||
<md-dialog-actions layout="row">
|
||||
<span flex></span>
|
||||
<md-button ng-disabled="loading || theForm.$invalid || !theForm.$dirty" type="submit"
|
||||
class="md-raised md-primary">
|
||||
{{ 'action.add' | translate }}
|
||||
</md-button>
|
||||
<md-button ng-disabled="loading" ng-click="vm.cancel()" style="margin-right:20px;">{{ 'action.cancel' |
|
||||
translate }}
|
||||
</md-button>
|
||||
</md-dialog-actions>
|
||||
</form>
|
||||
</md-dialog>
|
||||
179
ui/src/app/entity/relation/relation-table.directive.js
Normal file
179
ui/src/app/entity/relation/relation-table.directive.js
Normal file
@ -0,0 +1,179 @@
|
||||
/*
|
||||
* Copyright © 2016-2017 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.
|
||||
*/
|
||||
import 'angular-material-data-table/dist/md-data-table.min.css';
|
||||
import './relation-table.scss';
|
||||
|
||||
/* eslint-disable import/no-unresolved, import/default */
|
||||
|
||||
import relationTableTemplate from './relation-table.tpl.html';
|
||||
import addRelationTemplate from './add-relation-dialog.tpl.html';
|
||||
|
||||
/* eslint-enable import/no-unresolved, import/default */
|
||||
|
||||
import AddRelationController from './add-relation-dialog.controller';
|
||||
|
||||
/*@ngInject*/
|
||||
export default function RelationTable() {
|
||||
return {
|
||||
restrict: "E",
|
||||
scope: true,
|
||||
bindToController: {
|
||||
entityId: '=',
|
||||
entityType: '@'
|
||||
},
|
||||
controller: RelationTableController,
|
||||
controllerAs: 'vm',
|
||||
templateUrl: relationTableTemplate
|
||||
};
|
||||
}
|
||||
|
||||
/*@ngInject*/
|
||||
function RelationTableController($scope, $q, $mdDialog, $document, $translate, $filter, utils, types, entityRelationService) {
|
||||
|
||||
let vm = this;
|
||||
|
||||
vm.relations = [];
|
||||
vm.relationsCount = 0;
|
||||
vm.allRelations = [];
|
||||
vm.selectedRelations = [];
|
||||
|
||||
vm.query = {
|
||||
order: 'typeName',
|
||||
limit: 5,
|
||||
page: 1,
|
||||
search: null
|
||||
};
|
||||
|
||||
vm.enterFilterMode = enterFilterMode;
|
||||
vm.exitFilterMode = exitFilterMode;
|
||||
vm.onReorder = onReorder;
|
||||
vm.onPaginate = onPaginate;
|
||||
vm.addRelation = addRelation;
|
||||
vm.editRelation = editRelation;
|
||||
vm.deleteRelation = deleteRelation;
|
||||
vm.deleteRelations = deleteRelations;
|
||||
vm.reloadRelations = reloadRelations;
|
||||
vm.updateRelations = updateRelations;
|
||||
|
||||
|
||||
$scope.$watch("vm.entityId", function(newVal, prevVal) {
|
||||
if (newVal && !angular.equals(newVal, prevVal)) {
|
||||
reloadRelations();
|
||||
}
|
||||
});
|
||||
|
||||
$scope.$watch("vm.query.search", function(newVal, prevVal) {
|
||||
if (!angular.equals(newVal, prevVal) && vm.query.search != null) {
|
||||
updateRelations();
|
||||
}
|
||||
});
|
||||
|
||||
function enterFilterMode () {
|
||||
vm.query.search = '';
|
||||
}
|
||||
|
||||
function exitFilterMode () {
|
||||
vm.query.search = null;
|
||||
updateRelations();
|
||||
}
|
||||
|
||||
function onReorder () {
|
||||
updateRelations();
|
||||
}
|
||||
|
||||
function onPaginate () {
|
||||
updateRelations();
|
||||
}
|
||||
|
||||
function addRelation($event) {
|
||||
if ($event) {
|
||||
$event.stopPropagation();
|
||||
}
|
||||
var from = {
|
||||
id: vm.entityId,
|
||||
entityType: vm.entityType
|
||||
};
|
||||
$mdDialog.show({
|
||||
controller: AddRelationController,
|
||||
controllerAs: 'vm',
|
||||
templateUrl: addRelationTemplate,
|
||||
parent: angular.element($document[0].body),
|
||||
locals: { from: from },
|
||||
fullscreen: true,
|
||||
targetEvent: $event
|
||||
}).then(function () {
|
||||
reloadRelations();
|
||||
}, function () {
|
||||
});
|
||||
}
|
||||
|
||||
function editRelation($event, /*relation*/) {
|
||||
if ($event) {
|
||||
$event.stopPropagation();
|
||||
}
|
||||
//TODO:
|
||||
}
|
||||
|
||||
function deleteRelation($event, /*relation*/) {
|
||||
if ($event) {
|
||||
$event.stopPropagation();
|
||||
}
|
||||
//TODO:
|
||||
}
|
||||
|
||||
function deleteRelations($event) {
|
||||
if ($event) {
|
||||
$event.stopPropagation();
|
||||
}
|
||||
//TODO:
|
||||
}
|
||||
|
||||
function reloadRelations () {
|
||||
vm.allRelations.length = 0;
|
||||
vm.relations.length = 0;
|
||||
vm.relationsPromise = entityRelationService.findInfoByFrom(vm.entityId, vm.entityType);
|
||||
vm.relationsPromise.then(
|
||||
function success(allRelations) {
|
||||
allRelations.forEach(function(relation) {
|
||||
relation.typeName = $translate.instant('relation.relation-type.' + relation.type);
|
||||
relation.toEntityTypeName = $translate.instant(utils.entityTypeName(relation.to.entityType));
|
||||
});
|
||||
vm.allRelations = allRelations;
|
||||
vm.selectedRelations = [];
|
||||
vm.updateRelations();
|
||||
vm.relationsPromise = null;
|
||||
},
|
||||
function fail() {
|
||||
vm.allRelations = [];
|
||||
vm.selectedRelations = [];
|
||||
vm.updateRelations();
|
||||
vm.relationsPromise = null;
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
function updateRelations () {
|
||||
vm.selectedRelations = [];
|
||||
var result = $filter('orderBy')(vm.allRelations, vm.query.order);
|
||||
if (vm.query.search != null) {
|
||||
result = $filter('filter')(result, {$: vm.query.search});
|
||||
}
|
||||
vm.relationsCount = result.length;
|
||||
var startIndex = vm.query.limit * (vm.query.page - 1);
|
||||
vm.relations = result.slice(startIndex, startIndex + vm.query.limit);
|
||||
}
|
||||
|
||||
}
|
||||
28
ui/src/app/entity/relation/relation-table.scss
Normal file
28
ui/src/app/entity/relation/relation-table.scss
Normal file
@ -0,0 +1,28 @@
|
||||
/**
|
||||
* Copyright © 2016-2017 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.
|
||||
*/
|
||||
@import '../../../scss/constants';
|
||||
|
||||
$md-light: rgba(255, 255, 255, 100%);
|
||||
|
||||
.tb-relation-table {
|
||||
md-toolbar.md-table-toolbar.alternate {
|
||||
.md-toolbar-tools {
|
||||
md-icon {
|
||||
color: $md-light;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
119
ui/src/app/entity/relation/relation-table.tpl.html
Normal file
119
ui/src/app/entity/relation/relation-table.tpl.html
Normal file
@ -0,0 +1,119 @@
|
||||
<!--
|
||||
|
||||
Copyright © 2016-2017 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.
|
||||
|
||||
-->
|
||||
<md-content flex class="md-padding tb-absolute-fill tb-relation-table tb-data-table" layout="column">
|
||||
<div layout="column" class="md-whiteframe-z1">
|
||||
<md-toolbar class="md-table-toolbar md-default" ng-show="!vm.selectedRelations.length
|
||||
&& vm.query.search === null">
|
||||
<div class="md-toolbar-tools">
|
||||
<span translate>relation.entity-relations</span>
|
||||
<span flex></span>
|
||||
<md-button class="md-icon-button" ng-click="vm.addRelation($event)">
|
||||
<md-icon>add</md-icon>
|
||||
<md-tooltip md-direction="top">
|
||||
{{ 'action.add' | translate }}
|
||||
</md-tooltip>
|
||||
</md-button>
|
||||
<md-button class="md-icon-button" ng-click="vm.enterFilterMode()">
|
||||
<md-icon>search</md-icon>
|
||||
<md-tooltip md-direction="top">
|
||||
{{ 'action.search' | translate }}
|
||||
</md-tooltip>
|
||||
</md-button>
|
||||
<md-button class="md-icon-button" ng-click="vm.reloadRelations()">
|
||||
<md-icon>refresh</md-icon>
|
||||
<md-tooltip md-direction="top">
|
||||
{{ 'action.refresh' | translate }}
|
||||
</md-tooltip>
|
||||
</md-button>
|
||||
</div>
|
||||
</md-toolbar>
|
||||
<md-toolbar class="md-table-toolbar md-default" ng-show="!vm.selectedRelations.length
|
||||
&& vm.query.search != null">
|
||||
<div class="md-toolbar-tools">
|
||||
<md-button class="md-icon-button" aria-label="{{ 'action.search' | translate }}">
|
||||
<md-icon aria-label="{{ 'action.search' | translate }}" class="material-icons">search</md-icon>
|
||||
<md-tooltip md-direction="top">
|
||||
{{ 'action.search' | translate }}
|
||||
</md-tooltip>
|
||||
</md-button>
|
||||
<md-input-container flex>
|
||||
<label> </label>
|
||||
<input ng-model="vm.query.search" placeholder="{{ 'common.enter-search' | translate }}"/>
|
||||
</md-input-container>
|
||||
<md-button class="md-icon-button" aria-label="{{ 'action.back' | translate }}" ng-click="vm.exitFilterMode()">
|
||||
<md-icon aria-label="{{ 'action.close' | translate }}" class="material-icons">close</md-icon>
|
||||
<md-tooltip md-direction="top">
|
||||
{{ 'action.close' | translate }}
|
||||
</md-tooltip>
|
||||
</md-button>
|
||||
</div>
|
||||
</md-toolbar>
|
||||
<md-toolbar class="md-table-toolbar alternate" ng-show="vm.selectedRelations.length">
|
||||
<div class="md-toolbar-tools">
|
||||
<span translate
|
||||
translate-values="{count: selectedRelations.length}"
|
||||
translate-interpolation="messageformat">relation.selected-relations</span>
|
||||
<span flex></span>
|
||||
<md-button class="md-icon-button" ng-click="vm.deleteRelations($event)">
|
||||
<md-icon>delete</md-icon>
|
||||
<md-tooltip md-direction="top">
|
||||
{{ 'action.delete' | translate }}
|
||||
</md-tooltip>
|
||||
</md-button>
|
||||
</div>
|
||||
</md-toolbar>
|
||||
<md-table-container>
|
||||
<table md-table md-row-select multiple="" ng-model="vm.selectedRelations" md-progress="vm.relationsDeferred.promise">
|
||||
<thead md-head md-order="vm.query.order" md-on-reorder="vm.onReorder">
|
||||
<tr md-row>
|
||||
<th md-column md-order-by="typeName"><span translate>relation.type</span></th>
|
||||
<th md-column md-order-by="toEntityTypeName"><span translate>relation.to-entity-type</span></th>
|
||||
<th md-column md-order-by="toName"><span translate>relation.to-entity-name</span></th>
|
||||
<th md-column><span> </span></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody md-body>
|
||||
<tr md-row md-select="relation" md-select-id="relation" md-auto-select ng-repeat="relation in vm.relations">
|
||||
<td md-cell>{{ relation.typeName }}</td>
|
||||
<td md-cell>{{ relation.toEntityTypeName }}</td>
|
||||
<td md-cell>{{ relation.toName }}</td>
|
||||
<td md-cell class="tb-action-cell">
|
||||
<md-button class="md-icon-button" aria-label="{{ 'action.edit' | translate }}"
|
||||
ng-click="vm.editRelation($event, relation)">
|
||||
<md-icon aria-label="{{ 'action.edit' | translate }}" class="material-icons">edit</md-icon>
|
||||
<md-tooltip md-direction="top">
|
||||
{{ 'relation.edit' | translate }}
|
||||
</md-tooltip>
|
||||
</md-button>
|
||||
<md-button class="md-icon-button" aria-label="{{ 'action.delete' | translate }}" ng-click="vm.deleteRelation($event, relation)">
|
||||
<md-icon aria-label="{{ 'action.delete' | translate }}" class="material-icons">delete</md-icon>
|
||||
<md-tooltip md-direction="top">
|
||||
{{ 'relation.delete' | translate }}
|
||||
</md-tooltip>
|
||||
</md-button>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</md-table-container>
|
||||
<md-table-pagination md-limit="vm.query.limit" md-limit-options="[5, 10, 15]"
|
||||
md-page="vm.query.page" md-total="{{vm.relationsCount}}"
|
||||
md-on-paginate="onPaginate" md-page-select>
|
||||
</md-table-pagination>
|
||||
</div>
|
||||
</md-content>
|
||||
@ -235,7 +235,7 @@
|
||||
"socialshare-text": "'{{dashboardTitle}}' powered by ThingsBoard",
|
||||
"socialshare-title": "'{{dashboardTitle}}' powered by ThingsBoard",
|
||||
"select-dashboard": "Seleccionar panel",
|
||||
"no-dashboards-matching": "Panel '{{dashboard}}' no encontrado.",
|
||||
"no-dashboards-matching": "Panel '{{entity}}' no encontrado.",
|
||||
"dashboard-required": "Panel requerido.",
|
||||
"select-existing": "Seleccionar paneles existentes",
|
||||
"create-new": "Crear nuevo panel",
|
||||
@ -330,7 +330,7 @@
|
||||
"create-new-key": "Crear nueva clave!",
|
||||
"duplicate-alias-error": "Alias duplicado '{{alias}}'.<br> El alias de los dispositivos deben ser únicos dentro del panel.",
|
||||
"configure-alias": "Configurar alias '{{alias}}'",
|
||||
"no-devices-matching": "No se encontró dispositivo '{{device}}'",
|
||||
"no-devices-matching": "No se encontró dispositivo '{{entity}}'",
|
||||
"alias": "Alias",
|
||||
"alias-required": "Alias de dispositivo requerido.",
|
||||
"remove-alias": "Eliminar alias",
|
||||
@ -529,7 +529,7 @@
|
||||
"system": "Sistema",
|
||||
"select-plugin": "plugin",
|
||||
"plugin": "Plugin",
|
||||
"no-plugins-matching": "No se encontraron plugins: '{{plugin}}'",
|
||||
"no-plugins-matching": "No se encontraron plugins: '{{entity}}'",
|
||||
"plugin-required": "Plugin requerido.",
|
||||
"plugin-require-match": "Por favor, elija un plugin existente.",
|
||||
"events": "Eventos",
|
||||
|
||||
@ -218,7 +218,7 @@ export default function addLocaleKorean(locales) {
|
||||
"unassign-dashboards-title": "{ count, select, 1 {대시보드 1개} other {대시보드 #개} }의 할당을 취소하시겠습니까?",
|
||||
"unassign-dashboards-text": "선택된 대시보드가 할당 해제되고 커스터머는 액세스 할 수 없게됩니다.",
|
||||
"select-dashboard": "대시보드 선택",
|
||||
"no-dashboards-matching": "'{{dashboard}}'와 일치하는 대시보드가 없습니다.",
|
||||
"no-dashboards-matching": "'{{entity}}'와 일치하는 대시보드가 없습니다.",
|
||||
"dashboard-required": "대시보드를 입력하세요.",
|
||||
"select-existing": "기존 대시보드 선택",
|
||||
"create-new": "대시보드 생성",
|
||||
@ -305,7 +305,7 @@ export default function addLocaleKorean(locales) {
|
||||
"create-new-key": "새로 만들기!",
|
||||
"duplicate-alias-error": "중복된 '{{alias}}' 앨리어스가 있습니다.<br> 디바이스 앨리어스는 대시보드 내에서 고유해야 합니다.",
|
||||
"configure-alias": "'{{alias}}' 앨리어스 구성",
|
||||
"no-devices-matching": "'{{device}}'와 일치하는 디바이스를 찾을 수 없습니다.",
|
||||
"no-devices-matching": "'{{entity}}'와 일치하는 디바이스를 찾을 수 없습니다.",
|
||||
"alias": "앨리어스",
|
||||
"alias-required": "디바이스 앨리어스를 입력하세요.",
|
||||
"remove-alias": "디바이스 앨리어스 삭제",
|
||||
@ -496,7 +496,7 @@ export default function addLocaleKorean(locales) {
|
||||
"system": "시스템",
|
||||
"select-plugin": "플러그인 선택",
|
||||
"plugin": "플러그인",
|
||||
"no-plugins-matching": "'{{plugin}}'과 일치하는 플러그인을 찾을 수 없습니다.",
|
||||
"no-plugins-matching": "'{{entity}}'과 일치하는 플러그인을 찾을 수 없습니다.",
|
||||
"plugin-required": "플러그인을 입력하세요.",
|
||||
"plugin-require-match": "기존의 플러그인을 선택해주세요.",
|
||||
"events": "이벤트",
|
||||
|
||||
@ -235,7 +235,7 @@ export default function addLocaleRussian(locales) {
|
||||
"socialshare-text": "'{{dashboardTitle}}' сделано ThingsBoard",
|
||||
"socialshare-title": "'{{dashboardTitle}}' сделано ThingsBoard",
|
||||
"select-dashboard": "Выберите дашборд",
|
||||
"no-dashboards-matching": "Дашборд '{{dashboard}}' не найден.",
|
||||
"no-dashboards-matching": "Дашборд '{{entity}}' не найден.",
|
||||
"dashboard-required": "Дашборд обязателен.",
|
||||
"select-existing": "Выберите существующий дашборд",
|
||||
"create-new": "Создать новый дашборд",
|
||||
@ -330,7 +330,7 @@ export default function addLocaleRussian(locales) {
|
||||
"create-new-key": "Создать новый!",
|
||||
"duplicate-alias-error": "Найден дублирующийся псевдоним '{{alias}}'.<br>В рамках дашборда псевдонимы устройств должны быть уникальными.",
|
||||
"configure-alias": "Конфигурировать '{{alias}}' псевдоним",
|
||||
"no-devices-matching": "Устройство '{{device}}' не найдено.",
|
||||
"no-devices-matching": "Устройство '{{entity}}' не найдено.",
|
||||
"alias": "Псевдоним",
|
||||
"alias-required": "Псевдоним устройства обязателен.",
|
||||
"remove-alias": "Удалить псевдоним устройства",
|
||||
@ -529,7 +529,7 @@ export default function addLocaleRussian(locales) {
|
||||
"system": "Системный",
|
||||
"select-plugin": "Выберите плагин",
|
||||
"plugin": "Плагин",
|
||||
"no-plugins-matching": "Плагин '{{plugin}}' не найден.",
|
||||
"no-plugins-matching": "Плагин '{{entity}}' не найден.",
|
||||
"plugin-required": "Плагин обязателен.",
|
||||
"plugin-require-match": "Пожалуйста, выберите существующий плагин.",
|
||||
"events": "События",
|
||||
|
||||
@ -235,7 +235,7 @@ export default function addLocaleChinese(locales) {
|
||||
"socialshare-text" : "'{{dashboardTitle}}' 由ThingsBoard提供支持",
|
||||
"socialshare-title" : "'{{dashboardTitle}}' 由ThingsBoard提供支持",
|
||||
"select-dashboard" : "选择仪表板",
|
||||
"no-dashboards-matching" : "找不到符合 '{{dashboard}}' 的仪表板。",
|
||||
"no-dashboards-matching" : "找不到符合 '{{entity}}' 的仪表板。",
|
||||
"dashboard-required" : "仪表板是必需的。",
|
||||
"select-existing" : "选择现有仪表板",
|
||||
"create-new" : "创建新的仪表板",
|
||||
@ -330,7 +330,7 @@ export default function addLocaleChinese(locales) {
|
||||
"create-new-key": "创建一个新的!",
|
||||
"duplicate-alias-error" : "找到重复别名 '{{alias}}'。 <br> 设备别名必须是唯一的。",
|
||||
"configure-alias" : "配置 '{{alias}}' 别名",
|
||||
"no-devices-matching" : "找不到与 '{{device}}' 匹配的设备。",
|
||||
"no-devices-matching" : "找不到与 '{{entity}}' 匹配的设备。",
|
||||
"alias" : "别名",
|
||||
"alias-required" : "需要设备别名。",
|
||||
"remove-alias": "删除设备别名",
|
||||
@ -529,7 +529,7 @@ export default function addLocaleChinese(locales) {
|
||||
"system" : "系统",
|
||||
"select-plugin" : "选择插件",
|
||||
"plugin" : "插件",
|
||||
"no-plugins-matching" : "没有找到匹配'{{plugin}}'的插件。",
|
||||
"no-plugins-matching" : "没有找到匹配'{{entity}}'的插件。",
|
||||
"plugin-required" : "插件是必需的。",
|
||||
"plugin-require-match" : "请选择一个现有的插件。",
|
||||
"events" : "事件",
|
||||
|
||||
@ -106,6 +106,12 @@ export default angular.module('thingsboard.locale', [])
|
||||
"enable-tls": "Enable TLS",
|
||||
"send-test-mail": "Send test mail"
|
||||
},
|
||||
"alarm": {
|
||||
"alarm": "Alarm",
|
||||
"select-alarm": "Select alarm",
|
||||
"no-alarms-matching": "No alarms matching '{{entity}}' were found.",
|
||||
"alarm-required": "Alarm is required"
|
||||
},
|
||||
"asset": {
|
||||
"asset": "Asset",
|
||||
"assets": "Assets",
|
||||
@ -157,7 +163,10 @@ export default angular.module('thingsboard.locale', [])
|
||||
"unassign-assets-title": "Are you sure you want to unassign { count, select, 1 {1 asset} other {# assets} }?",
|
||||
"unassign-assets-text": "After the confirmation all selected assets will be unassigned and won't be accessible by the customer.",
|
||||
"copyId": "Copy asset Id",
|
||||
"idCopiedMessage": "Asset Id has been copied to clipboard"
|
||||
"idCopiedMessage": "Asset Id has been copied to clipboard",
|
||||
"select-asset": "Select asset",
|
||||
"no-assets-matching": "No assets matching '{{entity}}' were found.",
|
||||
"asset-required": "Asset is required"
|
||||
},
|
||||
"attribute": {
|
||||
"attributes": "Attributes",
|
||||
@ -169,6 +178,7 @@ export default angular.module('thingsboard.locale', [])
|
||||
"scope-shared": "Shared attributes",
|
||||
"add": "Add attribute",
|
||||
"key": "Key",
|
||||
"last-update-time": "Last update time",
|
||||
"key-required": "Attribute key is required.",
|
||||
"value": "Value",
|
||||
"value-required": "Attribute value is required.",
|
||||
@ -210,6 +220,7 @@ export default angular.module('thingsboard.locale', [])
|
||||
"enter-search": "Enter search"
|
||||
},
|
||||
"customer": {
|
||||
"customer": "Customer",
|
||||
"customers": "Customers",
|
||||
"management": "Customer management",
|
||||
"dashboard": "Customer Dashboard",
|
||||
@ -246,7 +257,10 @@ export default angular.module('thingsboard.locale', [])
|
||||
"details": "Details",
|
||||
"events": "Events",
|
||||
"copyId": "Copy customer Id",
|
||||
"idCopiedMessage": "Customer Id has been copied to clipboard"
|
||||
"idCopiedMessage": "Customer Id has been copied to clipboard",
|
||||
"select-customer": "Select customer",
|
||||
"no-customers-matching": "No customers matching '{{entity}}' were found.",
|
||||
"customer-required": "Customer is required"
|
||||
},
|
||||
"datetime": {
|
||||
"date-from": "Date from",
|
||||
@ -304,7 +318,7 @@ export default angular.module('thingsboard.locale', [])
|
||||
"socialshare-text": "'{{dashboardTitle}}' powered by ThingsBoard",
|
||||
"socialshare-title": "'{{dashboardTitle}}' powered by ThingsBoard",
|
||||
"select-dashboard": "Select dashboard",
|
||||
"no-dashboards-matching": "No dashboards matching '{{dashboard}}' were found.",
|
||||
"no-dashboards-matching": "No dashboards matching '{{entity}}' were found.",
|
||||
"dashboard-required": "Dashboard is required.",
|
||||
"select-existing": "Select existing dashboard",
|
||||
"create-new": "Create new dashboard",
|
||||
@ -425,7 +439,7 @@ export default angular.module('thingsboard.locale', [])
|
||||
"create-new-key": "Create a new one!",
|
||||
"duplicate-alias-error": "Duplicate alias found '{{alias}}'.<br>Device aliases must be unique whithin the dashboard.",
|
||||
"configure-alias": "Configure '{{alias}}' alias",
|
||||
"no-devices-matching": "No devices matching '{{device}}' were found.",
|
||||
"no-devices-matching": "No devices matching '{{entity}}' were found.",
|
||||
"alias": "Alias",
|
||||
"alias-required": "Device alias is required.",
|
||||
"remove-alias": "Remove device alias",
|
||||
@ -497,7 +511,8 @@ export default angular.module('thingsboard.locale', [])
|
||||
"unable-delete-device-alias-text": "Device alias '{{deviceAlias}}' can't be deleted as it used by the following widget(s):<br/>{{widgetsList}}",
|
||||
"is-gateway": "Is gateway",
|
||||
"public": "Public",
|
||||
"device-public": "Device is public"
|
||||
"device-public": "Device is public",
|
||||
"select-device": "Select device"
|
||||
},
|
||||
"dialog": {
|
||||
"close": "Close dialog"
|
||||
@ -535,6 +550,9 @@ export default angular.module('thingsboard.locale', [])
|
||||
"type-plugin": "Plugin",
|
||||
"type-tenant": "Tenant",
|
||||
"type-customer": "Customer",
|
||||
"type-user": "User",
|
||||
"type-dashboard": "Dashboard",
|
||||
"type-alarm": "Alarm",
|
||||
"select-entities": "Select entities",
|
||||
"no-aliases-found": "No aliases found.",
|
||||
"no-alias-matching": "'{{alias}}' not found.",
|
||||
@ -672,7 +690,7 @@ export default angular.module('thingsboard.locale', [])
|
||||
"system": "System",
|
||||
"select-plugin": "Select plugin",
|
||||
"plugin": "Plugin",
|
||||
"no-plugins-matching": "No plugins matching '{{plugin}}' were found.",
|
||||
"no-plugins-matching": "No plugins matching '{{entity}}' were found.",
|
||||
"plugin-required": "Plugin is required.",
|
||||
"plugin-require-match": "Please select an existing plugin.",
|
||||
"events": "Events",
|
||||
@ -685,6 +703,7 @@ export default angular.module('thingsboard.locale', [])
|
||||
"invalid-plugin-file-error": "Unable to import plugin: Invalid plugin data structure.",
|
||||
"copyId": "Copy plugin Id",
|
||||
"idCopiedMessage": "Plugin Id has been copied to clipboard"
|
||||
|
||||
},
|
||||
"position": {
|
||||
"top": "Top",
|
||||
@ -697,7 +716,24 @@ export default angular.module('thingsboard.locale', [])
|
||||
"change-password": "Change Password",
|
||||
"current-password": "Current password"
|
||||
},
|
||||
"relation": {
|
||||
"relations": "Relations",
|
||||
"entity-relations": "Entity relations",
|
||||
"selected-relations": "{ count, select, 1 {1 relation} other {# relations} } selected",
|
||||
"type": "Type",
|
||||
"to-entity-type": "Entity type",
|
||||
"to-entity-name": "Entity name",
|
||||
"edit": "Edit relation",
|
||||
"delete": "Delete relation",
|
||||
"relation-type": "Relation type",
|
||||
"relation-types": {
|
||||
"Contains": "Contains",
|
||||
"Manages": "Manages"
|
||||
},
|
||||
"add": "Add relation"
|
||||
},
|
||||
"rule": {
|
||||
"rule": "Rule",
|
||||
"rules": "Rules",
|
||||
"delete": "Delete rule",
|
||||
"activate": "Activate rule",
|
||||
@ -749,12 +785,16 @@ export default angular.module('thingsboard.locale', [])
|
||||
"rule-file": "Rule file",
|
||||
"invalid-rule-file-error": "Unable to import rule: Invalid rule data structure.",
|
||||
"copyId": "Copy rule Id",
|
||||
"idCopiedMessage": "Rule Id has been copied to clipboard"
|
||||
"idCopiedMessage": "Rule Id has been copied to clipboard",
|
||||
"select-rule": "Select rule",
|
||||
"no-rules-matching": "No rules matching '{{entity}}' were found.",
|
||||
"rule-required": "Rule is required"
|
||||
},
|
||||
"rule-plugin": {
|
||||
"management": "Rules and plugins management"
|
||||
},
|
||||
"tenant": {
|
||||
"tenant": "Tenant",
|
||||
"tenants": "Tenants",
|
||||
"management": "Tenant management",
|
||||
"add": "Add Tenant",
|
||||
@ -775,7 +815,10 @@ export default angular.module('thingsboard.locale', [])
|
||||
"details": "Details",
|
||||
"events": "Events",
|
||||
"copyId": "Copy tenant Id",
|
||||
"idCopiedMessage": "Tenant Id has been copied to clipboard"
|
||||
"idCopiedMessage": "Tenant Id has been copied to clipboard",
|
||||
"select-tenant": "Select tenant",
|
||||
"no-tenants-matching": "No tenants matching '{{entity}}' were found.",
|
||||
"tenant-required": "Tenant is required"
|
||||
},
|
||||
"timeinterval": {
|
||||
"seconds-interval": "{ seconds, select, 1 {1 second} other {# seconds} }",
|
||||
@ -803,6 +846,7 @@ export default angular.module('thingsboard.locale', [])
|
||||
"time-period": "Time period"
|
||||
},
|
||||
"user": {
|
||||
"user": "User",
|
||||
"users": "Users",
|
||||
"customer-users": "Customer Users",
|
||||
"tenant-admins": "Tenant Admins",
|
||||
@ -828,7 +872,10 @@ export default angular.module('thingsboard.locale', [])
|
||||
"last-name": "Last Name",
|
||||
"description": "Description",
|
||||
"default-dashboard": "Default dashboard",
|
||||
"always-fullscreen": "Always fullscreen"
|
||||
"always-fullscreen": "Always fullscreen",
|
||||
"select-user": "Select user",
|
||||
"no-users-matching": "No users matching '{{entity}}' were found.",
|
||||
"user-required": "User is required"
|
||||
},
|
||||
"value": {
|
||||
"type": "Value type",
|
||||
|
||||
@ -261,6 +261,45 @@ pre.tb-highlight {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.tb-data-table {
|
||||
md-toolbar {
|
||||
z-index: 0;
|
||||
}
|
||||
span.no-data-found {
|
||||
position: relative;
|
||||
height: calc(100% - 57px);
|
||||
text-transform: uppercase;
|
||||
display: flex;
|
||||
}
|
||||
table.md-table {
|
||||
tbody {
|
||||
tr {
|
||||
td {
|
||||
&.tb-action-cell {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
min-width: 72px;
|
||||
max-width: 72px;
|
||||
width: 72px;
|
||||
.md-button {
|
||||
&.md-icon-button {
|
||||
margin: 0;
|
||||
padding: 6px;
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
}
|
||||
}
|
||||
.tb-spacer {
|
||||
padding-left: 38px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/***********************
|
||||
* Flow
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user