Showing
61 changed files
with
1516 additions
and
145 deletions
... | ... | @@ -21,6 +21,7 @@ import org.springframework.web.bind.annotation.*; |
21 | 21 | import org.thingsboard.server.common.data.id.EntityId; |
22 | 22 | import org.thingsboard.server.common.data.id.EntityIdFactory; |
23 | 23 | import org.thingsboard.server.common.data.relation.EntityRelation; |
24 | +import org.thingsboard.server.common.data.relation.EntityRelationInfo; | |
24 | 25 | import org.thingsboard.server.dao.relation.EntityRelationsQuery; |
25 | 26 | import org.thingsboard.server.exception.ThingsboardErrorCode; |
26 | 27 | import org.thingsboard.server.exception.ThingsboardException; |
... | ... | @@ -128,6 +129,21 @@ public class EntityRelationController extends BaseController { |
128 | 129 | } |
129 | 130 | |
130 | 131 | @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") |
132 | + @RequestMapping(value = "/relations/info", method = RequestMethod.GET, params = {"fromId", "fromType"}) | |
133 | + @ResponseBody | |
134 | + public List<EntityRelationInfo> findInfoByFrom(@RequestParam("fromId") String strFromId, @RequestParam("fromType") String strFromType) throws ThingsboardException { | |
135 | + checkParameter("fromId", strFromId); | |
136 | + checkParameter("fromType", strFromType); | |
137 | + EntityId entityId = EntityIdFactory.getByTypeAndId(strFromType, strFromId); | |
138 | + checkEntityId(entityId); | |
139 | + try { | |
140 | + return checkNotNull(relationService.findInfoByFrom(entityId).get()); | |
141 | + } catch (Exception e) { | |
142 | + throw handleException(e); | |
143 | + } | |
144 | + } | |
145 | + | |
146 | + @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") | |
131 | 147 | @RequestMapping(value = "/relations", method = RequestMethod.GET, params = {"fromId", "fromType", "relationType"}) |
132 | 148 | @ResponseBody |
133 | 149 | public List<EntityRelation> findByFrom(@RequestParam("fromId") String strFromId, @RequestParam("fromType") String strFromType | ... | ... |
... | ... | @@ -20,7 +20,7 @@ import org.thingsboard.server.common.data.id.TenantId; |
20 | 20 | |
21 | 21 | import com.fasterxml.jackson.databind.JsonNode; |
22 | 22 | |
23 | -public class Customer extends ContactBased<CustomerId>{ | |
23 | +public class Customer extends ContactBased<CustomerId> implements HasName { | |
24 | 24 | |
25 | 25 | private static final long serialVersionUID = -1599722990298929275L; |
26 | 26 | |
... | ... | @@ -59,6 +59,11 @@ public class Customer extends ContactBased<CustomerId>{ |
59 | 59 | this.title = title; |
60 | 60 | } |
61 | 61 | |
62 | + @Override | |
63 | + public String getName() { | |
64 | + return title; | |
65 | + } | |
66 | + | |
62 | 67 | public JsonNode getAdditionalInfo() { |
63 | 68 | return additionalInfo; |
64 | 69 | } | ... | ... |
... | ... | @@ -19,7 +19,7 @@ import org.thingsboard.server.common.data.id.CustomerId; |
19 | 19 | import org.thingsboard.server.common.data.id.DashboardId; |
20 | 20 | import org.thingsboard.server.common.data.id.TenantId; |
21 | 21 | |
22 | -public class DashboardInfo extends SearchTextBased<DashboardId> { | |
22 | +public class DashboardInfo extends SearchTextBased<DashboardId> implements HasName { | |
23 | 23 | |
24 | 24 | private TenantId tenantId; |
25 | 25 | private CustomerId customerId; |
... | ... | @@ -65,6 +65,11 @@ public class DashboardInfo extends SearchTextBased<DashboardId> { |
65 | 65 | } |
66 | 66 | |
67 | 67 | @Override |
68 | + public String getName() { | |
69 | + return title; | |
70 | + } | |
71 | + | |
72 | + @Override | |
68 | 73 | public String getSearchText() { |
69 | 74 | return title; |
70 | 75 | } | ... | ... |
... | ... | @@ -21,7 +21,7 @@ import org.thingsboard.server.common.data.id.TenantId; |
21 | 21 | |
22 | 22 | import com.fasterxml.jackson.databind.JsonNode; |
23 | 23 | |
24 | -public class Device extends SearchTextBased<DeviceId> { | |
24 | +public class Device extends SearchTextBased<DeviceId> implements HasName { | |
25 | 25 | |
26 | 26 | private static final long serialVersionUID = 2807343040519543363L; |
27 | 27 | |
... | ... | @@ -64,6 +64,7 @@ public class Device extends SearchTextBased<DeviceId> { |
64 | 64 | this.customerId = customerId; |
65 | 65 | } |
66 | 66 | |
67 | + @Override | |
67 | 68 | public String getName() { |
68 | 69 | return name; |
69 | 70 | } | ... | ... |
1 | +/** | |
2 | + * Copyright © 2016-2017 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.common.data; | |
17 | + | |
18 | +public interface HasName { | |
19 | + | |
20 | + String getName(); | |
21 | + | |
22 | +} | ... | ... |
... | ... | @@ -19,7 +19,7 @@ import org.thingsboard.server.common.data.id.TenantId; |
19 | 19 | |
20 | 20 | import com.fasterxml.jackson.databind.JsonNode; |
21 | 21 | |
22 | -public class Tenant extends ContactBased<TenantId>{ | |
22 | +public class Tenant extends ContactBased<TenantId> implements HasName { | |
23 | 23 | |
24 | 24 | private static final long serialVersionUID = 8057243243859922101L; |
25 | 25 | |
... | ... | @@ -50,6 +50,11 @@ public class Tenant extends ContactBased<TenantId>{ |
50 | 50 | this.title = title; |
51 | 51 | } |
52 | 52 | |
53 | + @Override | |
54 | + public String getName() { | |
55 | + return title; | |
56 | + } | |
57 | + | |
53 | 58 | public String getRegion() { |
54 | 59 | return region; |
55 | 60 | } | ... | ... |
... | ... | @@ -22,7 +22,7 @@ import org.thingsboard.server.common.data.security.Authority; |
22 | 22 | |
23 | 23 | import com.fasterxml.jackson.databind.JsonNode; |
24 | 24 | |
25 | -public class User extends SearchTextBased<UserId> { | |
25 | +public class User extends SearchTextBased<UserId> implements HasName { | |
26 | 26 | |
27 | 27 | private static final long serialVersionUID = 8250339805336035966L; |
28 | 28 | |
... | ... | @@ -77,6 +77,11 @@ public class User extends SearchTextBased<UserId> { |
77 | 77 | this.email = email; |
78 | 78 | } |
79 | 79 | |
80 | + @Override | |
81 | + public String getName() { | |
82 | + return email; | |
83 | + } | |
84 | + | |
80 | 85 | public Authority getAuthority() { |
81 | 86 | return authority; |
82 | 87 | } | ... | ... |
... | ... | @@ -18,13 +18,14 @@ package org.thingsboard.server.common.data.alarm; |
18 | 18 | import com.fasterxml.jackson.databind.JsonNode; |
19 | 19 | import lombok.Data; |
20 | 20 | import org.thingsboard.server.common.data.BaseData; |
21 | +import org.thingsboard.server.common.data.HasName; | |
21 | 22 | import org.thingsboard.server.common.data.id.EntityId; |
22 | 23 | |
23 | 24 | /** |
24 | 25 | * Created by ashvayka on 11.05.17. |
25 | 26 | */ |
26 | 27 | @Data |
27 | -public class Alarm extends BaseData<AlarmId> { | |
28 | +public class Alarm extends BaseData<AlarmId> implements HasName { | |
28 | 29 | |
29 | 30 | private long startTs; |
30 | 31 | private long endTs; |
... | ... | @@ -37,4 +38,8 @@ public class Alarm extends BaseData<AlarmId> { |
37 | 38 | private JsonNode details; |
38 | 39 | private boolean propagate; |
39 | 40 | |
41 | + @Override | |
42 | + public String getName() { | |
43 | + return type; | |
44 | + } | |
40 | 45 | } | ... | ... |
... | ... | @@ -16,12 +16,13 @@ |
16 | 16 | package org.thingsboard.server.common.data.asset; |
17 | 17 | |
18 | 18 | import com.fasterxml.jackson.databind.JsonNode; |
19 | +import org.thingsboard.server.common.data.HasName; | |
19 | 20 | import org.thingsboard.server.common.data.SearchTextBased; |
20 | 21 | import org.thingsboard.server.common.data.id.AssetId; |
21 | 22 | import org.thingsboard.server.common.data.id.CustomerId; |
22 | 23 | import org.thingsboard.server.common.data.id.TenantId; |
23 | 24 | |
24 | -public class Asset extends SearchTextBased<AssetId> { | |
25 | +public class Asset extends SearchTextBased<AssetId> implements HasName { | |
25 | 26 | |
26 | 27 | private static final long serialVersionUID = 2807343040519543363L; |
27 | 28 | |
... | ... | @@ -64,6 +65,7 @@ public class Asset extends SearchTextBased<AssetId> { |
64 | 65 | this.customerId = customerId; |
65 | 66 | } |
66 | 67 | |
68 | + @Override | |
67 | 69 | public String getName() { |
68 | 70 | return name; |
69 | 71 | } | ... | ... |
... | ... | @@ -15,13 +15,14 @@ |
15 | 15 | */ |
16 | 16 | package org.thingsboard.server.common.data.plugin; |
17 | 17 | |
18 | +import org.thingsboard.server.common.data.HasName; | |
18 | 19 | import org.thingsboard.server.common.data.SearchTextBased; |
19 | 20 | import org.thingsboard.server.common.data.id.PluginId; |
20 | 21 | import org.thingsboard.server.common.data.id.TenantId; |
21 | 22 | |
22 | 23 | import com.fasterxml.jackson.databind.JsonNode; |
23 | 24 | |
24 | -public class PluginMetaData extends SearchTextBased<PluginId> { | |
25 | +public class PluginMetaData extends SearchTextBased<PluginId> implements HasName { | |
25 | 26 | |
26 | 27 | private static final long serialVersionUID = 1L; |
27 | 28 | |
... | ... | @@ -75,6 +76,7 @@ public class PluginMetaData extends SearchTextBased<PluginId> { |
75 | 76 | this.tenantId = tenantId; |
76 | 77 | } |
77 | 78 | |
79 | + @Override | |
78 | 80 | public String getName() { |
79 | 81 | return name; |
80 | 82 | } | ... | ... |
... | ... | @@ -47,11 +47,11 @@ public class EntityRelation { |
47 | 47 | this.additionalInfo = additionalInfo; |
48 | 48 | } |
49 | 49 | |
50 | - public EntityRelation(EntityRelation device) { | |
51 | - this.from = device.getFrom(); | |
52 | - this.to = device.getTo(); | |
53 | - this.type = device.getType(); | |
54 | - this.additionalInfo = device.getAdditionalInfo(); | |
50 | + public EntityRelation(EntityRelation entityRelation) { | |
51 | + this.from = entityRelation.getFrom(); | |
52 | + this.to = entityRelation.getTo(); | |
53 | + this.type = entityRelation.getType(); | |
54 | + this.additionalInfo = entityRelation.getAdditionalInfo(); | |
55 | 55 | } |
56 | 56 | |
57 | 57 | public EntityId getFrom() { | ... | ... |
common/data/src/main/java/org/thingsboard/server/common/data/relation/EntityRelationInfo.java
0 → 100644
1 | +/** | |
2 | + * Copyright © 2016-2017 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | + | |
17 | +package org.thingsboard.server.common.data.relation; | |
18 | + | |
19 | +public class EntityRelationInfo extends EntityRelation { | |
20 | + | |
21 | + private static final long serialVersionUID = 2807343097519543363L; | |
22 | + | |
23 | + private String toName; | |
24 | + | |
25 | + public EntityRelationInfo() { | |
26 | + super(); | |
27 | + } | |
28 | + | |
29 | + public EntityRelationInfo(EntityRelation entityRelation) { | |
30 | + super(entityRelation); | |
31 | + } | |
32 | + | |
33 | + public String getToName() { | |
34 | + return toName; | |
35 | + } | |
36 | + | |
37 | + public void setToName(String toName) { | |
38 | + this.toName = toName; | |
39 | + } | |
40 | + | |
41 | + @Override | |
42 | + public boolean equals(Object o) { | |
43 | + if (this == o) return true; | |
44 | + if (o == null || getClass() != o.getClass()) return false; | |
45 | + if (!super.equals(o)) return false; | |
46 | + | |
47 | + EntityRelationInfo that = (EntityRelationInfo) o; | |
48 | + | |
49 | + return toName != null ? toName.equals(that.toName) : that.toName == null; | |
50 | + | |
51 | + } | |
52 | + | |
53 | + @Override | |
54 | + public int hashCode() { | |
55 | + int result = super.hashCode(); | |
56 | + result = 31 * result + (toName != null ? toName.hashCode() : 0); | |
57 | + return result; | |
58 | + } | |
59 | +} | ... | ... |
... | ... | @@ -17,6 +17,7 @@ package org.thingsboard.server.common.data.rule; |
17 | 17 | |
18 | 18 | import lombok.Data; |
19 | 19 | import lombok.ToString; |
20 | +import org.thingsboard.server.common.data.HasName; | |
20 | 21 | import org.thingsboard.server.common.data.SearchTextBased; |
21 | 22 | import org.thingsboard.server.common.data.id.CustomerId; |
22 | 23 | import org.thingsboard.server.common.data.id.RuleId; |
... | ... | @@ -26,7 +27,7 @@ import com.fasterxml.jackson.databind.JsonNode; |
26 | 27 | import org.thingsboard.server.common.data.plugin.ComponentLifecycleState; |
27 | 28 | |
28 | 29 | @Data |
29 | -public class RuleMetaData extends SearchTextBased<RuleId> { | |
30 | +public class RuleMetaData extends SearchTextBased<RuleId> implements HasName { | |
30 | 31 | |
31 | 32 | private static final long serialVersionUID = -5656679015122935465L; |
32 | 33 | |
... | ... | @@ -66,4 +67,9 @@ public class RuleMetaData extends SearchTextBased<RuleId> { |
66 | 67 | return name; |
67 | 68 | } |
68 | 69 | |
70 | + @Override | |
71 | + public String getName() { | |
72 | + return name; | |
73 | + } | |
74 | + | |
69 | 75 | } | ... | ... |
... | ... | @@ -28,6 +28,10 @@ import java.util.Optional; |
28 | 28 | */ |
29 | 29 | public interface AlarmService { |
30 | 30 | |
31 | + Alarm findAlarmById(AlarmId alarmId); | |
32 | + | |
33 | + ListenableFuture<Alarm> findAlarmByIdAsync(AlarmId alarmId); | |
34 | + | |
31 | 35 | Optional<Alarm> saveIfNotExists(Alarm alarm); |
32 | 36 | |
33 | 37 | ListenableFuture<Boolean> updateAlarm(Alarm alarm); | ... | ... |
1 | +/** | |
2 | + * Copyright © 2016-2017 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.dao.alarm; | |
17 | + | |
18 | +import com.google.common.util.concurrent.ListenableFuture; | |
19 | +import lombok.extern.slf4j.Slf4j; | |
20 | +import org.springframework.stereotype.Service; | |
21 | +import org.thingsboard.server.common.data.alarm.Alarm; | |
22 | +import org.thingsboard.server.common.data.alarm.AlarmId; | |
23 | +import org.thingsboard.server.common.data.alarm.AlarmQuery; | |
24 | +import org.thingsboard.server.common.data.page.TimePageData; | |
25 | + | |
26 | +import java.util.Optional; | |
27 | + | |
28 | +@Service | |
29 | +@Slf4j | |
30 | +public class BaseAlarmService implements AlarmService { | |
31 | + | |
32 | + @Override | |
33 | + public Alarm findAlarmById(AlarmId alarmId) { | |
34 | + return null; | |
35 | + } | |
36 | + | |
37 | + @Override | |
38 | + public ListenableFuture<Alarm> findAlarmByIdAsync(AlarmId alarmId) { | |
39 | + return null; | |
40 | + } | |
41 | + | |
42 | + @Override | |
43 | + public Optional<Alarm> saveIfNotExists(Alarm alarm) { | |
44 | + return null; | |
45 | + } | |
46 | + | |
47 | + @Override | |
48 | + public ListenableFuture<Boolean> updateAlarm(Alarm alarm) { | |
49 | + return null; | |
50 | + } | |
51 | + | |
52 | + @Override | |
53 | + public ListenableFuture<Boolean> ackAlarm(Alarm alarm) { | |
54 | + return null; | |
55 | + } | |
56 | + | |
57 | + @Override | |
58 | + public ListenableFuture<Boolean> clearAlarm(AlarmId alarmId) { | |
59 | + return null; | |
60 | + } | |
61 | + | |
62 | + @Override | |
63 | + public ListenableFuture<TimePageData<Alarm>> findAlarms(AlarmQuery query) { | |
64 | + return null; | |
65 | + } | |
66 | +} | ... | ... |
... | ... | @@ -35,7 +35,7 @@ import org.thingsboard.server.common.data.page.TextPageData; |
35 | 35 | import org.thingsboard.server.common.data.page.TextPageLink; |
36 | 36 | import org.thingsboard.server.common.data.relation.EntityRelation; |
37 | 37 | import org.thingsboard.server.dao.customer.CustomerDao; |
38 | -import org.thingsboard.server.dao.entity.BaseEntityService; | |
38 | +import org.thingsboard.server.dao.entity.AbstractEntityService; | |
39 | 39 | import org.thingsboard.server.dao.exception.DataValidationException; |
40 | 40 | import org.thingsboard.server.dao.model.*; |
41 | 41 | import org.thingsboard.server.dao.relation.EntitySearchDirection; |
... | ... | @@ -55,7 +55,7 @@ import static org.thingsboard.server.dao.service.Validator.*; |
55 | 55 | |
56 | 56 | @Service |
57 | 57 | @Slf4j |
58 | -public class BaseAssetService extends BaseEntityService implements AssetService { | |
58 | +public class BaseAssetService extends AbstractEntityService implements AssetService { | |
59 | 59 | |
60 | 60 | @Autowired |
61 | 61 | private AssetDao assetDao; | ... | ... |
... | ... | @@ -31,17 +31,15 @@ import com.google.common.util.concurrent.ListenableFuture; |
31 | 31 | import lombok.extern.slf4j.Slf4j; |
32 | 32 | import org.apache.commons.lang3.StringUtils; |
33 | 33 | import org.thingsboard.server.common.data.Customer; |
34 | -import org.thingsboard.server.common.data.asset.Asset; | |
35 | 34 | import org.thingsboard.server.common.data.id.CustomerId; |
36 | 35 | import org.thingsboard.server.common.data.id.TenantId; |
37 | 36 | import org.thingsboard.server.common.data.page.TextPageData; |
38 | 37 | import org.thingsboard.server.common.data.page.TextPageLink; |
39 | 38 | import org.thingsboard.server.dao.dashboard.DashboardService; |
40 | 39 | import org.thingsboard.server.dao.device.DeviceService; |
41 | -import org.thingsboard.server.dao.entity.BaseEntityService; | |
40 | +import org.thingsboard.server.dao.entity.AbstractEntityService; | |
42 | 41 | import org.thingsboard.server.dao.exception.DataValidationException; |
43 | 42 | import org.thingsboard.server.dao.exception.IncorrectParameterException; |
44 | -import org.thingsboard.server.dao.model.AssetEntity; | |
45 | 43 | import org.thingsboard.server.dao.model.CustomerEntity; |
46 | 44 | import org.thingsboard.server.dao.model.TenantEntity; |
47 | 45 | import org.thingsboard.server.dao.service.DataValidator; |
... | ... | @@ -53,7 +51,7 @@ import org.springframework.stereotype.Service; |
53 | 51 | import org.thingsboard.server.dao.service.Validator; |
54 | 52 | @Service |
55 | 53 | @Slf4j |
56 | -public class CustomerServiceImpl extends BaseEntityService implements CustomerService { | |
54 | +public class CustomerServiceImpl extends AbstractEntityService implements CustomerService { | |
57 | 55 | |
58 | 56 | private static final String PUBLIC_CUSTOMER_TITLE = "Public"; |
59 | 57 | ... | ... |
... | ... | @@ -15,6 +15,7 @@ |
15 | 15 | */ |
16 | 16 | package org.thingsboard.server.dao.dashboard; |
17 | 17 | |
18 | +import com.google.common.util.concurrent.ListenableFuture; | |
18 | 19 | import org.thingsboard.server.common.data.Dashboard; |
19 | 20 | import org.thingsboard.server.common.data.DashboardInfo; |
20 | 21 | import org.thingsboard.server.common.data.id.CustomerId; |
... | ... | @@ -27,8 +28,12 @@ public interface DashboardService { |
27 | 28 | |
28 | 29 | public Dashboard findDashboardById(DashboardId dashboardId); |
29 | 30 | |
31 | + public ListenableFuture<Dashboard> findDashboardByIdAsync(DashboardId dashboardId); | |
32 | + | |
30 | 33 | public DashboardInfo findDashboardInfoById(DashboardId dashboardId); |
31 | 34 | |
35 | + public ListenableFuture<DashboardInfo> findDashboardInfoByIdAsync(DashboardId dashboardId); | |
36 | + | |
32 | 37 | public Dashboard saveDashboard(Dashboard dashboard); |
33 | 38 | |
34 | 39 | public Dashboard assignDashboardToCustomer(DashboardId dashboardId, CustomerId customerId); | ... | ... |
... | ... | @@ -17,9 +17,13 @@ package org.thingsboard.server.dao.dashboard; |
17 | 17 | |
18 | 18 | import static org.thingsboard.server.dao.DaoUtil.convertDataList; |
19 | 19 | import static org.thingsboard.server.dao.DaoUtil.getData; |
20 | +import static org.thingsboard.server.dao.service.Validator.validateId; | |
20 | 21 | |
21 | 22 | import java.util.List; |
22 | 23 | |
24 | +import com.google.common.base.Function; | |
25 | +import com.google.common.util.concurrent.Futures; | |
26 | +import com.google.common.util.concurrent.ListenableFuture; | |
23 | 27 | import lombok.extern.slf4j.Slf4j; |
24 | 28 | import org.apache.commons.lang3.StringUtils; |
25 | 29 | import org.thingsboard.server.common.data.Dashboard; |
... | ... | @@ -30,7 +34,7 @@ import org.thingsboard.server.common.data.id.TenantId; |
30 | 34 | import org.thingsboard.server.common.data.page.TextPageData; |
31 | 35 | import org.thingsboard.server.common.data.page.TextPageLink; |
32 | 36 | import org.thingsboard.server.dao.customer.CustomerDao; |
33 | -import org.thingsboard.server.dao.entity.BaseEntityService; | |
37 | +import org.thingsboard.server.dao.entity.AbstractEntityService; | |
34 | 38 | import org.thingsboard.server.dao.exception.DataValidationException; |
35 | 39 | import org.thingsboard.server.dao.model.*; |
36 | 40 | import org.thingsboard.server.dao.service.DataValidator; |
... | ... | @@ -42,7 +46,7 @@ import org.thingsboard.server.dao.service.Validator; |
42 | 46 | |
43 | 47 | @Service |
44 | 48 | @Slf4j |
45 | -public class DashboardServiceImpl extends BaseEntityService implements DashboardService { | |
49 | +public class DashboardServiceImpl extends AbstractEntityService implements DashboardService { | |
46 | 50 | |
47 | 51 | @Autowired |
48 | 52 | private DashboardDao dashboardDao; |
... | ... | @@ -65,6 +69,14 @@ public class DashboardServiceImpl extends BaseEntityService implements Dashboard |
65 | 69 | } |
66 | 70 | |
67 | 71 | @Override |
72 | + public ListenableFuture<Dashboard> findDashboardByIdAsync(DashboardId dashboardId) { | |
73 | + log.trace("Executing findDashboardByIdAsync [{}]", dashboardId); | |
74 | + validateId(dashboardId, "Incorrect dashboardId " + dashboardId); | |
75 | + ListenableFuture<DashboardEntity> dashboardEntity = dashboardDao.findByIdAsync(dashboardId.getId()); | |
76 | + return Futures.transform(dashboardEntity, (Function<? super DashboardEntity, ? extends Dashboard>) input -> getData(input)); | |
77 | + } | |
78 | + | |
79 | + @Override | |
68 | 80 | public DashboardInfo findDashboardInfoById(DashboardId dashboardId) { |
69 | 81 | log.trace("Executing findDashboardInfoById [{}]", dashboardId); |
70 | 82 | Validator.validateId(dashboardId, "Incorrect dashboardId " + dashboardId); |
... | ... | @@ -73,6 +85,14 @@ public class DashboardServiceImpl extends BaseEntityService implements Dashboard |
73 | 85 | } |
74 | 86 | |
75 | 87 | @Override |
88 | + public ListenableFuture<DashboardInfo> findDashboardInfoByIdAsync(DashboardId dashboardId) { | |
89 | + log.trace("Executing findDashboardInfoByIdAsync [{}]", dashboardId); | |
90 | + validateId(dashboardId, "Incorrect dashboardId " + dashboardId); | |
91 | + ListenableFuture<DashboardInfoEntity> dashboardInfoEntity = dashboardInfoDao.findByIdAsync(dashboardId.getId()); | |
92 | + return Futures.transform(dashboardInfoEntity, (Function<? super DashboardInfoEntity, ? extends DashboardInfo>) input -> getData(input)); | |
93 | + } | |
94 | + | |
95 | + @Override | |
76 | 96 | public Dashboard saveDashboard(Dashboard dashboard) { |
77 | 97 | log.trace("Executing saveDashboard [{}]", dashboard); |
78 | 98 | dashboardValidator.validate(dashboard); | ... | ... |
... | ... | @@ -37,7 +37,7 @@ import org.thingsboard.server.common.data.relation.EntityRelation; |
37 | 37 | import org.thingsboard.server.common.data.security.DeviceCredentials; |
38 | 38 | import org.thingsboard.server.common.data.security.DeviceCredentialsType; |
39 | 39 | import org.thingsboard.server.dao.customer.CustomerDao; |
40 | -import org.thingsboard.server.dao.entity.BaseEntityService; | |
40 | +import org.thingsboard.server.dao.entity.AbstractEntityService; | |
41 | 41 | import org.thingsboard.server.dao.exception.DataValidationException; |
42 | 42 | import org.thingsboard.server.dao.model.CustomerEntity; |
43 | 43 | import org.thingsboard.server.dao.model.DeviceEntity; |
... | ... | @@ -58,7 +58,7 @@ import static org.thingsboard.server.dao.service.Validator.*; |
58 | 58 | |
59 | 59 | @Service |
60 | 60 | @Slf4j |
61 | -public class DeviceServiceImpl extends BaseEntityService implements DeviceService { | |
61 | +public class DeviceServiceImpl extends AbstractEntityService implements DeviceService { | |
62 | 62 | |
63 | 63 | @Autowired |
64 | 64 | private DeviceDao deviceDao; | ... | ... |
1 | +/** | |
2 | + * Copyright © 2016-2017 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | + | |
17 | +package org.thingsboard.server.dao.entity; | |
18 | + | |
19 | +import lombok.extern.slf4j.Slf4j; | |
20 | +import org.springframework.beans.factory.annotation.Autowired; | |
21 | +import org.thingsboard.server.common.data.id.EntityId; | |
22 | +import org.thingsboard.server.dao.relation.RelationService; | |
23 | + | |
24 | +@Slf4j | |
25 | +public abstract class AbstractEntityService { | |
26 | + | |
27 | + @Autowired | |
28 | + protected RelationService relationService; | |
29 | + | |
30 | + protected void deleteEntityRelations(EntityId entityId) { | |
31 | + log.trace("Executing deleteEntityRelations [{}]", entityId); | |
32 | + relationService.deleteEntityRelations(entityId); | |
33 | + } | |
34 | + | |
35 | + | |
36 | +} | ... | ... |
... | ... | @@ -15,23 +15,102 @@ |
15 | 15 | */ |
16 | 16 | package org.thingsboard.server.dao.entity; |
17 | 17 | |
18 | +import com.google.common.base.Function; | |
19 | +import com.google.common.util.concurrent.Futures; | |
20 | +import com.google.common.util.concurrent.ListenableFuture; | |
18 | 21 | import lombok.extern.slf4j.Slf4j; |
19 | 22 | import org.springframework.beans.factory.annotation.Autowired; |
20 | -import org.thingsboard.server.common.data.id.EntityId; | |
21 | -import org.thingsboard.server.dao.relation.RelationService; | |
23 | +import org.springframework.stereotype.Service; | |
24 | +import org.thingsboard.server.common.data.*; | |
25 | +import org.thingsboard.server.common.data.alarm.AlarmId; | |
26 | +import org.thingsboard.server.common.data.id.*; | |
27 | +import org.thingsboard.server.dao.alarm.AlarmService; | |
28 | +import org.thingsboard.server.dao.asset.AssetService; | |
29 | +import org.thingsboard.server.dao.customer.CustomerService; | |
30 | +import org.thingsboard.server.dao.dashboard.DashboardService; | |
31 | +import org.thingsboard.server.dao.device.DeviceService; | |
32 | +import org.thingsboard.server.dao.plugin.PluginService; | |
33 | +import org.thingsboard.server.dao.rule.RuleService; | |
34 | +import org.thingsboard.server.dao.tenant.TenantService; | |
35 | +import org.thingsboard.server.dao.user.UserService; | |
22 | 36 | |
23 | 37 | /** |
24 | 38 | * Created by ashvayka on 04.05.17. |
25 | 39 | */ |
40 | +@Service | |
26 | 41 | @Slf4j |
27 | -public class BaseEntityService { | |
42 | +public class BaseEntityService extends AbstractEntityService implements EntityService { | |
28 | 43 | |
29 | 44 | @Autowired |
30 | - protected RelationService relationService; | |
45 | + private AssetService assetService; | |
31 | 46 | |
32 | - protected void deleteEntityRelations(EntityId entityId) { | |
33 | - log.trace("Executing deleteEntityRelations [{}]", entityId); | |
34 | - relationService.deleteEntityRelations(entityId); | |
47 | + @Autowired | |
48 | + private DeviceService deviceService; | |
49 | + | |
50 | + @Autowired | |
51 | + private RuleService ruleService; | |
52 | + | |
53 | + @Autowired | |
54 | + private PluginService pluginService; | |
55 | + | |
56 | + @Autowired | |
57 | + private TenantService tenantService; | |
58 | + | |
59 | + @Autowired | |
60 | + private CustomerService customerService; | |
61 | + | |
62 | + @Autowired | |
63 | + private UserService userService; | |
64 | + | |
65 | + @Autowired | |
66 | + private DashboardService dashboardService; | |
67 | + | |
68 | + @Autowired | |
69 | + private AlarmService alarmService; | |
70 | + | |
71 | + @Override | |
72 | + public void deleteEntityRelations(EntityId entityId) { | |
73 | + super.deleteEntityRelations(entityId); | |
74 | + } | |
75 | + | |
76 | + @Override | |
77 | + public ListenableFuture<String> fetchEntityNameAsync(EntityId entityId) { | |
78 | + log.trace("Executing fetchEntityNameAsync [{}]", entityId); | |
79 | + ListenableFuture<String> entityName; | |
80 | + ListenableFuture<? extends HasName> hasName; | |
81 | + switch (entityId.getEntityType()) { | |
82 | + case ASSET: | |
83 | + hasName = assetService.findAssetByIdAsync(new AssetId(entityId.getId())); | |
84 | + break; | |
85 | + case DEVICE: | |
86 | + hasName = deviceService.findDeviceByIdAsync(new DeviceId(entityId.getId())); | |
87 | + break; | |
88 | + case RULE: | |
89 | + hasName = ruleService.findRuleByIdAsync(new RuleId(entityId.getId())); | |
90 | + break; | |
91 | + case PLUGIN: | |
92 | + hasName = pluginService.findPluginByIdAsync(new PluginId(entityId.getId())); | |
93 | + break; | |
94 | + case TENANT: | |
95 | + hasName = tenantService.findTenantByIdAsync(new TenantId(entityId.getId())); | |
96 | + break; | |
97 | + case CUSTOMER: | |
98 | + hasName = customerService.findCustomerByIdAsync(new CustomerId(entityId.getId())); | |
99 | + break; | |
100 | + case USER: | |
101 | + hasName = userService.findUserByIdAsync(new UserId(entityId.getId())); | |
102 | + break; | |
103 | + case DASHBOARD: | |
104 | + hasName = dashboardService.findDashboardInfoByIdAsync(new DashboardId(entityId.getId())); | |
105 | + break; | |
106 | + case ALARM: | |
107 | + hasName = alarmService.findAlarmByIdAsync(new AlarmId(entityId.getId())); | |
108 | + break; | |
109 | + default: | |
110 | + throw new IllegalStateException("Not Implemented!"); | |
111 | + } | |
112 | + entityName = Futures.transform(hasName, (Function<HasName, String>) hasName1 -> hasName1.getName() ); | |
113 | + return entityName; | |
35 | 114 | } |
36 | 115 | |
37 | 116 | } | ... | ... |
1 | +/** | |
2 | + * Copyright © 2016-2017 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | + | |
17 | +package org.thingsboard.server.dao.entity; | |
18 | + | |
19 | +import com.google.common.util.concurrent.ListenableFuture; | |
20 | +import org.thingsboard.server.common.data.id.EntityId; | |
21 | + | |
22 | +public interface EntityService { | |
23 | + | |
24 | + ListenableFuture<String> fetchEntityNameAsync(EntityId entityId); | |
25 | + | |
26 | + void deleteEntityRelations(EntityId entityId); | |
27 | + | |
28 | +} | ... | ... |
... | ... | @@ -22,7 +22,6 @@ import org.apache.commons.lang3.StringUtils; |
22 | 22 | import org.springframework.beans.factory.annotation.Autowired; |
23 | 23 | import org.springframework.stereotype.Service; |
24 | 24 | import org.thingsboard.server.common.data.id.PluginId; |
25 | -import org.thingsboard.server.common.data.id.RuleId; | |
26 | 25 | import org.thingsboard.server.common.data.id.TenantId; |
27 | 26 | import org.thingsboard.server.common.data.page.TextPageData; |
28 | 27 | import org.thingsboard.server.common.data.page.TextPageLink; |
... | ... | @@ -30,9 +29,8 @@ import org.thingsboard.server.common.data.plugin.ComponentDescriptor; |
30 | 29 | import org.thingsboard.server.common.data.plugin.ComponentLifecycleState; |
31 | 30 | import org.thingsboard.server.common.data.plugin.ComponentType; |
32 | 31 | import org.thingsboard.server.common.data.plugin.PluginMetaData; |
33 | -import org.thingsboard.server.common.data.rule.RuleMetaData; | |
34 | 32 | import org.thingsboard.server.dao.component.ComponentDescriptorService; |
35 | -import org.thingsboard.server.dao.entity.BaseEntityService; | |
33 | +import org.thingsboard.server.dao.entity.AbstractEntityService; | |
36 | 34 | import org.thingsboard.server.dao.exception.DataValidationException; |
37 | 35 | import org.thingsboard.server.dao.exception.DatabaseException; |
38 | 36 | import org.thingsboard.server.dao.exception.IncorrectParameterException; |
... | ... | @@ -55,7 +53,7 @@ import static org.thingsboard.server.dao.service.Validator.validateId; |
55 | 53 | |
56 | 54 | @Service |
57 | 55 | @Slf4j |
58 | -public class BasePluginService extends BaseEntityService implements PluginService { | |
56 | +public class BasePluginService extends AbstractEntityService implements PluginService { | |
59 | 57 | |
60 | 58 | //TODO: move to a better place. |
61 | 59 | public static final TenantId SYSTEM_TENANT = new TenantId(ModelConstants.NULL_UUID); | ... | ... |
... | ... | @@ -23,9 +23,24 @@ import lombok.extern.slf4j.Slf4j; |
23 | 23 | import org.springframework.beans.factory.annotation.Autowired; |
24 | 24 | import org.springframework.stereotype.Service; |
25 | 25 | import org.springframework.util.StringUtils; |
26 | +import org.thingsboard.server.common.data.BaseData; | |
27 | +import org.thingsboard.server.common.data.Device; | |
28 | +import org.thingsboard.server.common.data.EntityType; | |
29 | +import org.thingsboard.server.common.data.asset.Asset; | |
30 | +import org.thingsboard.server.common.data.id.AssetId; | |
31 | +import org.thingsboard.server.common.data.id.DeviceId; | |
26 | 32 | import org.thingsboard.server.common.data.id.EntityId; |
33 | +import org.thingsboard.server.common.data.id.UUIDBased; | |
27 | 34 | import org.thingsboard.server.common.data.relation.EntityRelation; |
35 | +import org.thingsboard.server.common.data.relation.EntityRelationInfo; | |
36 | +import org.thingsboard.server.dao.asset.AssetService; | |
37 | +import org.thingsboard.server.dao.customer.CustomerService; | |
38 | +import org.thingsboard.server.dao.device.DeviceService; | |
39 | +import org.thingsboard.server.dao.entity.EntityService; | |
28 | 40 | import org.thingsboard.server.dao.exception.DataValidationException; |
41 | +import org.thingsboard.server.dao.plugin.PluginService; | |
42 | +import org.thingsboard.server.dao.rule.RuleService; | |
43 | +import org.thingsboard.server.dao.tenant.TenantService; | |
29 | 44 | |
30 | 45 | import javax.annotation.Nullable; |
31 | 46 | import java.util.*; |
... | ... | @@ -41,6 +56,9 @@ public class BaseRelationService implements RelationService { |
41 | 56 | @Autowired |
42 | 57 | private RelationDao relationDao; |
43 | 58 | |
59 | + @Autowired | |
60 | + private EntityService entityService; | |
61 | + | |
44 | 62 | @Override |
45 | 63 | public ListenableFuture<Boolean> checkRelation(EntityId from, EntityId to, String relationType) { |
46 | 64 | log.trace("Executing checkRelation [{}][{}][{}]", from, to, relationType); |
... | ... | @@ -100,6 +118,31 @@ public class BaseRelationService implements RelationService { |
100 | 118 | } |
101 | 119 | |
102 | 120 | @Override |
121 | + public ListenableFuture<List<EntityRelationInfo>> findInfoByFrom(EntityId from) { | |
122 | + log.trace("Executing findInfoByFrom [{}]", from); | |
123 | + validate(from); | |
124 | + ListenableFuture<List<EntityRelation>> relations = relationDao.findAllByFrom(from); | |
125 | + ListenableFuture<List<EntityRelationInfo>> relationsInfo = Futures.transform(relations, | |
126 | + (AsyncFunction<List<EntityRelation>, List<EntityRelationInfo>>) relations1 -> { | |
127 | + List<ListenableFuture<EntityRelationInfo>> futures = new ArrayList<>(); | |
128 | + relations1.stream().forEach(relation -> futures.add(fetchRelationInfoAsync(relation))); | |
129 | + return Futures.successfulAsList(futures); | |
130 | + }); | |
131 | + return relationsInfo; | |
132 | + } | |
133 | + | |
134 | + private ListenableFuture<EntityRelationInfo> fetchRelationInfoAsync(EntityRelation relation) { | |
135 | + ListenableFuture<String> entityName = entityService.fetchEntityNameAsync(relation.getTo()); | |
136 | + ListenableFuture<EntityRelationInfo> entityRelationInfo = | |
137 | + Futures.transform(entityName, (Function<String, EntityRelationInfo>) entityName1 -> { | |
138 | + EntityRelationInfo entityRelationInfo1 = new EntityRelationInfo(relation); | |
139 | + entityRelationInfo1.setToName(entityName1); | |
140 | + return entityRelationInfo1; | |
141 | + }); | |
142 | + return entityRelationInfo; | |
143 | + } | |
144 | + | |
145 | + @Override | |
103 | 146 | public ListenableFuture<List<EntityRelation>> findByFromAndType(EntityId from, String relationType) { |
104 | 147 | log.trace("Executing findByFromAndType [{}][{}]", from, relationType); |
105 | 148 | validate(from); | ... | ... |
... | ... | @@ -18,6 +18,7 @@ package org.thingsboard.server.dao.relation; |
18 | 18 | import com.google.common.util.concurrent.ListenableFuture; |
19 | 19 | import org.thingsboard.server.common.data.id.EntityId; |
20 | 20 | import org.thingsboard.server.common.data.relation.EntityRelation; |
21 | +import org.thingsboard.server.common.data.relation.EntityRelationInfo; | |
21 | 22 | |
22 | 23 | import java.util.List; |
23 | 24 | |
... | ... | @@ -38,6 +39,8 @@ public interface RelationService { |
38 | 39 | |
39 | 40 | ListenableFuture<List<EntityRelation>> findByFrom(EntityId from); |
40 | 41 | |
42 | + ListenableFuture<List<EntityRelationInfo>> findInfoByFrom(EntityId from); | |
43 | + | |
41 | 44 | ListenableFuture<List<EntityRelation>> findByFromAndType(EntityId from, String relationType); |
42 | 45 | |
43 | 46 | ListenableFuture<List<EntityRelation>> findByTo(EntityId to); | ... | ... |
... | ... | @@ -23,7 +23,6 @@ import lombok.extern.slf4j.Slf4j; |
23 | 23 | import org.apache.commons.lang3.StringUtils; |
24 | 24 | import org.springframework.beans.factory.annotation.Autowired; |
25 | 25 | import org.springframework.stereotype.Service; |
26 | -import org.thingsboard.server.common.data.asset.Asset; | |
27 | 26 | import org.thingsboard.server.common.data.id.RuleId; |
28 | 27 | import org.thingsboard.server.common.data.id.TenantId; |
29 | 28 | import org.thingsboard.server.common.data.page.TextPageData; |
... | ... | @@ -34,11 +33,10 @@ import org.thingsboard.server.common.data.plugin.ComponentType; |
34 | 33 | import org.thingsboard.server.common.data.plugin.PluginMetaData; |
35 | 34 | import org.thingsboard.server.common.data.rule.RuleMetaData; |
36 | 35 | import org.thingsboard.server.dao.component.ComponentDescriptorService; |
37 | -import org.thingsboard.server.dao.entity.BaseEntityService; | |
36 | +import org.thingsboard.server.dao.entity.AbstractEntityService; | |
38 | 37 | import org.thingsboard.server.dao.exception.DataValidationException; |
39 | 38 | import org.thingsboard.server.dao.exception.DatabaseException; |
40 | 39 | import org.thingsboard.server.dao.exception.IncorrectParameterException; |
41 | -import org.thingsboard.server.dao.model.AssetEntity; | |
42 | 40 | import org.thingsboard.server.dao.model.RuleMetaDataEntity; |
43 | 41 | import org.thingsboard.server.dao.plugin.PluginService; |
44 | 42 | import org.thingsboard.server.dao.service.DataValidator; |
... | ... | @@ -58,7 +56,7 @@ import static org.thingsboard.server.dao.service.Validator.validatePageLink; |
58 | 56 | |
59 | 57 | @Service |
60 | 58 | @Slf4j |
61 | -public class BaseRuleService extends BaseEntityService implements RuleService { | |
59 | +public class BaseRuleService extends AbstractEntityService implements RuleService { | |
62 | 60 | |
63 | 61 | private final TenantId systemTenantId = new TenantId(NULL_UUID); |
64 | 62 | ... | ... |
... | ... | @@ -26,7 +26,6 @@ import com.google.common.util.concurrent.Futures; |
26 | 26 | import com.google.common.util.concurrent.ListenableFuture; |
27 | 27 | import lombok.extern.slf4j.Slf4j; |
28 | 28 | import org.apache.commons.lang3.StringUtils; |
29 | -import org.thingsboard.server.common.data.Customer; | |
30 | 29 | import org.thingsboard.server.common.data.Tenant; |
31 | 30 | import org.thingsboard.server.common.data.id.TenantId; |
32 | 31 | import org.thingsboard.server.common.data.page.TextPageData; |
... | ... | @@ -34,9 +33,8 @@ import org.thingsboard.server.common.data.page.TextPageLink; |
34 | 33 | import org.thingsboard.server.dao.customer.CustomerService; |
35 | 34 | import org.thingsboard.server.dao.dashboard.DashboardService; |
36 | 35 | import org.thingsboard.server.dao.device.DeviceService; |
37 | -import org.thingsboard.server.dao.entity.BaseEntityService; | |
36 | +import org.thingsboard.server.dao.entity.AbstractEntityService; | |
38 | 37 | import org.thingsboard.server.dao.exception.DataValidationException; |
39 | -import org.thingsboard.server.dao.model.CustomerEntity; | |
40 | 38 | import org.thingsboard.server.dao.model.TenantEntity; |
41 | 39 | import org.thingsboard.server.dao.plugin.PluginService; |
42 | 40 | import org.thingsboard.server.dao.rule.RuleService; |
... | ... | @@ -50,7 +48,7 @@ import org.thingsboard.server.dao.widget.WidgetsBundleService; |
50 | 48 | |
51 | 49 | @Service |
52 | 50 | @Slf4j |
53 | -public class TenantServiceImpl extends BaseEntityService implements TenantService { | |
51 | +public class TenantServiceImpl extends AbstractEntityService implements TenantService { | |
54 | 52 | |
55 | 53 | private static final String DEFAULT_TENANT_REGION = "Global"; |
56 | 54 | ... | ... |
... | ... | @@ -15,6 +15,7 @@ |
15 | 15 | */ |
16 | 16 | package org.thingsboard.server.dao.user; |
17 | 17 | |
18 | +import com.google.common.util.concurrent.ListenableFuture; | |
18 | 19 | import org.thingsboard.server.common.data.User; |
19 | 20 | import org.thingsboard.server.common.data.id.CustomerId; |
20 | 21 | import org.thingsboard.server.common.data.id.TenantId; |
... | ... | @@ -27,6 +28,8 @@ public interface UserService { |
27 | 28 | |
28 | 29 | public User findUserById(UserId userId); |
29 | 30 | |
31 | + public ListenableFuture<User> findUserByIdAsync(UserId userId); | |
32 | + | |
30 | 33 | public User findUserByEmail(String email); |
31 | 34 | |
32 | 35 | public User saveUser(User user); | ... | ... |
... | ... | @@ -23,6 +23,9 @@ import static org.thingsboard.server.dao.service.Validator.validateString; |
23 | 23 | |
24 | 24 | import java.util.List; |
25 | 25 | |
26 | +import com.google.common.base.Function; | |
27 | +import com.google.common.util.concurrent.Futures; | |
28 | +import com.google.common.util.concurrent.ListenableFuture; | |
26 | 29 | import lombok.extern.slf4j.Slf4j; |
27 | 30 | import org.apache.commons.lang3.RandomStringUtils; |
28 | 31 | import org.apache.commons.lang3.StringUtils; |
... | ... | @@ -35,7 +38,7 @@ import org.thingsboard.server.common.data.page.TextPageLink; |
35 | 38 | import org.thingsboard.server.common.data.security.Authority; |
36 | 39 | import org.thingsboard.server.common.data.security.UserCredentials; |
37 | 40 | import org.thingsboard.server.dao.customer.CustomerDao; |
38 | -import org.thingsboard.server.dao.entity.BaseEntityService; | |
41 | +import org.thingsboard.server.dao.entity.AbstractEntityService; | |
39 | 42 | import org.thingsboard.server.dao.exception.DataValidationException; |
40 | 43 | import org.thingsboard.server.dao.exception.IncorrectParameterException; |
41 | 44 | import org.thingsboard.server.dao.model.*; |
... | ... | @@ -47,7 +50,7 @@ import org.springframework.stereotype.Service; |
47 | 50 | |
48 | 51 | @Service |
49 | 52 | @Slf4j |
50 | -public class UserServiceImpl extends BaseEntityService implements UserService { | |
53 | +public class UserServiceImpl extends AbstractEntityService implements UserService { | |
51 | 54 | |
52 | 55 | @Autowired |
53 | 56 | private UserDao userDao; |
... | ... | @@ -78,6 +81,14 @@ public class UserServiceImpl extends BaseEntityService implements UserService { |
78 | 81 | } |
79 | 82 | |
80 | 83 | @Override |
84 | + public ListenableFuture<User> findUserByIdAsync(UserId userId) { | |
85 | + log.trace("Executing findUserByIdAsync [{}]", userId); | |
86 | + validateId(userId, "Incorrect userId " + userId); | |
87 | + ListenableFuture<UserEntity> userEntity = userDao.findByIdAsync(userId.getId()); | |
88 | + return Futures.transform(userEntity, (Function<? super UserEntity, ? extends User>) input -> getData(input)); | |
89 | + } | |
90 | + | |
91 | + @Override | |
81 | 92 | public User saveUser(User user) { |
82 | 93 | log.trace("Executing saveUser [{}]", user); |
83 | 94 | userValidator.validate(user); | ... | ... |
... | ... | @@ -25,6 +25,7 @@ function EntityRelationService($http, $q) { |
25 | 25 | deleteRelation: deleteRelation, |
26 | 26 | deleteRelations: deleteRelations, |
27 | 27 | findByFrom: findByFrom, |
28 | + findInfoByFrom: findInfoByFrom, | |
28 | 29 | findByFromAndType: findByFromAndType, |
29 | 30 | findByTo: findByTo, |
30 | 31 | findByToAndType: findByToAndType, |
... | ... | @@ -84,6 +85,18 @@ function EntityRelationService($http, $q) { |
84 | 85 | return deferred.promise; |
85 | 86 | } |
86 | 87 | |
88 | + function findInfoByFrom(fromId, fromType) { | |
89 | + var deferred = $q.defer(); | |
90 | + var url = '/api/relations/info?fromId=' + fromId; | |
91 | + url += '&fromType=' + fromType; | |
92 | + $http.get(url, null).then(function success(response) { | |
93 | + deferred.resolve(response.data); | |
94 | + }, function fail() { | |
95 | + deferred.reject(); | |
96 | + }); | |
97 | + return deferred.promise; | |
98 | + } | |
99 | + | |
87 | 100 | function findByFromAndType(fromId, fromType, relationType) { |
88 | 101 | var deferred = $q.defer(); |
89 | 102 | var url = '/api/relations?fromId=' + fromId; | ... | ... |
... | ... | @@ -20,14 +20,13 @@ export default angular.module('thingsboard.api.entity', [thingsboardTypes]) |
20 | 20 | .name; |
21 | 21 | |
22 | 22 | /*@ngInject*/ |
23 | -function EntityService($http, $q, $filter, $translate, userService, deviceService, | |
23 | +function EntityService($http, $q, $filter, $translate, $log, userService, deviceService, | |
24 | 24 | assetService, tenantService, customerService, |
25 | - ruleService, pluginService, entityRelationService, attributeService, types, utils) { | |
25 | + ruleService, pluginService, dashboardService, entityRelationService, attributeService, types, utils) { | |
26 | 26 | var service = { |
27 | 27 | getEntity: getEntity, |
28 | 28 | getEntities: getEntities, |
29 | 29 | getEntitiesByNameFilter: getEntitiesByNameFilter, |
30 | - entityName: entityName, | |
31 | 30 | processEntityAliases: processEntityAliases, |
32 | 31 | getEntityKeys: getEntityKeys, |
33 | 32 | checkEntityAlias: checkEntityAlias, |
... | ... | @@ -63,6 +62,15 @@ function EntityService($http, $q, $filter, $translate, userService, deviceServic |
63 | 62 | case types.entityType.plugin: |
64 | 63 | promise = pluginService.getPlugin(entityId); |
65 | 64 | break; |
65 | + case types.entityType.dashboard: | |
66 | + promise = dashboardService.getDashboardInfo(entityId); | |
67 | + break; | |
68 | + case types.entityType.user: | |
69 | + promise = userService.getUser(entityId); | |
70 | + break; | |
71 | + case types.entityType.alarm: | |
72 | + $log.error('Get Alarm Entity is not implemented!'); | |
73 | + break; | |
66 | 74 | } |
67 | 75 | return promise; |
68 | 76 | } |
... | ... | @@ -134,6 +142,15 @@ function EntityService($http, $q, $filter, $translate, userService, deviceServic |
134 | 142 | case types.entityType.plugin: |
135 | 143 | promise = getEntitiesByIdsPromise(pluginService.getPlugin, entityIds); |
136 | 144 | break; |
145 | + case types.entityType.dashboard: | |
146 | + promise = getEntitiesByIdsPromise(dashboardService.getDashboardInfo, entityIds); | |
147 | + break; | |
148 | + case types.entityType.user: | |
149 | + promise = getEntitiesByIdsPromise(userService.getUser, entityIds); | |
150 | + break; | |
151 | + case types.entityType.alarm: | |
152 | + $log.error('Get Alarm Entity is not implemented!'); | |
153 | + break; | |
137 | 154 | } |
138 | 155 | return promise; |
139 | 156 | } |
... | ... | @@ -141,34 +158,38 @@ function EntityService($http, $q, $filter, $translate, userService, deviceServic |
141 | 158 | function getEntities(entityType, entityIds, config) { |
142 | 159 | var deferred = $q.defer(); |
143 | 160 | var promise = getEntitiesPromise(entityType, entityIds, config); |
144 | - promise.then( | |
145 | - function success(result) { | |
146 | - deferred.resolve(result); | |
147 | - }, | |
148 | - function fail() { | |
149 | - deferred.reject(); | |
150 | - } | |
151 | - ); | |
161 | + if (promise) { | |
162 | + promise.then( | |
163 | + function success(result) { | |
164 | + deferred.resolve(result); | |
165 | + }, | |
166 | + function fail() { | |
167 | + deferred.reject(); | |
168 | + } | |
169 | + ); | |
170 | + } else { | |
171 | + deferred.reject(); | |
172 | + } | |
152 | 173 | return deferred.promise; |
153 | 174 | } |
154 | 175 | |
155 | - function getEntitiesByPageLinkPromise(entityType, pageLink, config) { | |
176 | + function getEntitiesByPageLinkPromise(entityType, pageLink, config, subType) { | |
156 | 177 | var promise; |
157 | 178 | var user = userService.getCurrentUser(); |
158 | 179 | var customerId = user.customerId; |
159 | 180 | switch (entityType) { |
160 | 181 | case types.entityType.device: |
161 | 182 | if (user.authority === 'CUSTOMER_USER') { |
162 | - promise = deviceService.getCustomerDevices(customerId, pageLink, false, config); | |
183 | + promise = deviceService.getCustomerDevices(customerId, pageLink, false, config, subType); | |
163 | 184 | } else { |
164 | - promise = deviceService.getTenantDevices(pageLink, false, config); | |
185 | + promise = deviceService.getTenantDevices(pageLink, false, config, subType); | |
165 | 186 | } |
166 | 187 | break; |
167 | 188 | case types.entityType.asset: |
168 | 189 | if (user.authority === 'CUSTOMER_USER') { |
169 | - promise = assetService.getCustomerAssets(customerId, pageLink, false, config); | |
190 | + promise = assetService.getCustomerAssets(customerId, pageLink, false, config, subType); | |
170 | 191 | } else { |
171 | - promise = assetService.getTenantAssets(pageLink, false, config); | |
192 | + promise = assetService.getTenantAssets(pageLink, false, config, subType); | |
172 | 193 | } |
173 | 194 | break; |
174 | 195 | case types.entityType.tenant: |
... | ... | @@ -183,48 +204,48 @@ function EntityService($http, $q, $filter, $translate, userService, deviceServic |
183 | 204 | case types.entityType.plugin: |
184 | 205 | promise = pluginService.getAllPlugins(pageLink); |
185 | 206 | break; |
207 | + case types.entityType.dashboard: | |
208 | + if (user.authority === 'CUSTOMER_USER') { | |
209 | + promise = dashboardService.getCustomerDashboards(customerId, pageLink); | |
210 | + } else { | |
211 | + promise = dashboardService.getTenantDashboards(pageLink); | |
212 | + } | |
213 | + break; | |
214 | + case types.entityType.user: | |
215 | + $log.error('Get User Entities is not implemented!'); | |
216 | + break; | |
217 | + case types.entityType.alarm: | |
218 | + $log.error('Get Alarm Entities is not implemented!'); | |
219 | + break; | |
186 | 220 | } |
187 | 221 | return promise; |
188 | 222 | } |
189 | 223 | |
190 | - function getEntitiesByNameFilter(entityType, entityNameFilter, limit, config) { | |
224 | + function getEntitiesByNameFilter(entityType, entityNameFilter, limit, config, subType) { | |
191 | 225 | var deferred = $q.defer(); |
192 | 226 | var pageLink = {limit: limit, textSearch: entityNameFilter}; |
193 | - var promise = getEntitiesByPageLinkPromise(entityType, pageLink, config); | |
194 | - promise.then( | |
195 | - function success(result) { | |
196 | - if (result.data && result.data.length > 0) { | |
197 | - deferred.resolve(result.data); | |
198 | - } else { | |
227 | + var promise = getEntitiesByPageLinkPromise(entityType, pageLink, config, subType); | |
228 | + if (promise) { | |
229 | + promise.then( | |
230 | + function success(result) { | |
231 | + if (result.data && result.data.length > 0) { | |
232 | + deferred.resolve(result.data); | |
233 | + } else { | |
234 | + deferred.resolve(null); | |
235 | + } | |
236 | + }, | |
237 | + function fail() { | |
199 | 238 | deferred.resolve(null); |
200 | 239 | } |
201 | - }, | |
202 | - function fail() { | |
203 | - deferred.resolve(null); | |
204 | - } | |
205 | - ); | |
206 | - return deferred.promise; | |
207 | - } | |
208 | - | |
209 | - function entityName(entityType, entity) { | |
210 | - var name = ''; | |
211 | - switch (entityType) { | |
212 | - case types.entityType.device: | |
213 | - case types.entityType.asset: | |
214 | - case types.entityType.rule: | |
215 | - case types.entityType.plugin: | |
216 | - name = entity.name; | |
217 | - break; | |
218 | - case types.entityType.tenant: | |
219 | - case types.entityType.customer: | |
220 | - name = entity.title; | |
221 | - break; | |
240 | + ); | |
241 | + } else { | |
242 | + deferred.resolve(null); | |
222 | 243 | } |
223 | - return name; | |
244 | + return deferred.promise; | |
224 | 245 | } |
225 | 246 | |
226 | 247 | function entityToEntityInfo(entityType, entity) { |
227 | - return { name: entityName(entityType, entity), entityType: entityType, id: entity.id.id }; | |
248 | + return { name: entity.name, entityType: entityType, id: entity.id.id }; | |
228 | 249 | } |
229 | 250 | |
230 | 251 | function entitiesToEntitiesInfo(entityType, entities) { | ... | ... |
... | ... | @@ -55,4 +55,10 @@ |
55 | 55 | default-event-type="{{vm.types.eventType.alarm.value}}"> |
56 | 56 | </tb-event-table> |
57 | 57 | </md-tab> |
58 | + <md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode" label="{{ 'relation.relations' | translate }}"> | |
59 | + <tb-relation-table flex | |
60 | + entity-id="vm.grid.operatingItem().id.id" | |
61 | + entity-type="{{vm.types.entityType.asset}}"> | |
62 | + </tb-relation-table> | |
63 | + </md-tab> | |
58 | 64 | </tb-grid> | ... | ... |
... | ... | @@ -98,7 +98,10 @@ export default angular.module('thingsboard.types', []) |
98 | 98 | rule: "RULE", |
99 | 99 | plugin: "PLUGIN", |
100 | 100 | tenant: "TENANT", |
101 | - customer: "CUSTOMER" | |
101 | + customer: "CUSTOMER", | |
102 | + user: "USER", | |
103 | + dashboard: "DASHBOARD", | |
104 | + alarm: "ALARM" | |
102 | 105 | }, |
103 | 106 | entitySearchDirection: { |
104 | 107 | from: "FROM", | ... | ... |
... | ... | @@ -108,7 +108,8 @@ function Utils($mdColorPalette, $rootScope, $window, types) { |
108 | 108 | guid: guid, |
109 | 109 | isLocalUrl: isLocalUrl, |
110 | 110 | validateDatasources: validateDatasources, |
111 | - createKey: createKey | |
111 | + createKey: createKey, | |
112 | + entityTypeName: entityTypeName | |
112 | 113 | } |
113 | 114 | |
114 | 115 | return service; |
... | ... | @@ -346,4 +347,27 @@ function Utils($mdColorPalette, $rootScope, $window, types) { |
346 | 347 | return dataKey; |
347 | 348 | } |
348 | 349 | |
350 | + function entityTypeName (type) { | |
351 | + switch (type) { | |
352 | + case types.entityType.device: | |
353 | + return 'entity.type-device'; | |
354 | + case types.entityType.asset: | |
355 | + return 'entity.type-asset'; | |
356 | + case types.entityType.rule: | |
357 | + return 'entity.type-rule'; | |
358 | + case types.entityType.plugin: | |
359 | + return 'entity.type-plugin'; | |
360 | + case types.entityType.tenant: | |
361 | + return 'entity.type-tenant'; | |
362 | + case types.entityType.customer: | |
363 | + return 'entity.type-customer'; | |
364 | + case types.entityType.user: | |
365 | + return 'entity.type-user'; | |
366 | + case types.entityType.dashboard: | |
367 | + return 'entity.type-dashboard'; | |
368 | + case types.entityType.alarm: | |
369 | + return 'entity.type-alarm'; | |
370 | + } | |
371 | + } | |
372 | + | |
349 | 373 | } | ... | ... |
... | ... | @@ -34,7 +34,7 @@ |
34 | 34 | </md-item-template> |
35 | 35 | <md-not-found> |
36 | 36 | <div class="tb-not-found"> |
37 | - <span translate translate-values='{ dashboard: dashboardSearchText }'>dashboard.no-dashboards-matching</span> | |
37 | + <span translate translate-values='{ entity: dashboardSearchText }'>dashboard.no-dashboards-matching</span> | |
38 | 38 | </div> |
39 | 39 | </md-not-found> |
40 | 40 | <div ng-messages="theForm.dashboard.$error"> | ... | ... |
... | ... | @@ -34,7 +34,7 @@ |
34 | 34 | </md-item-template> |
35 | 35 | <md-not-found> |
36 | 36 | <div class="tb-not-found"> |
37 | - <span translate translate-values='{ plugin: pluginSearchText }'>plugin.no-plugins-matching</span> | |
37 | + <span translate translate-values='{ entity: pluginSearchText }'>plugin.no-plugins-matching</span> | |
38 | 38 | </div> |
39 | 39 | </md-not-found> |
40 | 40 | </md-autocomplete> | ... | ... |
... | ... | @@ -109,7 +109,7 @@ export default function EntityStateController($scope, $location, $state, $stateP |
109 | 109 | if (params && params.entityId && params.entityId.id && params.entityId.entityType) { |
110 | 110 | entityService.getEntity(params.entityId.entityType, params.entityId.id, {ignoreLoading: true, ignoreErrors: true}).then( |
111 | 111 | function success(entity) { |
112 | - var entityName = entityService.entityName(params.entityId.entityType, entity); | |
112 | + var entityName = entity.name; | |
113 | 113 | deferred.resolve(entityName); |
114 | 114 | }, |
115 | 115 | function fail() { | ... | ... |
... | ... | @@ -128,9 +128,9 @@ |
128 | 128 | <table md-table md-row-select multiple="" ng-model="selectedAttributes" md-progress="attributesDeferred.promise"> |
129 | 129 | <thead md-head md-order="query.order" md-on-reorder="onReorder"> |
130 | 130 | <tr md-row> |
131 | - <th md-column md-order-by="lastUpdateTs"><span>Last update time</span></th> | |
132 | - <th md-column md-order-by="key"><span>Key</span></th> | |
133 | - <th md-column>Value</th> | |
131 | + <th md-column md-order-by="lastUpdateTs"><span translate>attribute.last-update-time</span></th> | |
132 | + <th md-column md-order-by="key"><span translate>attribute.key</span></th> | |
133 | + <th md-column><span translate>attribute.value</span></th> | |
134 | 134 | </tr> |
135 | 135 | </thead> |
136 | 136 | <tbody md-body> | ... | ... |
... | ... | @@ -110,7 +110,7 @@ export default function EntityAliasesController(utils, entityService, toast, $sc |
110 | 110 | entityAlias.changed = false; |
111 | 111 | } |
112 | 112 | if (!entityAlias.changed && entity && entityAlias.entityType) { |
113 | - entityAlias.alias = entityService.entityName(entityAlias.entityType, entity); | |
113 | + entityAlias.alias = entity.name; | |
114 | 114 | } |
115 | 115 | } |
116 | 116 | } | ... | ... |
1 | +/* | |
2 | + * Copyright © 2016-2017 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +import './entity-autocomplete.scss'; | |
17 | + | |
18 | +/* eslint-disable import/no-unresolved, import/default */ | |
19 | + | |
20 | +import entityAutocompleteTemplate from './entity-autocomplete.tpl.html'; | |
21 | + | |
22 | +/* eslint-enable import/no-unresolved, import/default */ | |
23 | + | |
24 | +/*@ngInject*/ | |
25 | +export default function EntityAutocomplete($compile, $templateCache, $q, $filter, entityService, types) { | |
26 | + | |
27 | + var linker = function (scope, element, attrs, ngModelCtrl) { | |
28 | + var template = $templateCache.get(entityAutocompleteTemplate); | |
29 | + element.html(template); | |
30 | + | |
31 | + scope.tbRequired = angular.isDefined(scope.tbRequired) ? scope.tbRequired : false; | |
32 | + scope.entity = null; | |
33 | + scope.entitySearchText = ''; | |
34 | + | |
35 | + scope.fetchEntities = function(searchText) { | |
36 | + var deferred = $q.defer(); | |
37 | + entityService.getEntitiesByNameFilter(scope.entityType, searchText, 50, null, scope.entitySubtype).then(function success(result) { | |
38 | + if (result) { | |
39 | + deferred.resolve(result); | |
40 | + } else { | |
41 | + deferred.resolve([]); | |
42 | + } | |
43 | + }, function fail() { | |
44 | + deferred.reject(); | |
45 | + }); | |
46 | + return deferred.promise; | |
47 | + } | |
48 | + | |
49 | + scope.entitySearchTextChanged = function() { | |
50 | + } | |
51 | + | |
52 | + scope.updateView = function () { | |
53 | + if (!scope.disabled) { | |
54 | + ngModelCtrl.$setViewValue(scope.entity ? scope.entity.id.id : null); | |
55 | + } | |
56 | + } | |
57 | + | |
58 | + ngModelCtrl.$render = function () { | |
59 | + if (ngModelCtrl.$viewValue) { | |
60 | + entityService.getEntity(scope.entityType, ngModelCtrl.$viewValue).then( | |
61 | + function success(entity) { | |
62 | + scope.entity = entity; | |
63 | + }, | |
64 | + function fail() { | |
65 | + scope.entity = null; | |
66 | + } | |
67 | + ); | |
68 | + } else { | |
69 | + scope.entity = null; | |
70 | + } | |
71 | + } | |
72 | + | |
73 | + scope.$watch('entityType', function () { | |
74 | + load(); | |
75 | + }); | |
76 | + | |
77 | + scope.$watch('entitySubtype', function () { | |
78 | + if (scope.entity && scope.entity.type != scope.entitySubtype) { | |
79 | + scope.entity = null; | |
80 | + scope.updateView(); | |
81 | + } | |
82 | + }); | |
83 | + | |
84 | + scope.$watch('entity', function () { | |
85 | + scope.updateView(); | |
86 | + }); | |
87 | + | |
88 | + scope.$watch('disabled', function () { | |
89 | + scope.updateView(); | |
90 | + }); | |
91 | + | |
92 | + | |
93 | + function load() { | |
94 | + switch (scope.entityType) { | |
95 | + case types.entityType.asset: | |
96 | + scope.selectEntityText = 'asset.select-asset'; | |
97 | + scope.entityText = 'asset.asset'; | |
98 | + scope.noEntitiesMatchingText = 'asset.no-assets-matching'; | |
99 | + scope.entityRequiredText = 'asset.asset-required' | |
100 | + break; | |
101 | + case types.entityType.device: | |
102 | + scope.selectEntityText = 'device.select-device'; | |
103 | + scope.entityText = 'device.device'; | |
104 | + scope.noEntitiesMatchingText = 'device.no-devices-matching'; | |
105 | + scope.entityRequiredText = 'device.device-required' | |
106 | + break; | |
107 | + case types.entityType.rule: | |
108 | + scope.selectEntityText = 'rule.select-rule'; | |
109 | + scope.entityText = 'rule.rule'; | |
110 | + scope.noEntitiesMatchingText = 'rule.no-rules-matching'; | |
111 | + scope.entityRequiredText = 'rule.rule-required' | |
112 | + break; | |
113 | + case types.entityType.plugin: | |
114 | + scope.selectEntityText = 'plugin.select-plugin'; | |
115 | + scope.entityText = 'plugin.plugin'; | |
116 | + scope.noEntitiesMatchingText = 'plugin.no-plugins-matching'; | |
117 | + scope.entityRequiredText = 'plugin.plugin-required' | |
118 | + break; | |
119 | + case types.entityType.tenant: | |
120 | + scope.selectEntityText = 'tenant.select-tenant'; | |
121 | + scope.entityText = 'tenant.tenant'; | |
122 | + scope.noEntitiesMatchingText = 'tenant.no-tenants-matching'; | |
123 | + scope.entityRequiredText = 'tenant.tenant-required' | |
124 | + break; | |
125 | + case types.entityType.customer: | |
126 | + scope.selectEntityText = 'customer.select-customer'; | |
127 | + scope.entityText = 'customer.customer'; | |
128 | + scope.noEntitiesMatchingText = 'customer.no-customers-matching'; | |
129 | + scope.entityRequiredText = 'customer.customer-required' | |
130 | + break; | |
131 | + case types.entityType.user: | |
132 | + scope.selectEntityText = 'user.select-user'; | |
133 | + scope.entityText = 'user.user'; | |
134 | + scope.noEntitiesMatchingText = 'user.no-users-matching'; | |
135 | + scope.entityRequiredText = 'user.user-required' | |
136 | + break; | |
137 | + case types.entityType.dashboard: | |
138 | + scope.selectEntityText = 'dashboard.select-dashboard'; | |
139 | + scope.entityText = 'dashboard.dashboard'; | |
140 | + scope.noEntitiesMatchingText = 'dashboard.no-dashboards-matching'; | |
141 | + scope.entityRequiredText = 'dashboard.dashboard-required' | |
142 | + break; | |
143 | + case types.entityType.alarm: | |
144 | + scope.selectEntityText = 'alarm.select-alarm'; | |
145 | + scope.entityText = 'alarm.alarm'; | |
146 | + scope.noEntitiesMatchingText = 'alarm.no-alarms-matching'; | |
147 | + scope.entityRequiredText = 'alarm.alarm-required' | |
148 | + break; | |
149 | + } | |
150 | + if (scope.entity && scope.entity.id.entityType != scope.entityType) { | |
151 | + scope.entity = null; | |
152 | + scope.updateView(); | |
153 | + } | |
154 | + } | |
155 | + | |
156 | + $compile(element.contents())(scope); | |
157 | + } | |
158 | + | |
159 | + return { | |
160 | + restrict: "E", | |
161 | + require: "^ngModel", | |
162 | + link: linker, | |
163 | + scope: { | |
164 | + theForm: '=?', | |
165 | + tbRequired: '=?', | |
166 | + disabled:'=ngDisabled', | |
167 | + entityType: '=', | |
168 | + entitySubtype: '=?' | |
169 | + } | |
170 | + }; | |
171 | +} | ... | ... |
ui/src/app/entity/entity-autocomplete.scss
0 → 100644
1 | +/** | |
2 | + * Copyright © 2016-2017 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +.tb-entity-autocomplete { | |
17 | + .tb-entity-item { | |
18 | + display: block; | |
19 | + height: 48px; | |
20 | + } | |
21 | + li { | |
22 | + height: auto !important; | |
23 | + white-space: normal !important; | |
24 | + } | |
25 | +} | ... | ... |
1 | +<!-- | |
2 | + | |
3 | + Copyright © 2016-2017 The Thingsboard Authors | |
4 | + | |
5 | + Licensed under the Apache License, Version 2.0 (the "License"); | |
6 | + you may not use this file except in compliance with the License. | |
7 | + You may obtain a copy of the License at | |
8 | + | |
9 | + http://www.apache.org/licenses/LICENSE-2.0 | |
10 | + | |
11 | + Unless required by applicable law or agreed to in writing, software | |
12 | + distributed under the License is distributed on an "AS IS" BASIS, | |
13 | + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
14 | + See the License for the specific language governing permissions and | |
15 | + limitations under the License. | |
16 | + | |
17 | +--> | |
18 | +<md-autocomplete ng-required="tbRequired" | |
19 | + ng-disabled="disabled" | |
20 | + md-no-cache="true" | |
21 | + md-input-name="entity" | |
22 | + ng-model="entity" | |
23 | + md-selected-item="entity" | |
24 | + md-search-text="entitySearchText" | |
25 | + md-search-text-change="entitySearchTextChanged()" | |
26 | + md-items="item in fetchEntities(entitySearchText)" | |
27 | + md-item-text="item.name" | |
28 | + md-min-length="0" | |
29 | + md-floating-label="{{ entityText | translate }}" | |
30 | + md-select-on-match="true" | |
31 | + md-menu-class="tb-entity-autocomplete"> | |
32 | + <md-item-template> | |
33 | + <div class="tb-entity-item"> | |
34 | + <span md-highlight-text="entitySearchText" md-highlight-flags="^i">{{item.name}}</span> | |
35 | + </div> | |
36 | + </md-item-template> | |
37 | + <md-not-found> | |
38 | + <div class="tb-not-found"> | |
39 | + <span translate translate-values='{ entity: entitySearchText }'>{{ noEntitiesMatchingText }}</span> | |
40 | + </div> | |
41 | + </md-not-found> | |
42 | + <div ng-messages="theForm.entity.$error"> | |
43 | + <div translate ng-message="required">{{ entityRequiredText }}</div> | |
44 | + </div> | |
45 | +</md-autocomplete> | ... | ... |
... | ... | @@ -32,14 +32,6 @@ export default function EntityFilterDirective($compile, $templateCache, $q, enti |
32 | 32 | |
33 | 33 | scope.ngModelCtrl = ngModelCtrl; |
34 | 34 | |
35 | - scope.itemName = function(item) { | |
36 | - if (item) { | |
37 | - return entityService.entityName(scope.entityType, item); | |
38 | - } else { | |
39 | - return ''; | |
40 | - } | |
41 | - } | |
42 | - | |
43 | 35 | scope.fetchEntities = function(searchText, limit) { |
44 | 36 | var deferred = $q.defer(); |
45 | 37 | entityService.getEntitiesByNameFilter(scope.entityType, searchText, limit).then(function success(result) { | ... | ... |
... | ... | @@ -33,7 +33,7 @@ |
33 | 33 | md-min-length="0" |
34 | 34 | placeholder="{{ 'entity.entity-list' | translate }}"> |
35 | 35 | <md-item-template> |
36 | - <span md-highlight-text="entitySearchText" md-highlight-flags="^i">{{itemName(item)}}</span> | |
36 | + <span md-highlight-text="entitySearchText" md-highlight-flags="^i">{{item.name}}</span> | |
37 | 37 | </md-item-template> |
38 | 38 | <md-not-found> |
39 | 39 | <span translate translate-values='{ entity: entitySearchText }'>entity.no-entities-matching</span> | ... | ... |
ui/src/app/entity/entity-select.directive.js
0 → 100644
1 | +/* | |
2 | + * Copyright © 2016-2017 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +import './entity-select.scss'; | |
17 | + | |
18 | +/* eslint-disable import/no-unresolved, import/default */ | |
19 | + | |
20 | +import entitySelectTemplate from './entity-select.tpl.html'; | |
21 | + | |
22 | +/* eslint-enable import/no-unresolved, import/default */ | |
23 | + | |
24 | +/*@ngInject*/ | |
25 | +export default function EntitySelect($compile, $templateCache) { | |
26 | + | |
27 | + var linker = function (scope, element, attrs, ngModelCtrl) { | |
28 | + var template = $templateCache.get(entitySelectTemplate); | |
29 | + element.html(template); | |
30 | + | |
31 | + scope.tbRequired = angular.isDefined(scope.tbRequired) ? scope.tbRequired : false; | |
32 | + scope.model = null; | |
33 | + | |
34 | + scope.updateView = function () { | |
35 | + if (!scope.disabled) { | |
36 | + var value = ngModelCtrl.$viewValue; | |
37 | + if (scope.model && scope.model.entityType && scope.model.entityId) { | |
38 | + if (!value) { | |
39 | + value = {}; | |
40 | + } | |
41 | + value.entityType = scope.model.entityType; | |
42 | + value.id = scope.model.entityId; | |
43 | + ngModelCtrl.$setViewValue(value); | |
44 | + } else { | |
45 | + ngModelCtrl.$setViewValue(null); | |
46 | + } | |
47 | + } | |
48 | + } | |
49 | + | |
50 | + ngModelCtrl.$render = function () { | |
51 | + if (ngModelCtrl.$viewValue) { | |
52 | + var value = ngModelCtrl.$viewValue; | |
53 | + scope.model = {}; | |
54 | + scope.model.entityType = value.entityType; | |
55 | + scope.model.entityId = value.id; | |
56 | + } else { | |
57 | + scope.model = null; | |
58 | + } | |
59 | + } | |
60 | + | |
61 | + scope.$watch('model.entityType', function () { | |
62 | + scope.updateView(); | |
63 | + }); | |
64 | + | |
65 | + scope.$watch('model.entityId', function () { | |
66 | + scope.updateView(); | |
67 | + }); | |
68 | + | |
69 | + scope.$watch('disabled', function () { | |
70 | + scope.updateView(); | |
71 | + }); | |
72 | + | |
73 | + $compile(element.contents())(scope); | |
74 | + } | |
75 | + | |
76 | + return { | |
77 | + restrict: "E", | |
78 | + require: "^ngModel", | |
79 | + link: linker, | |
80 | + scope: { | |
81 | + theForm: '=?', | |
82 | + tbRequired: '=?', | |
83 | + disabled:'=ngDisabled' | |
84 | + } | |
85 | + }; | |
86 | +} | ... | ... |
ui/src/app/entity/entity-select.scss
0 → 100644
1 | +/** | |
2 | + * Copyright © 2016-2017 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | + | |
17 | +.tb-entity-select { | |
18 | + | |
19 | +} | |
\ No newline at end of file | ... | ... |
ui/src/app/entity/entity-select.tpl.html
0 → 100644
1 | +<!-- | |
2 | + | |
3 | + Copyright © 2016-2017 The Thingsboard Authors | |
4 | + | |
5 | + Licensed under the Apache License, Version 2.0 (the "License"); | |
6 | + you may not use this file except in compliance with the License. | |
7 | + You may obtain a copy of the License at | |
8 | + | |
9 | + http://www.apache.org/licenses/LICENSE-2.0 | |
10 | + | |
11 | + Unless required by applicable law or agreed to in writing, software | |
12 | + distributed under the License is distributed on an "AS IS" BASIS, | |
13 | + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
14 | + See the License for the specific language governing permissions and | |
15 | + limitations under the License. | |
16 | + | |
17 | +--> | |
18 | +<div layout='row' class="tb-entity-select"> | |
19 | + <tb-entity-type-select style="min-width: 100px;" | |
20 | + ng-model="model.entityType"> | |
21 | + </tb-entity-type-select> | |
22 | + <tb-entity-autocomplete flex | |
23 | + the-form="theForm" | |
24 | + ng-disabled="disabled" | |
25 | + tb-required="tbRequired" | |
26 | + entity-type="model.entityType" | |
27 | + ng-model="model.entityId"> | |
28 | + </tb-entity-autocomplete> | |
29 | +</div> | |
\ No newline at end of file | ... | ... |
... | ... | @@ -23,7 +23,7 @@ import entityTypeSelectTemplate from './entity-type-select.tpl.html'; |
23 | 23 | /* eslint-enable import/no-unresolved, import/default */ |
24 | 24 | |
25 | 25 | /*@ngInject*/ |
26 | -export default function EntityTypeSelect($compile, $templateCache, userService, types) { | |
26 | +export default function EntityTypeSelect($compile, $templateCache, utils, userService, types) { | |
27 | 27 | |
28 | 28 | var linker = function (scope, element, attrs, ngModelCtrl) { |
29 | 29 | var template = $templateCache.get(entityTypeSelectTemplate); |
... | ... | @@ -51,10 +51,12 @@ export default function EntityTypeSelect($compile, $templateCache, userService, |
51 | 51 | scope.entityTypes.customer = types.entityType.customer; |
52 | 52 | scope.entityTypes.rule = types.entityType.rule; |
53 | 53 | scope.entityTypes.plugin = types.entityType.plugin; |
54 | + scope.entityTypes.dashboard = types.entityType.dashboard; | |
54 | 55 | break; |
55 | 56 | case 'CUSTOMER_USER': |
56 | 57 | scope.entityTypes.device = types.entityType.device; |
57 | 58 | scope.entityTypes.asset = types.entityType.asset; |
59 | + scope.entityTypes.dashboard = types.entityType.dashboard; | |
58 | 60 | break; |
59 | 61 | } |
60 | 62 | |
... | ... | @@ -67,20 +69,7 @@ export default function EntityTypeSelect($compile, $templateCache, userService, |
67 | 69 | } |
68 | 70 | |
69 | 71 | scope.typeName = function(type) { |
70 | - switch (type) { | |
71 | - case types.entityType.device: | |
72 | - return 'entity.type-device'; | |
73 | - case types.entityType.asset: | |
74 | - return 'entity.type-asset'; | |
75 | - case types.entityType.rule: | |
76 | - return 'entity.type-rule'; | |
77 | - case types.entityType.plugin: | |
78 | - return 'entity.type-plugin'; | |
79 | - case types.entityType.tenant: | |
80 | - return 'entity.type-tenant'; | |
81 | - case types.entityType.customer: | |
82 | - return 'entity.type-customer'; | |
83 | - } | |
72 | + return utils.entityTypeName(type); | |
84 | 73 | } |
85 | 74 | |
86 | 75 | scope.updateValidity = function () { | ... | ... |
... | ... | @@ -18,12 +18,15 @@ import EntityAliasesController from './entity-aliases.controller'; |
18 | 18 | import EntityTypeSelectDirective from './entity-type-select.directive'; |
19 | 19 | import EntitySubtypeSelectDirective from './entity-subtype-select.directive'; |
20 | 20 | import EntitySubtypeAutocompleteDirective from './entity-subtype-autocomplete.directive'; |
21 | +import EntityAutocompleteDirective from './entity-autocomplete.directive'; | |
22 | +import EntitySelectDirective from './entity-select.directive'; | |
21 | 23 | import EntityFilterDirective from './entity-filter.directive'; |
22 | 24 | import AliasesEntitySelectPanelController from './aliases-entity-select-panel.controller'; |
23 | 25 | import AliasesEntitySelectDirective from './aliases-entity-select.directive'; |
24 | 26 | import AddAttributeDialogController from './attribute/add-attribute-dialog.controller'; |
25 | 27 | import AddWidgetToDashboardDialogController from './attribute/add-widget-to-dashboard-dialog.controller'; |
26 | 28 | import AttributeTableDirective from './attribute/attribute-table.directive'; |
29 | +import RelationTableDirective from './relation/relation-table.directive'; | |
27 | 30 | |
28 | 31 | export default angular.module('thingsboard.entity', []) |
29 | 32 | .controller('EntityAliasesController', EntityAliasesController) |
... | ... | @@ -33,7 +36,10 @@ export default angular.module('thingsboard.entity', []) |
33 | 36 | .directive('tbEntityTypeSelect', EntityTypeSelectDirective) |
34 | 37 | .directive('tbEntitySubtypeSelect', EntitySubtypeSelectDirective) |
35 | 38 | .directive('tbEntitySubtypeAutocomplete', EntitySubtypeAutocompleteDirective) |
39 | + .directive('tbEntityAutocomplete', EntityAutocompleteDirective) | |
40 | + .directive('tbEntitySelect', EntitySelectDirective) | |
36 | 41 | .directive('tbEntityFilter', EntityFilterDirective) |
37 | 42 | .directive('tbAliasesEntitySelect', AliasesEntitySelectDirective) |
38 | 43 | .directive('tbAttributeTable', AttributeTableDirective) |
44 | + .directive('tbRelationTable', RelationTableDirective) | |
39 | 45 | .name; | ... | ... |
1 | +/* | |
2 | + * Copyright © 2016-2017 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +/*@ngInject*/ | |
17 | +export default function AddRelationDialogController($scope, $mdDialog, types, entityRelationService, from) { | |
18 | + | |
19 | + var vm = this; | |
20 | + | |
21 | + vm.types = types; | |
22 | + | |
23 | + vm.relation = {}; | |
24 | + vm.relation.from = from; | |
25 | + vm.relation.type = types.entityRelationType.contains; | |
26 | + | |
27 | + vm.add = add; | |
28 | + vm.cancel = cancel; | |
29 | + | |
30 | + function cancel() { | |
31 | + $mdDialog.cancel(); | |
32 | + } | |
33 | + | |
34 | + function add() { | |
35 | + $scope.theForm.$setPristine(); | |
36 | + entityRelationService.saveRelation(vm.relation).then( | |
37 | + function success() { | |
38 | + $mdDialog.hide(); | |
39 | + } | |
40 | + ); | |
41 | + } | |
42 | + | |
43 | +} | ... | ... |
1 | +<!-- | |
2 | + | |
3 | + Copyright © 2016-2017 The Thingsboard Authors | |
4 | + | |
5 | + Licensed under the Apache License, Version 2.0 (the "License"); | |
6 | + you may not use this file except in compliance with the License. | |
7 | + You may obtain a copy of the License at | |
8 | + | |
9 | + http://www.apache.org/licenses/LICENSE-2.0 | |
10 | + | |
11 | + Unless required by applicable law or agreed to in writing, software | |
12 | + distributed under the License is distributed on an "AS IS" BASIS, | |
13 | + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
14 | + See the License for the specific language governing permissions and | |
15 | + limitations under the License. | |
16 | + | |
17 | +--> | |
18 | +<md-dialog aria-label="{{ 'relation.add' | translate }}" style="min-width: 400px;"> | |
19 | + <form name="theForm" ng-submit="vm.add()"> | |
20 | + <md-toolbar> | |
21 | + <div class="md-toolbar-tools"> | |
22 | + <h2 translate>relation.add</h2> | |
23 | + <span flex></span> | |
24 | + <md-button class="md-icon-button" ng-click="vm.cancel()"> | |
25 | + <ng-md-icon icon="close" aria-label="{{ 'dialog.close' | translate }}"></ng-md-icon> | |
26 | + </md-button> | |
27 | + </div> | |
28 | + </md-toolbar> | |
29 | + <md-progress-linear class="md-warn" md-mode="indeterminate" ng-disabled="!loading" ng-show="loading"></md-progress-linear> | |
30 | + <span style="min-height: 5px;" flex="" ng-show="!loading"></span> | |
31 | + <md-dialog-content> | |
32 | + <div class="md-dialog-content"> | |
33 | + <md-content class="md-padding" layout="column"> | |
34 | + <fieldset ng-disabled="loading"> | |
35 | + <md-input-container class="md-block"> | |
36 | + <label translate>relation.relation-type</label> | |
37 | + <md-select required ng-model="vm.relation.type" ng-disabled="loading"> | |
38 | + <md-option ng-repeat="type in vm.types.entityRelationType" ng-value="type"> | |
39 | + <span>{{('relation.relation-types.' + type) | translate}}</span> | |
40 | + </md-option> | |
41 | + </md-select> | |
42 | + </md-input-container> | |
43 | + <span class="tb-small">{{'entity.entity' | translate }}</span> | |
44 | + <tb-entity-select flex | |
45 | + the-form="theForm" | |
46 | + tb-required="true" | |
47 | + ng-model="vm.relation.to"> | |
48 | + </tb-entity-select> | |
49 | + </fieldset> | |
50 | + </md-content> | |
51 | + </div> | |
52 | + </md-dialog-content> | |
53 | + <md-dialog-actions layout="row"> | |
54 | + <span flex></span> | |
55 | + <md-button ng-disabled="loading || theForm.$invalid || !theForm.$dirty" type="submit" | |
56 | + class="md-raised md-primary"> | |
57 | + {{ 'action.add' | translate }} | |
58 | + </md-button> | |
59 | + <md-button ng-disabled="loading" ng-click="vm.cancel()" style="margin-right:20px;">{{ 'action.cancel' | | |
60 | + translate }} | |
61 | + </md-button> | |
62 | + </md-dialog-actions> | |
63 | + </form> | |
64 | +</md-dialog> | ... | ... |
1 | +/* | |
2 | + * Copyright © 2016-2017 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +import 'angular-material-data-table/dist/md-data-table.min.css'; | |
17 | +import './relation-table.scss'; | |
18 | + | |
19 | +/* eslint-disable import/no-unresolved, import/default */ | |
20 | + | |
21 | +import relationTableTemplate from './relation-table.tpl.html'; | |
22 | +import addRelationTemplate from './add-relation-dialog.tpl.html'; | |
23 | + | |
24 | +/* eslint-enable import/no-unresolved, import/default */ | |
25 | + | |
26 | +import AddRelationController from './add-relation-dialog.controller'; | |
27 | + | |
28 | +/*@ngInject*/ | |
29 | +export default function RelationTable() { | |
30 | + return { | |
31 | + restrict: "E", | |
32 | + scope: true, | |
33 | + bindToController: { | |
34 | + entityId: '=', | |
35 | + entityType: '@' | |
36 | + }, | |
37 | + controller: RelationTableController, | |
38 | + controllerAs: 'vm', | |
39 | + templateUrl: relationTableTemplate | |
40 | + }; | |
41 | +} | |
42 | + | |
43 | +/*@ngInject*/ | |
44 | +function RelationTableController($scope, $q, $mdDialog, $document, $translate, $filter, utils, types, entityRelationService) { | |
45 | + | |
46 | + let vm = this; | |
47 | + | |
48 | + vm.relations = []; | |
49 | + vm.relationsCount = 0; | |
50 | + vm.allRelations = []; | |
51 | + vm.selectedRelations = []; | |
52 | + | |
53 | + vm.query = { | |
54 | + order: 'typeName', | |
55 | + limit: 5, | |
56 | + page: 1, | |
57 | + search: null | |
58 | + }; | |
59 | + | |
60 | + vm.enterFilterMode = enterFilterMode; | |
61 | + vm.exitFilterMode = exitFilterMode; | |
62 | + vm.onReorder = onReorder; | |
63 | + vm.onPaginate = onPaginate; | |
64 | + vm.addRelation = addRelation; | |
65 | + vm.editRelation = editRelation; | |
66 | + vm.deleteRelation = deleteRelation; | |
67 | + vm.deleteRelations = deleteRelations; | |
68 | + vm.reloadRelations = reloadRelations; | |
69 | + vm.updateRelations = updateRelations; | |
70 | + | |
71 | + | |
72 | + $scope.$watch("vm.entityId", function(newVal, prevVal) { | |
73 | + if (newVal && !angular.equals(newVal, prevVal)) { | |
74 | + reloadRelations(); | |
75 | + } | |
76 | + }); | |
77 | + | |
78 | + $scope.$watch("vm.query.search", function(newVal, prevVal) { | |
79 | + if (!angular.equals(newVal, prevVal) && vm.query.search != null) { | |
80 | + updateRelations(); | |
81 | + } | |
82 | + }); | |
83 | + | |
84 | + function enterFilterMode () { | |
85 | + vm.query.search = ''; | |
86 | + } | |
87 | + | |
88 | + function exitFilterMode () { | |
89 | + vm.query.search = null; | |
90 | + updateRelations(); | |
91 | + } | |
92 | + | |
93 | + function onReorder () { | |
94 | + updateRelations(); | |
95 | + } | |
96 | + | |
97 | + function onPaginate () { | |
98 | + updateRelations(); | |
99 | + } | |
100 | + | |
101 | + function addRelation($event) { | |
102 | + if ($event) { | |
103 | + $event.stopPropagation(); | |
104 | + } | |
105 | + var from = { | |
106 | + id: vm.entityId, | |
107 | + entityType: vm.entityType | |
108 | + }; | |
109 | + $mdDialog.show({ | |
110 | + controller: AddRelationController, | |
111 | + controllerAs: 'vm', | |
112 | + templateUrl: addRelationTemplate, | |
113 | + parent: angular.element($document[0].body), | |
114 | + locals: { from: from }, | |
115 | + fullscreen: true, | |
116 | + targetEvent: $event | |
117 | + }).then(function () { | |
118 | + reloadRelations(); | |
119 | + }, function () { | |
120 | + }); | |
121 | + } | |
122 | + | |
123 | + function editRelation($event, /*relation*/) { | |
124 | + if ($event) { | |
125 | + $event.stopPropagation(); | |
126 | + } | |
127 | + //TODO: | |
128 | + } | |
129 | + | |
130 | + function deleteRelation($event, /*relation*/) { | |
131 | + if ($event) { | |
132 | + $event.stopPropagation(); | |
133 | + } | |
134 | + //TODO: | |
135 | + } | |
136 | + | |
137 | + function deleteRelations($event) { | |
138 | + if ($event) { | |
139 | + $event.stopPropagation(); | |
140 | + } | |
141 | + //TODO: | |
142 | + } | |
143 | + | |
144 | + function reloadRelations () { | |
145 | + vm.allRelations.length = 0; | |
146 | + vm.relations.length = 0; | |
147 | + vm.relationsPromise = entityRelationService.findInfoByFrom(vm.entityId, vm.entityType); | |
148 | + vm.relationsPromise.then( | |
149 | + function success(allRelations) { | |
150 | + allRelations.forEach(function(relation) { | |
151 | + relation.typeName = $translate.instant('relation.relation-type.' + relation.type); | |
152 | + relation.toEntityTypeName = $translate.instant(utils.entityTypeName(relation.to.entityType)); | |
153 | + }); | |
154 | + vm.allRelations = allRelations; | |
155 | + vm.selectedRelations = []; | |
156 | + vm.updateRelations(); | |
157 | + vm.relationsPromise = null; | |
158 | + }, | |
159 | + function fail() { | |
160 | + vm.allRelations = []; | |
161 | + vm.selectedRelations = []; | |
162 | + vm.updateRelations(); | |
163 | + vm.relationsPromise = null; | |
164 | + } | |
165 | + ) | |
166 | + } | |
167 | + | |
168 | + function updateRelations () { | |
169 | + vm.selectedRelations = []; | |
170 | + var result = $filter('orderBy')(vm.allRelations, vm.query.order); | |
171 | + if (vm.query.search != null) { | |
172 | + result = $filter('filter')(result, {$: vm.query.search}); | |
173 | + } | |
174 | + vm.relationsCount = result.length; | |
175 | + var startIndex = vm.query.limit * (vm.query.page - 1); | |
176 | + vm.relations = result.slice(startIndex, startIndex + vm.query.limit); | |
177 | + } | |
178 | + | |
179 | +} | ... | ... |
1 | +/** | |
2 | + * Copyright © 2016-2017 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +@import '../../../scss/constants'; | |
17 | + | |
18 | +$md-light: rgba(255, 255, 255, 100%); | |
19 | + | |
20 | +.tb-relation-table { | |
21 | + md-toolbar.md-table-toolbar.alternate { | |
22 | + .md-toolbar-tools { | |
23 | + md-icon { | |
24 | + color: $md-light; | |
25 | + } | |
26 | + } | |
27 | + } | |
28 | +} | ... | ... |
1 | +<!-- | |
2 | + | |
3 | + Copyright © 2016-2017 The Thingsboard Authors | |
4 | + | |
5 | + Licensed under the Apache License, Version 2.0 (the "License"); | |
6 | + you may not use this file except in compliance with the License. | |
7 | + You may obtain a copy of the License at | |
8 | + | |
9 | + http://www.apache.org/licenses/LICENSE-2.0 | |
10 | + | |
11 | + Unless required by applicable law or agreed to in writing, software | |
12 | + distributed under the License is distributed on an "AS IS" BASIS, | |
13 | + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
14 | + See the License for the specific language governing permissions and | |
15 | + limitations under the License. | |
16 | + | |
17 | +--> | |
18 | +<md-content flex class="md-padding tb-absolute-fill tb-relation-table tb-data-table" layout="column"> | |
19 | + <div layout="column" class="md-whiteframe-z1"> | |
20 | + <md-toolbar class="md-table-toolbar md-default" ng-show="!vm.selectedRelations.length | |
21 | + && vm.query.search === null"> | |
22 | + <div class="md-toolbar-tools"> | |
23 | + <span translate>relation.entity-relations</span> | |
24 | + <span flex></span> | |
25 | + <md-button class="md-icon-button" ng-click="vm.addRelation($event)"> | |
26 | + <md-icon>add</md-icon> | |
27 | + <md-tooltip md-direction="top"> | |
28 | + {{ 'action.add' | translate }} | |
29 | + </md-tooltip> | |
30 | + </md-button> | |
31 | + <md-button class="md-icon-button" ng-click="vm.enterFilterMode()"> | |
32 | + <md-icon>search</md-icon> | |
33 | + <md-tooltip md-direction="top"> | |
34 | + {{ 'action.search' | translate }} | |
35 | + </md-tooltip> | |
36 | + </md-button> | |
37 | + <md-button class="md-icon-button" ng-click="vm.reloadRelations()"> | |
38 | + <md-icon>refresh</md-icon> | |
39 | + <md-tooltip md-direction="top"> | |
40 | + {{ 'action.refresh' | translate }} | |
41 | + </md-tooltip> | |
42 | + </md-button> | |
43 | + </div> | |
44 | + </md-toolbar> | |
45 | + <md-toolbar class="md-table-toolbar md-default" ng-show="!vm.selectedRelations.length | |
46 | + && vm.query.search != null"> | |
47 | + <div class="md-toolbar-tools"> | |
48 | + <md-button class="md-icon-button" aria-label="{{ 'action.search' | translate }}"> | |
49 | + <md-icon aria-label="{{ 'action.search' | translate }}" class="material-icons">search</md-icon> | |
50 | + <md-tooltip md-direction="top"> | |
51 | + {{ 'action.search' | translate }} | |
52 | + </md-tooltip> | |
53 | + </md-button> | |
54 | + <md-input-container flex> | |
55 | + <label> </label> | |
56 | + <input ng-model="vm.query.search" placeholder="{{ 'common.enter-search' | translate }}"/> | |
57 | + </md-input-container> | |
58 | + <md-button class="md-icon-button" aria-label="{{ 'action.back' | translate }}" ng-click="vm.exitFilterMode()"> | |
59 | + <md-icon aria-label="{{ 'action.close' | translate }}" class="material-icons">close</md-icon> | |
60 | + <md-tooltip md-direction="top"> | |
61 | + {{ 'action.close' | translate }} | |
62 | + </md-tooltip> | |
63 | + </md-button> | |
64 | + </div> | |
65 | + </md-toolbar> | |
66 | + <md-toolbar class="md-table-toolbar alternate" ng-show="vm.selectedRelations.length"> | |
67 | + <div class="md-toolbar-tools"> | |
68 | + <span translate | |
69 | + translate-values="{count: selectedRelations.length}" | |
70 | + translate-interpolation="messageformat">relation.selected-relations</span> | |
71 | + <span flex></span> | |
72 | + <md-button class="md-icon-button" ng-click="vm.deleteRelations($event)"> | |
73 | + <md-icon>delete</md-icon> | |
74 | + <md-tooltip md-direction="top"> | |
75 | + {{ 'action.delete' | translate }} | |
76 | + </md-tooltip> | |
77 | + </md-button> | |
78 | + </div> | |
79 | + </md-toolbar> | |
80 | + <md-table-container> | |
81 | + <table md-table md-row-select multiple="" ng-model="vm.selectedRelations" md-progress="vm.relationsDeferred.promise"> | |
82 | + <thead md-head md-order="vm.query.order" md-on-reorder="vm.onReorder"> | |
83 | + <tr md-row> | |
84 | + <th md-column md-order-by="typeName"><span translate>relation.type</span></th> | |
85 | + <th md-column md-order-by="toEntityTypeName"><span translate>relation.to-entity-type</span></th> | |
86 | + <th md-column md-order-by="toName"><span translate>relation.to-entity-name</span></th> | |
87 | + <th md-column><span> </span></th> | |
88 | + </tr> | |
89 | + </thead> | |
90 | + <tbody md-body> | |
91 | + <tr md-row md-select="relation" md-select-id="relation" md-auto-select ng-repeat="relation in vm.relations"> | |
92 | + <td md-cell>{{ relation.typeName }}</td> | |
93 | + <td md-cell>{{ relation.toEntityTypeName }}</td> | |
94 | + <td md-cell>{{ relation.toName }}</td> | |
95 | + <td md-cell class="tb-action-cell"> | |
96 | + <md-button class="md-icon-button" aria-label="{{ 'action.edit' | translate }}" | |
97 | + ng-click="vm.editRelation($event, relation)"> | |
98 | + <md-icon aria-label="{{ 'action.edit' | translate }}" class="material-icons">edit</md-icon> | |
99 | + <md-tooltip md-direction="top"> | |
100 | + {{ 'relation.edit' | translate }} | |
101 | + </md-tooltip> | |
102 | + </md-button> | |
103 | + <md-button class="md-icon-button" aria-label="{{ 'action.delete' | translate }}" ng-click="vm.deleteRelation($event, relation)"> | |
104 | + <md-icon aria-label="{{ 'action.delete' | translate }}" class="material-icons">delete</md-icon> | |
105 | + <md-tooltip md-direction="top"> | |
106 | + {{ 'relation.delete' | translate }} | |
107 | + </md-tooltip> | |
108 | + </md-button> | |
109 | + </td> | |
110 | + </tr> | |
111 | + </tbody> | |
112 | + </table> | |
113 | + </md-table-container> | |
114 | + <md-table-pagination md-limit="vm.query.limit" md-limit-options="[5, 10, 15]" | |
115 | + md-page="vm.query.page" md-total="{{vm.relationsCount}}" | |
116 | + md-on-paginate="onPaginate" md-page-select> | |
117 | + </md-table-pagination> | |
118 | + </div> | |
119 | +</md-content> | ... | ... |
... | ... | @@ -235,7 +235,7 @@ |
235 | 235 | "socialshare-text": "'{{dashboardTitle}}' powered by ThingsBoard", |
236 | 236 | "socialshare-title": "'{{dashboardTitle}}' powered by ThingsBoard", |
237 | 237 | "select-dashboard": "Seleccionar panel", |
238 | - "no-dashboards-matching": "Panel '{{dashboard}}' no encontrado.", | |
238 | + "no-dashboards-matching": "Panel '{{entity}}' no encontrado.", | |
239 | 239 | "dashboard-required": "Panel requerido.", |
240 | 240 | "select-existing": "Seleccionar paneles existentes", |
241 | 241 | "create-new": "Crear nuevo panel", |
... | ... | @@ -330,7 +330,7 @@ |
330 | 330 | "create-new-key": "Crear nueva clave!", |
331 | 331 | "duplicate-alias-error": "Alias duplicado '{{alias}}'.<br> El alias de los dispositivos deben ser únicos dentro del panel.", |
332 | 332 | "configure-alias": "Configurar alias '{{alias}}'", |
333 | - "no-devices-matching": "No se encontró dispositivo '{{device}}'", | |
333 | + "no-devices-matching": "No se encontró dispositivo '{{entity}}'", | |
334 | 334 | "alias": "Alias", |
335 | 335 | "alias-required": "Alias de dispositivo requerido.", |
336 | 336 | "remove-alias": "Eliminar alias", |
... | ... | @@ -529,7 +529,7 @@ |
529 | 529 | "system": "Sistema", |
530 | 530 | "select-plugin": "plugin", |
531 | 531 | "plugin": "Plugin", |
532 | - "no-plugins-matching": "No se encontraron plugins: '{{plugin}}'", | |
532 | + "no-plugins-matching": "No se encontraron plugins: '{{entity}}'", | |
533 | 533 | "plugin-required": "Plugin requerido.", |
534 | 534 | "plugin-require-match": "Por favor, elija un plugin existente.", |
535 | 535 | "events": "Eventos", | ... | ... |
... | ... | @@ -218,7 +218,7 @@ export default function addLocaleKorean(locales) { |
218 | 218 | "unassign-dashboards-title": "{ count, select, 1 {대시보드 1개} other {대시보드 #개} }의 할당을 취소하시겠습니까?", |
219 | 219 | "unassign-dashboards-text": "선택된 대시보드가 할당 해제되고 커스터머는 액세스 할 수 없게됩니다.", |
220 | 220 | "select-dashboard": "대시보드 선택", |
221 | - "no-dashboards-matching": "'{{dashboard}}'와 일치하는 대시보드가 없습니다.", | |
221 | + "no-dashboards-matching": "'{{entity}}'와 일치하는 대시보드가 없습니다.", | |
222 | 222 | "dashboard-required": "대시보드를 입력하세요.", |
223 | 223 | "select-existing": "기존 대시보드 선택", |
224 | 224 | "create-new": "대시보드 생성", |
... | ... | @@ -305,7 +305,7 @@ export default function addLocaleKorean(locales) { |
305 | 305 | "create-new-key": "새로 만들기!", |
306 | 306 | "duplicate-alias-error": "중복된 '{{alias}}' 앨리어스가 있습니다.<br> 디바이스 앨리어스는 대시보드 내에서 고유해야 합니다.", |
307 | 307 | "configure-alias": "'{{alias}}' 앨리어스 구성", |
308 | - "no-devices-matching": "'{{device}}'와 일치하는 디바이스를 찾을 수 없습니다.", | |
308 | + "no-devices-matching": "'{{entity}}'와 일치하는 디바이스를 찾을 수 없습니다.", | |
309 | 309 | "alias": "앨리어스", |
310 | 310 | "alias-required": "디바이스 앨리어스를 입력하세요.", |
311 | 311 | "remove-alias": "디바이스 앨리어스 삭제", |
... | ... | @@ -496,7 +496,7 @@ export default function addLocaleKorean(locales) { |
496 | 496 | "system": "시스템", |
497 | 497 | "select-plugin": "플러그인 선택", |
498 | 498 | "plugin": "플러그인", |
499 | - "no-plugins-matching": "'{{plugin}}'과 일치하는 플러그인을 찾을 수 없습니다.", | |
499 | + "no-plugins-matching": "'{{entity}}'과 일치하는 플러그인을 찾을 수 없습니다.", | |
500 | 500 | "plugin-required": "플러그인을 입력하세요.", |
501 | 501 | "plugin-require-match": "기존의 플러그인을 선택해주세요.", |
502 | 502 | "events": "이벤트", | ... | ... |
... | ... | @@ -235,7 +235,7 @@ export default function addLocaleRussian(locales) { |
235 | 235 | "socialshare-text": "'{{dashboardTitle}}' сделано ThingsBoard", |
236 | 236 | "socialshare-title": "'{{dashboardTitle}}' сделано ThingsBoard", |
237 | 237 | "select-dashboard": "Выберите дашборд", |
238 | - "no-dashboards-matching": "Дашборд '{{dashboard}}' не найден.", | |
238 | + "no-dashboards-matching": "Дашборд '{{entity}}' не найден.", | |
239 | 239 | "dashboard-required": "Дашборд обязателен.", |
240 | 240 | "select-existing": "Выберите существующий дашборд", |
241 | 241 | "create-new": "Создать новый дашборд", |
... | ... | @@ -330,7 +330,7 @@ export default function addLocaleRussian(locales) { |
330 | 330 | "create-new-key": "Создать новый!", |
331 | 331 | "duplicate-alias-error": "Найден дублирующийся псевдоним '{{alias}}'.<br>В рамках дашборда псевдонимы устройств должны быть уникальными.", |
332 | 332 | "configure-alias": "Конфигурировать '{{alias}}' псевдоним", |
333 | - "no-devices-matching": "Устройство '{{device}}' не найдено.", | |
333 | + "no-devices-matching": "Устройство '{{entity}}' не найдено.", | |
334 | 334 | "alias": "Псевдоним", |
335 | 335 | "alias-required": "Псевдоним устройства обязателен.", |
336 | 336 | "remove-alias": "Удалить псевдоним устройства", |
... | ... | @@ -529,7 +529,7 @@ export default function addLocaleRussian(locales) { |
529 | 529 | "system": "Системный", |
530 | 530 | "select-plugin": "Выберите плагин", |
531 | 531 | "plugin": "Плагин", |
532 | - "no-plugins-matching": "Плагин '{{plugin}}' не найден.", | |
532 | + "no-plugins-matching": "Плагин '{{entity}}' не найден.", | |
533 | 533 | "plugin-required": "Плагин обязателен.", |
534 | 534 | "plugin-require-match": "Пожалуйста, выберите существующий плагин.", |
535 | 535 | "events": "События", | ... | ... |
... | ... | @@ -235,7 +235,7 @@ export default function addLocaleChinese(locales) { |
235 | 235 | "socialshare-text" : "'{{dashboardTitle}}' 由ThingsBoard提供支持", |
236 | 236 | "socialshare-title" : "'{{dashboardTitle}}' 由ThingsBoard提供支持", |
237 | 237 | "select-dashboard" : "选择仪表板", |
238 | - "no-dashboards-matching" : "找不到符合 '{{dashboard}}' 的仪表板。", | |
238 | + "no-dashboards-matching" : "找不到符合 '{{entity}}' 的仪表板。", | |
239 | 239 | "dashboard-required" : "仪表板是必需的。", |
240 | 240 | "select-existing" : "选择现有仪表板", |
241 | 241 | "create-new" : "创建新的仪表板", |
... | ... | @@ -330,7 +330,7 @@ export default function addLocaleChinese(locales) { |
330 | 330 | "create-new-key": "创建一个新的!", |
331 | 331 | "duplicate-alias-error" : "找到重复别名 '{{alias}}'。 <br> 设备别名必须是唯一的。", |
332 | 332 | "configure-alias" : "配置 '{{alias}}' 别名", |
333 | - "no-devices-matching" : "找不到与 '{{device}}' 匹配的设备。", | |
333 | + "no-devices-matching" : "找不到与 '{{entity}}' 匹配的设备。", | |
334 | 334 | "alias" : "别名", |
335 | 335 | "alias-required" : "需要设备别名。", |
336 | 336 | "remove-alias": "删除设备别名", |
... | ... | @@ -529,7 +529,7 @@ export default function addLocaleChinese(locales) { |
529 | 529 | "system" : "系统", |
530 | 530 | "select-plugin" : "选择插件", |
531 | 531 | "plugin" : "插件", |
532 | - "no-plugins-matching" : "没有找到匹配'{{plugin}}'的插件。", | |
532 | + "no-plugins-matching" : "没有找到匹配'{{entity}}'的插件。", | |
533 | 533 | "plugin-required" : "插件是必需的。", |
534 | 534 | "plugin-require-match" : "请选择一个现有的插件。", |
535 | 535 | "events" : "事件", | ... | ... |
... | ... | @@ -106,6 +106,12 @@ export default angular.module('thingsboard.locale', []) |
106 | 106 | "enable-tls": "Enable TLS", |
107 | 107 | "send-test-mail": "Send test mail" |
108 | 108 | }, |
109 | + "alarm": { | |
110 | + "alarm": "Alarm", | |
111 | + "select-alarm": "Select alarm", | |
112 | + "no-alarms-matching": "No alarms matching '{{entity}}' were found.", | |
113 | + "alarm-required": "Alarm is required" | |
114 | + }, | |
109 | 115 | "asset": { |
110 | 116 | "asset": "Asset", |
111 | 117 | "assets": "Assets", |
... | ... | @@ -157,7 +163,10 @@ export default angular.module('thingsboard.locale', []) |
157 | 163 | "unassign-assets-title": "Are you sure you want to unassign { count, select, 1 {1 asset} other {# assets} }?", |
158 | 164 | "unassign-assets-text": "After the confirmation all selected assets will be unassigned and won't be accessible by the customer.", |
159 | 165 | "copyId": "Copy asset Id", |
160 | - "idCopiedMessage": "Asset Id has been copied to clipboard" | |
166 | + "idCopiedMessage": "Asset Id has been copied to clipboard", | |
167 | + "select-asset": "Select asset", | |
168 | + "no-assets-matching": "No assets matching '{{entity}}' were found.", | |
169 | + "asset-required": "Asset is required" | |
161 | 170 | }, |
162 | 171 | "attribute": { |
163 | 172 | "attributes": "Attributes", |
... | ... | @@ -169,6 +178,7 @@ export default angular.module('thingsboard.locale', []) |
169 | 178 | "scope-shared": "Shared attributes", |
170 | 179 | "add": "Add attribute", |
171 | 180 | "key": "Key", |
181 | + "last-update-time": "Last update time", | |
172 | 182 | "key-required": "Attribute key is required.", |
173 | 183 | "value": "Value", |
174 | 184 | "value-required": "Attribute value is required.", |
... | ... | @@ -210,6 +220,7 @@ export default angular.module('thingsboard.locale', []) |
210 | 220 | "enter-search": "Enter search" |
211 | 221 | }, |
212 | 222 | "customer": { |
223 | + "customer": "Customer", | |
213 | 224 | "customers": "Customers", |
214 | 225 | "management": "Customer management", |
215 | 226 | "dashboard": "Customer Dashboard", |
... | ... | @@ -246,7 +257,10 @@ export default angular.module('thingsboard.locale', []) |
246 | 257 | "details": "Details", |
247 | 258 | "events": "Events", |
248 | 259 | "copyId": "Copy customer Id", |
249 | - "idCopiedMessage": "Customer Id has been copied to clipboard" | |
260 | + "idCopiedMessage": "Customer Id has been copied to clipboard", | |
261 | + "select-customer": "Select customer", | |
262 | + "no-customers-matching": "No customers matching '{{entity}}' were found.", | |
263 | + "customer-required": "Customer is required" | |
250 | 264 | }, |
251 | 265 | "datetime": { |
252 | 266 | "date-from": "Date from", |
... | ... | @@ -304,7 +318,7 @@ export default angular.module('thingsboard.locale', []) |
304 | 318 | "socialshare-text": "'{{dashboardTitle}}' powered by ThingsBoard", |
305 | 319 | "socialshare-title": "'{{dashboardTitle}}' powered by ThingsBoard", |
306 | 320 | "select-dashboard": "Select dashboard", |
307 | - "no-dashboards-matching": "No dashboards matching '{{dashboard}}' were found.", | |
321 | + "no-dashboards-matching": "No dashboards matching '{{entity}}' were found.", | |
308 | 322 | "dashboard-required": "Dashboard is required.", |
309 | 323 | "select-existing": "Select existing dashboard", |
310 | 324 | "create-new": "Create new dashboard", |
... | ... | @@ -425,7 +439,7 @@ export default angular.module('thingsboard.locale', []) |
425 | 439 | "create-new-key": "Create a new one!", |
426 | 440 | "duplicate-alias-error": "Duplicate alias found '{{alias}}'.<br>Device aliases must be unique whithin the dashboard.", |
427 | 441 | "configure-alias": "Configure '{{alias}}' alias", |
428 | - "no-devices-matching": "No devices matching '{{device}}' were found.", | |
442 | + "no-devices-matching": "No devices matching '{{entity}}' were found.", | |
429 | 443 | "alias": "Alias", |
430 | 444 | "alias-required": "Device alias is required.", |
431 | 445 | "remove-alias": "Remove device alias", |
... | ... | @@ -497,7 +511,8 @@ export default angular.module('thingsboard.locale', []) |
497 | 511 | "unable-delete-device-alias-text": "Device alias '{{deviceAlias}}' can't be deleted as it used by the following widget(s):<br/>{{widgetsList}}", |
498 | 512 | "is-gateway": "Is gateway", |
499 | 513 | "public": "Public", |
500 | - "device-public": "Device is public" | |
514 | + "device-public": "Device is public", | |
515 | + "select-device": "Select device" | |
501 | 516 | }, |
502 | 517 | "dialog": { |
503 | 518 | "close": "Close dialog" |
... | ... | @@ -535,6 +550,9 @@ export default angular.module('thingsboard.locale', []) |
535 | 550 | "type-plugin": "Plugin", |
536 | 551 | "type-tenant": "Tenant", |
537 | 552 | "type-customer": "Customer", |
553 | + "type-user": "User", | |
554 | + "type-dashboard": "Dashboard", | |
555 | + "type-alarm": "Alarm", | |
538 | 556 | "select-entities": "Select entities", |
539 | 557 | "no-aliases-found": "No aliases found.", |
540 | 558 | "no-alias-matching": "'{{alias}}' not found.", |
... | ... | @@ -672,7 +690,7 @@ export default angular.module('thingsboard.locale', []) |
672 | 690 | "system": "System", |
673 | 691 | "select-plugin": "Select plugin", |
674 | 692 | "plugin": "Plugin", |
675 | - "no-plugins-matching": "No plugins matching '{{plugin}}' were found.", | |
693 | + "no-plugins-matching": "No plugins matching '{{entity}}' were found.", | |
676 | 694 | "plugin-required": "Plugin is required.", |
677 | 695 | "plugin-require-match": "Please select an existing plugin.", |
678 | 696 | "events": "Events", |
... | ... | @@ -685,6 +703,7 @@ export default angular.module('thingsboard.locale', []) |
685 | 703 | "invalid-plugin-file-error": "Unable to import plugin: Invalid plugin data structure.", |
686 | 704 | "copyId": "Copy plugin Id", |
687 | 705 | "idCopiedMessage": "Plugin Id has been copied to clipboard" |
706 | + | |
688 | 707 | }, |
689 | 708 | "position": { |
690 | 709 | "top": "Top", |
... | ... | @@ -697,7 +716,24 @@ export default angular.module('thingsboard.locale', []) |
697 | 716 | "change-password": "Change Password", |
698 | 717 | "current-password": "Current password" |
699 | 718 | }, |
719 | + "relation": { | |
720 | + "relations": "Relations", | |
721 | + "entity-relations": "Entity relations", | |
722 | + "selected-relations": "{ count, select, 1 {1 relation} other {# relations} } selected", | |
723 | + "type": "Type", | |
724 | + "to-entity-type": "Entity type", | |
725 | + "to-entity-name": "Entity name", | |
726 | + "edit": "Edit relation", | |
727 | + "delete": "Delete relation", | |
728 | + "relation-type": "Relation type", | |
729 | + "relation-types": { | |
730 | + "Contains": "Contains", | |
731 | + "Manages": "Manages" | |
732 | + }, | |
733 | + "add": "Add relation" | |
734 | + }, | |
700 | 735 | "rule": { |
736 | + "rule": "Rule", | |
701 | 737 | "rules": "Rules", |
702 | 738 | "delete": "Delete rule", |
703 | 739 | "activate": "Activate rule", |
... | ... | @@ -749,12 +785,16 @@ export default angular.module('thingsboard.locale', []) |
749 | 785 | "rule-file": "Rule file", |
750 | 786 | "invalid-rule-file-error": "Unable to import rule: Invalid rule data structure.", |
751 | 787 | "copyId": "Copy rule Id", |
752 | - "idCopiedMessage": "Rule Id has been copied to clipboard" | |
788 | + "idCopiedMessage": "Rule Id has been copied to clipboard", | |
789 | + "select-rule": "Select rule", | |
790 | + "no-rules-matching": "No rules matching '{{entity}}' were found.", | |
791 | + "rule-required": "Rule is required" | |
753 | 792 | }, |
754 | 793 | "rule-plugin": { |
755 | 794 | "management": "Rules and plugins management" |
756 | 795 | }, |
757 | 796 | "tenant": { |
797 | + "tenant": "Tenant", | |
758 | 798 | "tenants": "Tenants", |
759 | 799 | "management": "Tenant management", |
760 | 800 | "add": "Add Tenant", |
... | ... | @@ -775,7 +815,10 @@ export default angular.module('thingsboard.locale', []) |
775 | 815 | "details": "Details", |
776 | 816 | "events": "Events", |
777 | 817 | "copyId": "Copy tenant Id", |
778 | - "idCopiedMessage": "Tenant Id has been copied to clipboard" | |
818 | + "idCopiedMessage": "Tenant Id has been copied to clipboard", | |
819 | + "select-tenant": "Select tenant", | |
820 | + "no-tenants-matching": "No tenants matching '{{entity}}' were found.", | |
821 | + "tenant-required": "Tenant is required" | |
779 | 822 | }, |
780 | 823 | "timeinterval": { |
781 | 824 | "seconds-interval": "{ seconds, select, 1 {1 second} other {# seconds} }", |
... | ... | @@ -803,6 +846,7 @@ export default angular.module('thingsboard.locale', []) |
803 | 846 | "time-period": "Time period" |
804 | 847 | }, |
805 | 848 | "user": { |
849 | + "user": "User", | |
806 | 850 | "users": "Users", |
807 | 851 | "customer-users": "Customer Users", |
808 | 852 | "tenant-admins": "Tenant Admins", |
... | ... | @@ -828,7 +872,10 @@ export default angular.module('thingsboard.locale', []) |
828 | 872 | "last-name": "Last Name", |
829 | 873 | "description": "Description", |
830 | 874 | "default-dashboard": "Default dashboard", |
831 | - "always-fullscreen": "Always fullscreen" | |
875 | + "always-fullscreen": "Always fullscreen", | |
876 | + "select-user": "Select user", | |
877 | + "no-users-matching": "No users matching '{{entity}}' were found.", | |
878 | + "user-required": "User is required" | |
832 | 879 | }, |
833 | 880 | "value": { |
834 | 881 | "type": "Value type", | ... | ... |
... | ... | @@ -261,6 +261,45 @@ pre.tb-highlight { |
261 | 261 | font-size: 16px; |
262 | 262 | } |
263 | 263 | |
264 | +.tb-data-table { | |
265 | + md-toolbar { | |
266 | + z-index: 0; | |
267 | + } | |
268 | + span.no-data-found { | |
269 | + position: relative; | |
270 | + height: calc(100% - 57px); | |
271 | + text-transform: uppercase; | |
272 | + display: flex; | |
273 | + } | |
274 | + table.md-table { | |
275 | + tbody { | |
276 | + tr { | |
277 | + td { | |
278 | + &.tb-action-cell { | |
279 | + overflow: hidden; | |
280 | + text-overflow: ellipsis; | |
281 | + white-space: nowrap; | |
282 | + min-width: 72px; | |
283 | + max-width: 72px; | |
284 | + width: 72px; | |
285 | + .md-button { | |
286 | + &.md-icon-button { | |
287 | + margin: 0; | |
288 | + padding: 6px; | |
289 | + width: 36px; | |
290 | + height: 36px; | |
291 | + } | |
292 | + } | |
293 | + .tb-spacer { | |
294 | + padding-left: 38px; | |
295 | + } | |
296 | + } | |
297 | + } | |
298 | + } | |
299 | + } | |
300 | + } | |
301 | +} | |
302 | + | |
264 | 303 | |
265 | 304 | /*********************** |
266 | 305 | * Flow | ... | ... |