Showing
89 changed files
with
2288 additions
and
307 deletions
... | ... | @@ -343,7 +343,7 @@ public abstract class BaseController { |
343 | 343 | Alarm checkAlarmId(AlarmId alarmId) throws ThingsboardException { |
344 | 344 | try { |
345 | 345 | validateId(alarmId, "Incorrect alarmId " + alarmId); |
346 | - Alarm alarm = alarmService.findAlarmById(alarmId).get(); | |
346 | + Alarm alarm = alarmService.findAlarmByIdAsync(alarmId).get(); | |
347 | 347 | checkAlarm(alarm); |
348 | 348 | return alarm; |
349 | 349 | } catch (Exception e) { | ... | ... |
... | ... | @@ -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 | ... | ... |
... | ... | @@ -19,12 +19,18 @@ server: |
19 | 19 | address: "${HTTP_BIND_ADDRESS:0.0.0.0}" |
20 | 20 | # Server bind port |
21 | 21 | port: "${HTTP_BIND_PORT:8080}" |
22 | -# Uncomment the following section to enable ssl | |
23 | -# ssl: | |
24 | -# key-store: classpath:keystore/keystore.p12 | |
25 | -# key-store-password: thingsboard | |
26 | -# keyStoreType: PKCS12 | |
27 | -# keyAlias: tomcat | |
22 | + # Server SSL configuration | |
23 | + ssl: | |
24 | + # Enable/disable SSL support | |
25 | + enabled: "${SSL_ENABLED:false}" | |
26 | + # Path to the key store that holds the SSL certificate | |
27 | + key-store: "${SSL_KEY_STORE:classpath:keystore/keystore.p12}" | |
28 | + # Password used to access the key store | |
29 | + key-store-password: "${SSL_KEY_STORE_PASSWORD:thingsboard}" | |
30 | + # Type of the key store | |
31 | + key-store-type: "${SSL_KEY_STORE_TYPE:PKCS12}" | |
32 | + # Alias that identifies the key in the key store | |
33 | + key-alias: "${SSL_KEY_ALIAS:tomcat}" | |
28 | 34 | |
29 | 35 | # Zookeeper connection parameters. Used for service discovery. |
30 | 36 | zk: |
... | ... | @@ -79,12 +85,18 @@ mqtt: |
79 | 85 | leak_detector_level: "${NETTY_LEASK_DETECTOR_LVL:DISABLED}" |
80 | 86 | boss_group_thread_count: "${NETTY_BOSS_GROUP_THREADS:1}" |
81 | 87 | worker_group_thread_count: "${NETTY_WORKER_GROUP_THREADS:12}" |
82 | -# Uncomment the following lines to enable ssl for MQTT | |
83 | -# ssl: | |
84 | -# key_store: mqttserver.jks | |
85 | -# key_store_password: server_ks_password | |
86 | -# key_password: server_key_password | |
87 | -# key_store_type: JKS | |
88 | + # MQTT SSL configuration | |
89 | + ssl: | |
90 | + # Enable/disable SSL support | |
91 | + enabled: "${MQTT_SSL_ENABLED:false}" | |
92 | + # Path to the key store that holds the SSL certificate | |
93 | + key_store: "${MQTT_SSL_KEY_STORE:mqttserver.jks}" | |
94 | + # Password used to access the key store | |
95 | + key_store_password: "${MQTT_SSL_KEY_STORE_PASSWORD:server_ks_password}" | |
96 | + # Password used to access the key | |
97 | + key_password: "${MQTT_SSL_KEY_PASSWORD:server_key_password}" | |
98 | + # Type of the key store | |
99 | + key_store_type: "${MQTT_SSL_KEY_STORE_TYPE:JKS}" | |
88 | 100 | |
89 | 101 | # CoAP server parameters |
90 | 102 | coap: | ... | ... |
... | ... | @@ -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 | } | ... | ... |
... | ... | @@ -21,6 +21,7 @@ import lombok.Builder; |
21 | 21 | import lombok.Data; |
22 | 22 | import org.thingsboard.server.common.data.BaseData; |
23 | 23 | import org.thingsboard.server.common.data.id.AssetId; |
24 | +import org.thingsboard.server.common.data.HasName; | |
24 | 25 | import org.thingsboard.server.common.data.id.EntityId; |
25 | 26 | import org.thingsboard.server.common.data.id.TenantId; |
26 | 27 | |
... | ... | @@ -30,7 +31,7 @@ import org.thingsboard.server.common.data.id.TenantId; |
30 | 31 | @Data |
31 | 32 | @Builder |
32 | 33 | @AllArgsConstructor |
33 | -public class Alarm extends BaseData<AlarmId> { | |
34 | +public class Alarm extends BaseData<AlarmId> implements HasName { | |
34 | 35 | |
35 | 36 | private TenantId tenantId; |
36 | 37 | private String type; |
... | ... | @@ -52,4 +53,8 @@ public class Alarm extends BaseData<AlarmId> { |
52 | 53 | super(id); |
53 | 54 | } |
54 | 55 | |
56 | + @Override | |
57 | + public String getName() { | |
58 | + return type; | |
59 | + } | |
55 | 60 | } | ... | ... |
... | ... | @@ -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 | } | ... | ... |
... | ... | @@ -32,7 +32,7 @@ public interface AlarmService { |
32 | 32 | |
33 | 33 | ListenableFuture<Boolean> clearAlarm(AlarmId alarmId, long ackTs); |
34 | 34 | |
35 | - ListenableFuture<Alarm> findAlarmById(AlarmId alarmId); | |
35 | + ListenableFuture<Alarm> findAlarmByIdAsync(AlarmId alarmId); | |
36 | 36 | |
37 | 37 | ListenableFuture<TimePageData<Alarm>> findAlarms(AlarmQuery query); |
38 | 38 | ... | ... |
... | ... | @@ -30,6 +30,7 @@ import org.thingsboard.server.common.data.alarm.AlarmStatus; |
30 | 30 | import org.thingsboard.server.common.data.id.EntityId; |
31 | 31 | import org.thingsboard.server.common.data.page.TimePageData; |
32 | 32 | import org.thingsboard.server.common.data.relation.EntityRelation; |
33 | +import org.thingsboard.server.dao.entity.AbstractEntityService; | |
33 | 34 | import org.thingsboard.server.dao.entity.BaseEntityService; |
34 | 35 | import org.thingsboard.server.dao.exception.DataValidationException; |
35 | 36 | import org.thingsboard.server.dao.model.*; |
... | ... | @@ -54,7 +55,7 @@ import static org.thingsboard.server.dao.service.Validator.*; |
54 | 55 | |
55 | 56 | @Service |
56 | 57 | @Slf4j |
57 | -public class BaseAlarmService extends BaseEntityService implements AlarmService { | |
58 | +public class BaseAlarmService extends AbstractEntityService implements AlarmService { | |
58 | 59 | |
59 | 60 | public static final String ALARM_RELATION_PREFIX = "ALARM_"; |
60 | 61 | public static final String ALARM_RELATION = "ALARM_ANY"; |
... | ... | @@ -190,7 +191,7 @@ public class BaseAlarmService extends BaseEntityService implements AlarmService |
190 | 191 | } |
191 | 192 | |
192 | 193 | @Override |
193 | - public ListenableFuture<Alarm> findAlarmById(AlarmId alarmId) { | |
194 | + public ListenableFuture<Alarm> findAlarmByIdAsync(AlarmId alarmId) { | |
194 | 195 | log.trace("Executing findAlarmById [{}]", alarmId); |
195 | 196 | validateId(alarmId, "Incorrect alarmId " + alarmId); |
196 | 197 | return alarmDao.findAlarmByIdAsync(alarmId.getId()); | ... | ... |
... | ... | @@ -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); | ... | ... |
... | ... | @@ -95,7 +95,7 @@ public class AlarmServiceTest extends AbstractServiceTest { |
95 | 95 | Assert.assertEquals(0L, created.getAckTs()); |
96 | 96 | Assert.assertEquals(0L, created.getClearTs()); |
97 | 97 | |
98 | - Alarm fetched = alarmService.findAlarmById(created.getId()).get(); | |
98 | + Alarm fetched = alarmService.findAlarmByIdAsync(created.getId()).get(); | |
99 | 99 | Assert.assertEquals(created, fetched); |
100 | 100 | } |
101 | 101 | |
... | ... | @@ -137,7 +137,7 @@ public class AlarmServiceTest extends AbstractServiceTest { |
137 | 137 | Assert.assertEquals(created, alarms.getData().get(0)); |
138 | 138 | |
139 | 139 | alarmService.ackAlarm(created.getId(), System.currentTimeMillis()).get(); |
140 | - created = alarmService.findAlarmById(created.getId()).get(); | |
140 | + created = alarmService.findAlarmByIdAsync(created.getId()).get(); | |
141 | 141 | |
142 | 142 | alarms = alarmService.findAlarms(AlarmQuery.builder() |
143 | 143 | .affectedEntityId(childId) |
... | ... | @@ -158,7 +158,7 @@ public class AlarmServiceTest extends AbstractServiceTest { |
158 | 158 | Assert.assertEquals(0, alarms.getData().size()); |
159 | 159 | |
160 | 160 | alarmService.clearAlarm(created.getId(), System.currentTimeMillis()).get(); |
161 | - created = alarmService.findAlarmById(created.getId()).get(); | |
161 | + created = alarmService.findAlarmByIdAsync(created.getId()).get(); | |
162 | 162 | |
163 | 163 | alarms = alarmService.findAlarms(AlarmQuery.builder() |
164 | 164 | .affectedEntityId(childId) | ... | ... |
docker/cassandra/cassandra.yaml
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 | +apiVersion: v1 | |
18 | +kind: Service | |
19 | +metadata: | |
20 | + name: cassandra-headless | |
21 | + labels: | |
22 | + app: cassandra-headless | |
23 | +spec: | |
24 | + ports: | |
25 | + - port: 9042 | |
26 | + name: cql | |
27 | + clusterIP: None | |
28 | + selector: | |
29 | + app: cassandra | |
30 | +--- | |
31 | +apiVersion: "apps/v1beta1" | |
32 | +kind: StatefulSet | |
33 | +metadata: | |
34 | + name: cassandra | |
35 | +spec: | |
36 | + serviceName: cassandra-headless | |
37 | + replicas: 2 | |
38 | + template: | |
39 | + metadata: | |
40 | + labels: | |
41 | + app: cassandra | |
42 | + spec: | |
43 | + nodeSelector: | |
44 | + machinetype: other | |
45 | + affinity: | |
46 | + podAntiAffinity: | |
47 | + requiredDuringSchedulingIgnoredDuringExecution: | |
48 | + - labelSelector: | |
49 | + matchExpressions: | |
50 | + - key: "app" | |
51 | + operator: In | |
52 | + values: | |
53 | + - cassandra-headless | |
54 | + topologyKey: "kubernetes.io/hostname" | |
55 | + containers: | |
56 | + - name: cassandra | |
57 | + image: cassandra:3.9 | |
58 | + imagePullPolicy: Always | |
59 | + ports: | |
60 | + - containerPort: 7000 | |
61 | + name: intra-node | |
62 | + - containerPort: 7001 | |
63 | + name: tls-intra-node | |
64 | + - containerPort: 7199 | |
65 | + name: jmx | |
66 | + - containerPort: 9042 | |
67 | + name: cql | |
68 | + - containerPort: 9160 | |
69 | + name: thrift | |
70 | + securityContext: | |
71 | + capabilities: | |
72 | + add: | |
73 | + - IPC_LOCK | |
74 | + lifecycle: | |
75 | + preStop: | |
76 | + exec: | |
77 | + command: ["/bin/sh", "-c", "PID=$(pidof java) && kill $PID && while ps -p $PID > /dev/null; do sleep 1; done"] | |
78 | + env: | |
79 | + - name: MAX_HEAP_SIZE | |
80 | + value: 2048M | |
81 | + - name: HEAP_NEWSIZE | |
82 | + value: 100M | |
83 | + - name: CASSANDRA_SEEDS | |
84 | + value: "cassandra-0.cassandra-headless.default.svc.cluster.local" | |
85 | + - name: CASSANDRA_CLUSTER_NAME | |
86 | + value: "Thingsboard-Cluster" | |
87 | + - name: CASSANDRA_DC | |
88 | + value: "DC1-Thingsboard-Cluster" | |
89 | + - name: CASSANDRA_RACK | |
90 | + value: "Rack-Thingsboard-Cluster" | |
91 | + - name: CASSANDRA_AUTO_BOOTSTRAP | |
92 | + value: "false" | |
93 | + - name: POD_IP | |
94 | + valueFrom: | |
95 | + fieldRef: | |
96 | + fieldPath: status.podIP | |
97 | + - name: POD_NAMESPACE | |
98 | + valueFrom: | |
99 | + fieldRef: | |
100 | + fieldPath: metadata.namespace | |
101 | + readinessProbe: | |
102 | + exec: | |
103 | + command: | |
104 | + - /bin/bash | |
105 | + - -c | |
106 | + - /ready-probe.sh | |
107 | + initialDelaySeconds: 15 | |
108 | + timeoutSeconds: 5 | |
109 | + volumeMounts: | |
110 | + - name: cassandra-data | |
111 | + mountPath: /var/lib/cassandra/data | |
112 | + - name: cassandra-commitlog | |
113 | + mountPath: /var/lib/cassandra/commitlog | |
114 | + volumeClaimTemplates: | |
115 | + - metadata: | |
116 | + name: cassandra-data | |
117 | + annotations: | |
118 | + volume.beta.kubernetes.io/storage-class: fast | |
119 | + spec: | |
120 | + accessModes: [ "ReadWriteOnce" ] | |
121 | + resources: | |
122 | + requests: | |
123 | + storage: 3Gi | |
124 | + - metadata: | |
125 | + name: cassandra-commitlog | |
126 | + annotations: | |
127 | + volume.beta.kubernetes.io/storage-class: fast | |
128 | + spec: | |
129 | + accessModes: [ "ReadWriteOnce" ] | |
130 | + resources: | |
131 | + requests: | |
132 | + storage: 2Gi | |
\ No newline at end of file | ... | ... |
docker/common/common.yaml
renamed from
docker/docker-compose.random.yml
... | ... | @@ -14,13 +14,20 @@ |
14 | 14 | # limitations under the License. |
15 | 15 | # |
16 | 16 | |
17 | -version: '2' | |
18 | - | |
19 | -services: | |
20 | - db: | |
21 | - ports: | |
22 | - - "9042" | |
23 | - - "9160" | |
24 | - zk: | |
25 | - ports: | |
26 | - - "2181" | |
17 | +--- | |
18 | +apiVersion: storage.k8s.io/v1beta1 | |
19 | +kind: StorageClass | |
20 | +metadata: | |
21 | + name: slow | |
22 | +provisioner: kubernetes.io/gce-pd | |
23 | +parameters: | |
24 | + type: pd-standard | |
25 | +--- | |
26 | +apiVersion: storage.k8s.io/v1beta1 | |
27 | +kind: StorageClass | |
28 | +metadata: | |
29 | + name: fast | |
30 | +provisioner: kubernetes.io/gce-pd | |
31 | +parameters: | |
32 | + type: pd-ssd | |
33 | +--- | |
\ No newline at end of file | ... | ... |
docker/deploy.sh
deleted
100755 → 0
1 | -#!/bin/bash | |
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 | - | |
19 | -command='docker-compose -f docker-compose.yml -f docker-compose.random.yml' | |
20 | - | |
21 | -echo "stopping images.." | |
22 | -$command stop | |
23 | - | |
24 | -echo "removing stopped images.." | |
25 | -$command rm -f | |
26 | - | |
27 | -echo "building images.." | |
28 | -$command build | |
29 | - | |
30 | -echo "starting images..." | |
31 | -$command up -d |
docker/deploy_cassandra_zookeeper.sh
deleted
100755 → 0
1 | -#!/bin/bash | |
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 | - | |
19 | -command='docker-compose -f docker-compose.yml -f docker-compose.static.yml' | |
20 | - | |
21 | -echo "stopping images.." | |
22 | -$command stop | |
23 | - | |
24 | -echo "removing stopped images.." | |
25 | -$command rm -f | |
26 | - | |
27 | -echo "building images.." | |
28 | -$command build | |
29 | - | |
30 | -echo "starting cassandra, zookeeper, thingsboard-db-schema images..." | |
31 | -$command up -d db zk thingsboard-db-schema |
... | ... | @@ -17,24 +17,32 @@ |
17 | 17 | version: '2' |
18 | 18 | |
19 | 19 | services: |
20 | - thingsboard: | |
21 | - image: "thingsboard/application:1.2.3" | |
20 | + tb: | |
21 | + image: "thingsboard/application:1.2.4" | |
22 | 22 | ports: |
23 | 23 | - "8080:8080" |
24 | 24 | - "1883:1883" |
25 | 25 | - "5683:5683/udp" |
26 | 26 | env_file: |
27 | - - thingsboard.env | |
28 | - entrypoint: ./run_thingsboard.sh | |
29 | - thingsboard-db-schema: | |
30 | - image: "thingsboard/thingsboard-db-schema:1.2.3" | |
31 | - env_file: | |
32 | - - thingsboard-db-schema.env | |
33 | - entrypoint: ./install_schema.sh | |
34 | - db: | |
27 | + - tb.env | |
28 | + entrypoint: ./run-application.sh | |
29 | + tb-cassandra-schema: | |
30 | + image: "thingsboard/tb-cassandra-schema:1.2.4" | |
31 | + environment: | |
32 | + - CREATE_SCHEMA=${CREATE_SCHEMA} | |
33 | + - ADD_SYSTEM_DATA=${ADD_SYSTEM_DATA} | |
34 | + - ADD_DEMO_DATA=${ADD_DEMO_DATA} | |
35 | + - CASSANDRA_URL=${CASSANDRA_URL} | |
36 | + entrypoint: ./install-schema.sh | |
37 | + cassandra: | |
35 | 38 | image: "cassandra:3.9" |
39 | + ports: | |
40 | + - "9042" | |
41 | + - "9160" | |
36 | 42 | volumes: |
37 | 43 | - "${CASSANDRA_DATA_DIR}:/var/lib/cassandra" |
38 | 44 | zk: |
39 | 45 | image: "zookeeper:3.4.9" |
46 | + ports: | |
47 | + - "2181" | |
40 | 48 | restart: always | ... | ... |
docker/tb-cassandra-schema/Dockerfile
renamed from
docker/thingsboard-db-schema/Dockerfile
... | ... | @@ -16,12 +16,12 @@ |
16 | 16 | |
17 | 17 | FROM cassandra:3.9 |
18 | 18 | |
19 | -ADD install_schema.sh /root/install_schema.sh | |
19 | +ADD install-schema.sh /root/install-schema.sh | |
20 | 20 | |
21 | 21 | RUN apt-get update \ |
22 | 22 | && apt-get install -y nmap |
23 | 23 | |
24 | -RUN chmod +x /root/install_schema.sh | |
24 | +RUN chmod +x /root/install-schema.sh | |
25 | 25 | |
26 | 26 | ADD schema.cql /root/schema.cql |
27 | 27 | ADD demo-data.cql /root/demo-data.cql | ... | ... |
docker/tb-cassandra-schema/Makefile
0 → 100644
1 | +VERSION=1.2.4 | |
2 | +PROJECT=thingsboard | |
3 | +APP=tb-cassandra-schema | |
4 | + | |
5 | +build: | |
6 | + cp ../../dao/src/main/resources/schema.cql . | |
7 | + cp ../../dao/src/main/resources/demo-data.cql . | |
8 | + cp ../../dao/src/main/resources/system-data.cql . | |
9 | + docker build --pull -t ${PROJECT}/${APP}:${VERSION} . | |
10 | + rm schema.cql demo-data.cql system-data.cql | |
11 | + | |
12 | +push: build | |
13 | + docker push ${PROJECT}/${APP}:${VERSION} | |
\ No newline at end of file | ... | ... |
docker/tb-cassandra-schema/install-schema.sh
renamed from
docker/thingsboard-db-schema/install_schema.sh
... | ... | @@ -16,15 +16,15 @@ |
16 | 16 | # |
17 | 17 | |
18 | 18 | |
19 | -until nmap db -p 9042 | grep "9042/tcp open" | |
19 | +until nmap $CASSANDRA_URL -p 9042 | grep "9042/tcp open" | |
20 | 20 | do |
21 | - echo "Wait for Cassandra..." | |
21 | + echo "Wait for $CASSANDRA_URL..." | |
22 | 22 | sleep 10 |
23 | 23 | done |
24 | 24 | |
25 | -if [ "$SKIP_SCHEMA_CREATION" == "false" ]; then | |
25 | +if [ "$CREATE_SCHEMA" == "true" ]; then | |
26 | 26 | echo "Creating 'Thingsboard' keyspace..." |
27 | - cqlsh db -f /root/schema.cql | |
27 | + cqlsh $CASSANDRA_URL -f /root/schema.cql | |
28 | 28 | if [ "$?" -eq 0 ]; then |
29 | 29 | echo "'Thingsboard' keyspace was successfully created!" |
30 | 30 | else |
... | ... | @@ -32,9 +32,9 @@ if [ "$SKIP_SCHEMA_CREATION" == "false" ]; then |
32 | 32 | fi |
33 | 33 | fi |
34 | 34 | |
35 | -if [ "$SKIP_SYSTEM_DATA" == "false" ]; then | |
35 | +if [ "$ADD_SYSTEM_DATA" == "true" ]; then | |
36 | 36 | echo "Adding system data..." |
37 | - cqlsh db -f /root/system-data.cql | |
37 | + cqlsh $CASSANDRA_URL -f /root/system-data.cql | |
38 | 38 | if [ "$?" -eq 0 ]; then |
39 | 39 | echo "System data was successfully added!" |
40 | 40 | else |
... | ... | @@ -42,9 +42,9 @@ if [ "$SKIP_SYSTEM_DATA" == "false" ]; then |
42 | 42 | fi |
43 | 43 | fi |
44 | 44 | |
45 | -if [ "$SKIP_DEMO_DATA" == "false" ]; then | |
45 | +if [ "$ADD_DEMO_DATA" == "true" ]; then | |
46 | 46 | echo "Adding demo data..." |
47 | - cqlsh db -f /root/demo-data.cql | |
47 | + cqlsh $CASSANDRA_URL -f /root/demo-data.cql | |
48 | 48 | if [ "$?" -eq 0 ]; then |
49 | 49 | echo "Demo data was successfully added!" |
50 | 50 | else | ... | ... |
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 | +apiVersion: v1 | |
18 | +kind: Pod | |
19 | +metadata: | |
20 | + name: tb-cassandra-schema | |
21 | +spec: | |
22 | + containers: | |
23 | + - name: tb-cassandra-schema | |
24 | + imagePullPolicy: Always | |
25 | + image: thingsboard/tb-cassandra-schema:1.2.4 | |
26 | + env: | |
27 | + - name: CREATE_SCHEMA | |
28 | + value: "false" | |
29 | + - name: ADD_SYSTEM_DATA | |
30 | + value: "false" | |
31 | + - name : ADD_DEMO_DATA | |
32 | + value: "false" | |
33 | + - name : CASSANDRA_URL | |
34 | + value: "cassandra-headless" | |
35 | + command: | |
36 | + - sh | |
37 | + - -c | |
38 | + - ./install-schema.sh | |
39 | + restartPolicy: Never | |
\ No newline at end of file | ... | ... |
docker/tb.env
renamed from
docker/thingsboard.env
docker/tb/Dockerfile
renamed from
docker/thingsboard/Dockerfile
... | ... | @@ -16,9 +16,9 @@ |
16 | 16 | |
17 | 17 | FROM openjdk:8-jre |
18 | 18 | |
19 | -ADD run_thingsboard.sh /root/run_thingsboard.sh | |
19 | +ADD run-application.sh /root/run-application.sh | |
20 | 20 | ADD thingsboard.deb /root/thingsboard.deb |
21 | 21 | |
22 | -RUN chmod +x /root/run_thingsboard.sh | |
22 | +RUN chmod +x /root/run-application.sh | |
23 | 23 | |
24 | 24 | WORKDIR /root | ... | ... |
docker/tb/Makefile
0 → 100644
1 | +VERSION=1.2.4 | |
2 | +PROJECT=thingsboard | |
3 | +APP=application | |
4 | + | |
5 | +build: | |
6 | + cp ../../application/target/thingsboard.deb . | |
7 | + docker build --pull -t ${PROJECT}/${APP}:${VERSION} . | |
8 | + rm thingsboard.deb | |
9 | + | |
10 | +push: build | |
11 | + docker push ${PROJECT}/${APP}:${VERSION} | |
\ No newline at end of file | ... | ... |
docker/tb/run-application.sh
renamed from
docker/thingsboard/run_thingsboard.sh
... | ... | @@ -21,12 +21,12 @@ dpkg -i /root/thingsboard.deb |
21 | 21 | reachable=0 |
22 | 22 | while [ $reachable -eq 0 ]; |
23 | 23 | do |
24 | - echo "thingsboard-db-schema container is still in progress. waiting until it completed..." | |
24 | + echo "$TB_CASSANDRA_SCHEMA_URL container is still in progress. waiting until it completed..." | |
25 | 25 | sleep 3 |
26 | - ping -q -c 1 thingsboard-db-schema > /dev/null 2>&1 | |
26 | + ping -q -c 1 $TB_CASSANDRA_SCHEMA_URL > /dev/null 2>&1 | |
27 | 27 | if [ "$?" -ne 0 ]; |
28 | 28 | then |
29 | - echo "thingsboard-db-schema container completed!" | |
29 | + echo "$TB_CASSANDRA_SCHEMA_URL container completed!" | |
30 | 30 | reachable=1 |
31 | 31 | fi |
32 | 32 | done | ... | ... |
docker/tb/tb.yaml
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 | +--- | |
18 | +apiVersion: v1 | |
19 | +kind: Service | |
20 | +metadata: | |
21 | + name: tb-service | |
22 | + labels: | |
23 | + app: tb-service | |
24 | +spec: | |
25 | + ports: | |
26 | + - port: 8080 | |
27 | + name: ui | |
28 | + - port: 1883 | |
29 | + name: mqtt | |
30 | + - port: 5683 | |
31 | + name: coap | |
32 | + selector: | |
33 | + app: tb | |
34 | + type: LoadBalancer | |
35 | +--- | |
36 | +apiVersion: policy/v1beta1 | |
37 | +kind: PodDisruptionBudget | |
38 | +metadata: | |
39 | + name: tb-budget | |
40 | +spec: | |
41 | + selector: | |
42 | + matchLabels: | |
43 | + app: tb | |
44 | + minAvailable: 3 | |
45 | +--- | |
46 | +apiVersion: v1 | |
47 | +kind: ConfigMap | |
48 | +metadata: | |
49 | + name: tb-config | |
50 | +data: | |
51 | + zookeeper.enabled: "true" | |
52 | + zookeeper.url: "zk-headless" | |
53 | + cassandra.url: "cassandra-headless:9042" | |
54 | +--- | |
55 | +apiVersion: apps/v1beta1 | |
56 | +kind: StatefulSet | |
57 | +metadata: | |
58 | + name: tb | |
59 | +spec: | |
60 | + serviceName: "tb-service" | |
61 | + replicas: 3 | |
62 | + template: | |
63 | + metadata: | |
64 | + labels: | |
65 | + app: tb | |
66 | + spec: | |
67 | + nodeSelector: | |
68 | + machinetype: tb | |
69 | + affinity: | |
70 | + podAntiAffinity: | |
71 | + requiredDuringSchedulingIgnoredDuringExecution: | |
72 | + - labelSelector: | |
73 | + matchExpressions: | |
74 | + - key: "app" | |
75 | + operator: In | |
76 | + values: | |
77 | + - tb-service | |
78 | + topologyKey: "kubernetes.io/hostname" | |
79 | + containers: | |
80 | + - name: tb | |
81 | + imagePullPolicy: Always | |
82 | + image: thingsboard/application:1.2.4 | |
83 | + ports: | |
84 | + - containerPort: 8080 | |
85 | + name: ui | |
86 | + - containerPort: 1883 | |
87 | + name: mqtt | |
88 | + - containerPort: 5683 | |
89 | + name: coap | |
90 | + - containerPort: 9001 | |
91 | + name: rpc | |
92 | + env: | |
93 | + - name: ZOOKEEPER_ENABLED | |
94 | + valueFrom: | |
95 | + configMapKeyRef: | |
96 | + name: tb-config | |
97 | + key: zookeeper.enabled | |
98 | + - name: ZOOKEEPER_URL | |
99 | + valueFrom: | |
100 | + configMapKeyRef: | |
101 | + name: tb-config | |
102 | + key: zookeeper.url | |
103 | + - name : CASSANDRA_URL | |
104 | + valueFrom: | |
105 | + configMapKeyRef: | |
106 | + name: tb-config | |
107 | + key: cassandra.url | |
108 | + - name : RPC_HOST | |
109 | + valueFrom: | |
110 | + fieldRef: | |
111 | + fieldPath: status.podIP | |
112 | + command: | |
113 | + - sh | |
114 | + - -c | |
115 | + - ./run-application.sh | |
116 | + livenessProbe: | |
117 | + httpGet: | |
118 | + path: /login | |
119 | + port: ui-port | |
120 | + initialDelaySeconds: 120 | |
121 | + timeoutSeconds: 10 | |
\ No newline at end of file | ... | ... |
docker/thingsboard-db-schema.env
deleted
100644 → 0
docker/thingsboard-db-schema/build_and_deploy.sh
deleted
100755 → 0
1 | -#!/bin/bash | |
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 | - | |
19 | -cp ../../dao/src/main/resources/schema.cql schema.cql | |
20 | -cp ../../dao/src/main/resources/demo-data.cql demo-data.cql | |
21 | -cp ../../dao/src/main/resources/system-data.cql system-data.cql | |
22 | - | |
23 | -docker build -t thingsboard/thingsboard-db-schema:1.2.3 -t thingsboard/thingsboard-db-schema:latest . | |
24 | - | |
25 | -docker login | |
26 | - | |
27 | -docker push thingsboard/thingsboard-db-schema:1.2.3 | |
28 | -docker push thingsboard/thingsboard-db-schema:latest | |
\ No newline at end of file |
docker/zookeeper/Dockerfile
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 | +FROM ubuntu:16.04 | |
18 | +ENV ZK_USER=zookeeper \ | |
19 | +ZK_DATA_DIR=/var/lib/zookeeper/data \ | |
20 | +ZK_DATA_LOG_DIR=/var/lib/zookeeper/log \ | |
21 | +ZK_LOG_DIR=/var/log/zookeeper \ | |
22 | +JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64 | |
23 | + | |
24 | +ARG GPG_KEY=C823E3E5B12AF29C67F81976F5CECB3CB5E9BD2D | |
25 | +ARG ZK_DIST=zookeeper-3.4.9 | |
26 | +RUN set -x \ | |
27 | + && apt-get update \ | |
28 | + && apt-get install -y openjdk-8-jre-headless wget netcat-openbsd \ | |
29 | + && wget -q "http://www.apache.org/dist/zookeeper/$ZK_DIST/$ZK_DIST.tar.gz" \ | |
30 | + && wget -q "http://www.apache.org/dist/zookeeper/$ZK_DIST/$ZK_DIST.tar.gz.asc" \ | |
31 | + && export GNUPGHOME="$(mktemp -d)" \ | |
32 | + && gpg --keyserver ha.pool.sks-keyservers.net --recv-key "$GPG_KEY" \ | |
33 | + && gpg --batch --verify "$ZK_DIST.tar.gz.asc" "$ZK_DIST.tar.gz" \ | |
34 | + && tar -xzf "$ZK_DIST.tar.gz" -C /opt \ | |
35 | + && rm -r "$GNUPGHOME" "$ZK_DIST.tar.gz" "$ZK_DIST.tar.gz.asc" \ | |
36 | + && ln -s /opt/$ZK_DIST /opt/zookeeper \ | |
37 | + && rm -rf /opt/zookeeper/CHANGES.txt \ | |
38 | + /opt/zookeeper/README.txt \ | |
39 | + /opt/zookeeper/NOTICE.txt \ | |
40 | + /opt/zookeeper/CHANGES.txt \ | |
41 | + /opt/zookeeper/README_packaging.txt \ | |
42 | + /opt/zookeeper/build.xml \ | |
43 | + /opt/zookeeper/config \ | |
44 | + /opt/zookeeper/contrib \ | |
45 | + /opt/zookeeper/dist-maven \ | |
46 | + /opt/zookeeper/docs \ | |
47 | + /opt/zookeeper/ivy.xml \ | |
48 | + /opt/zookeeper/ivysettings.xml \ | |
49 | + /opt/zookeeper/recipes \ | |
50 | + /opt/zookeeper/src \ | |
51 | + /opt/zookeeper/$ZK_DIST.jar.asc \ | |
52 | + /opt/zookeeper/$ZK_DIST.jar.md5 \ | |
53 | + /opt/zookeeper/$ZK_DIST.jar.sha1 \ | |
54 | + && apt-get autoremove -y wget \ | |
55 | + && rm -rf /var/lib/apt/lists/* | |
56 | + | |
57 | +#Copy configuration generator script to bin | |
58 | +COPY zk-gen-config.sh zk-ok.sh /opt/zookeeper/bin/ | |
59 | + | |
60 | +# Create a user for the zookeeper process and configure file system ownership | |
61 | +# for nessecary directories and symlink the distribution as a user executable | |
62 | +RUN set -x \ | |
63 | + && useradd $ZK_USER \ | |
64 | + && [ `id -u $ZK_USER` -eq 1000 ] \ | |
65 | + && [ `id -g $ZK_USER` -eq 1000 ] \ | |
66 | + && mkdir -p $ZK_DATA_DIR $ZK_DATA_LOG_DIR $ZK_LOG_DIR /usr/share/zookeeper /tmp/zookeeper /usr/etc/ \ | |
67 | + && chown -R "$ZK_USER:$ZK_USER" /opt/$ZK_DIST $ZK_DATA_DIR $ZK_LOG_DIR $ZK_DATA_LOG_DIR /tmp/zookeeper \ | |
68 | + && ln -s /opt/zookeeper/conf/ /usr/etc/zookeeper \ | |
69 | + && ln -s /opt/zookeeper/bin/* /usr/bin \ | |
70 | + && ln -s /opt/zookeeper/$ZK_DIST.jar /usr/share/zookeeper/ \ | |
71 | + && ln -s /opt/zookeeper/lib/* /usr/share/zookeeper | ... | ... |
docker/zookeeper/Makefile
0 → 100644
docker/zookeeper/zk-gen-config.sh
0 → 100755
1 | +#!/usr/bin/env bash | |
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 | +ZK_USER=${ZK_USER:-"zookeeper"} | |
19 | +ZK_LOG_LEVEL=${ZK_LOG_LEVEL:-"INFO"} | |
20 | +ZK_DATA_DIR=${ZK_DATA_DIR:-"/var/lib/zookeeper/data"} | |
21 | +ZK_DATA_LOG_DIR=${ZK_DATA_LOG_DIR:-"/var/lib/zookeeper/log"} | |
22 | +ZK_LOG_DIR=${ZK_LOG_DIR:-"var/log/zookeeper"} | |
23 | +ZK_CONF_DIR=${ZK_CONF_DIR:-"/opt/zookeeper/conf"} | |
24 | +ZK_CLIENT_PORT=${ZK_CLIENT_PORT:-2181} | |
25 | +ZK_SERVER_PORT=${ZK_SERVER_PORT:-2888} | |
26 | +ZK_ELECTION_PORT=${ZK_ELECTION_PORT:-3888} | |
27 | +ZK_TICK_TIME=${ZK_TICK_TIME:-2000} | |
28 | +ZK_INIT_LIMIT=${ZK_INIT_LIMIT:-10} | |
29 | +ZK_SYNC_LIMIT=${ZK_SYNC_LIMIT:-5} | |
30 | +ZK_HEAP_SIZE=${ZK_HEAP_SIZE:-2G} | |
31 | +ZK_MAX_CLIENT_CNXNS=${ZK_MAX_CLIENT_CNXNS:-60} | |
32 | +ZK_MIN_SESSION_TIMEOUT=${ZK_MIN_SESSION_TIMEOUT:- $((ZK_TICK_TIME*2))} | |
33 | +ZK_MAX_SESSION_TIMEOUT=${ZK_MAX_SESSION_TIMEOUT:- $((ZK_TICK_TIME*20))} | |
34 | +ZK_SNAP_RETAIN_COUNT=${ZK_SNAP_RETAIN_COUNT:-3} | |
35 | +ZK_PURGE_INTERVAL=${ZK_PURGE_INTERVAL:-0} | |
36 | +ID_FILE="$ZK_DATA_DIR/myid" | |
37 | +ZK_CONFIG_FILE="$ZK_CONF_DIR/zoo.cfg" | |
38 | +LOGGER_PROPS_FILE="$ZK_CONF_DIR/log4j.properties" | |
39 | +JAVA_ENV_FILE="$ZK_CONF_DIR/java.env" | |
40 | +HOST=`hostname -s` | |
41 | +DOMAIN=`hostname -d` | |
42 | + | |
43 | +function print_servers() { | |
44 | + for (( i=1; i<=$ZK_REPLICAS; i++ )) | |
45 | + do | |
46 | + echo "server.$i=$NAME-$((i-1)).$DOMAIN:$ZK_SERVER_PORT:$ZK_ELECTION_PORT" | |
47 | + done | |
48 | +} | |
49 | + | |
50 | +function validate_env() { | |
51 | + echo "Validating environment" | |
52 | + if [ -z $ZK_REPLICAS ]; then | |
53 | + echo "ZK_REPLICAS is a mandatory environment variable" | |
54 | + exit 1 | |
55 | + fi | |
56 | + | |
57 | + if [[ $HOST =~ (.*)-([0-9]+)$ ]]; then | |
58 | + NAME=${BASH_REMATCH[1]} | |
59 | + ORD=${BASH_REMATCH[2]} | |
60 | + else | |
61 | + echo "Failed to extract ordinal from hostname $HOST" | |
62 | + exit 1 | |
63 | + fi | |
64 | + MY_ID=$((ORD+1)) | |
65 | + echo "ZK_REPLICAS=$ZK_REPLICAS" | |
66 | + echo "MY_ID=$MY_ID" | |
67 | + echo "ZK_LOG_LEVEL=$ZK_LOG_LEVEL" | |
68 | + echo "ZK_DATA_DIR=$ZK_DATA_DIR" | |
69 | + echo "ZK_DATA_LOG_DIR=$ZK_DATA_LOG_DIR" | |
70 | + echo "ZK_LOG_DIR=$ZK_LOG_DIR" | |
71 | + echo "ZK_CLIENT_PORT=$ZK_CLIENT_PORT" | |
72 | + echo "ZK_SERVER_PORT=$ZK_SERVER_PORT" | |
73 | + echo "ZK_ELECTION_PORT=$ZK_ELECTION_PORT" | |
74 | + echo "ZK_TICK_TIME=$ZK_TICK_TIME" | |
75 | + echo "ZK_INIT_LIMIT=$ZK_INIT_LIMIT" | |
76 | + echo "ZK_SYNC_LIMIT=$ZK_SYNC_LIMIT" | |
77 | + echo "ZK_MAX_CLIENT_CNXNS=$ZK_MAX_CLIENT_CNXNS" | |
78 | + echo "ZK_MIN_SESSION_TIMEOUT=$ZK_MIN_SESSION_TIMEOUT" | |
79 | + echo "ZK_MAX_SESSION_TIMEOUT=$ZK_MAX_SESSION_TIMEOUT" | |
80 | + echo "ZK_HEAP_SIZE=$ZK_HEAP_SIZE" | |
81 | + echo "ZK_SNAP_RETAIN_COUNT=$ZK_SNAP_RETAIN_COUNT" | |
82 | + echo "ZK_PURGE_INTERVAL=$ZK_PURGE_INTERVAL" | |
83 | + echo "ENSEMBLE" | |
84 | + print_servers | |
85 | + echo "Environment validation successful" | |
86 | +} | |
87 | + | |
88 | +function create_config() { | |
89 | + rm -f $ZK_CONFIG_FILE | |
90 | + echo "Creating ZooKeeper configuration" | |
91 | + echo "#This file was autogenerated by zk DO NOT EDIT" >> $ZK_CONFIG_FILE | |
92 | + echo "clientPort=$ZK_CLIENT_PORT" >> $ZK_CONFIG_FILE | |
93 | + echo "dataDir=$ZK_DATA_DIR" >> $ZK_CONFIG_FILE | |
94 | + echo "dataLogDir=$ZK_DATA_LOG_DIR" >> $ZK_CONFIG_FILE | |
95 | + echo "tickTime=$ZK_TICK_TIME" >> $ZK_CONFIG_FILE | |
96 | + echo "initLimit=$ZK_INIT_LIMIT" >> $ZK_CONFIG_FILE | |
97 | + echo "syncLimit=$ZK_SYNC_LIMIT" >> $ZK_CONFIG_FILE | |
98 | + echo "maxClientCnxns=$ZK_MAX_CLIENT_CNXNS" >> $ZK_CONFIG_FILE | |
99 | + echo "minSessionTimeout=$ZK_MIN_SESSION_TIMEOUT" >> $ZK_CONFIG_FILE | |
100 | + echo "maxSessionTimeout=$ZK_MAX_SESSION_TIMEOUT" >> $ZK_CONFIG_FILE | |
101 | + echo "autopurge.snapRetainCount=$ZK_SNAP_RETAIN_COUNT" >> $ZK_CONFIG_FILE | |
102 | + echo "autopurge.purgeInteval=$ZK_PURGE_INTERVAL" >> $ZK_CONFIG_FILE | |
103 | + | |
104 | + if [ $ZK_REPLICAS -gt 1 ]; then | |
105 | + print_servers >> $ZK_CONFIG_FILE | |
106 | + fi | |
107 | + echo "Wrote ZooKeeper configuration file to $ZK_CONFIG_FILE" | |
108 | +} | |
109 | + | |
110 | +function create_data_dirs() { | |
111 | + echo "Creating ZooKeeper data directories and setting permissions" | |
112 | + if [ ! -d $ZK_DATA_DIR ]; then | |
113 | + mkdir -p $ZK_DATA_DIR | |
114 | + chown -R $ZK_USER:$ZK_USER $ZK_DATA_DIR | |
115 | + fi | |
116 | + | |
117 | + if [ ! -d $ZK_DATA_LOG_DIR ]; then | |
118 | + mkdir -p $ZK_DATA_LOG_DIR | |
119 | + chown -R $ZK_USER:$ZK_USER $ZK_DATA_LOG_DIR | |
120 | + fi | |
121 | + | |
122 | + if [ ! -d $ZK_LOG_DIR ]; then | |
123 | + mkdir -p $ZK_LOG_DIR | |
124 | + chown -R $ZK_USER:$ZK_USER $ZK_LOG_DIR | |
125 | + fi | |
126 | + if [ ! -f $ID_FILE ]; then | |
127 | + echo $MY_ID >> $ID_FILE | |
128 | + fi | |
129 | + echo "Created ZooKeeper data directories and set permissions in $ZK_DATA_DIR" | |
130 | +} | |
131 | + | |
132 | +function create_log_props () { | |
133 | + rm -f $LOGGER_PROPS_FILE | |
134 | + echo "Creating ZooKeeper log4j configuration" | |
135 | + echo "zookeeper.root.logger=CONSOLE" >> $LOGGER_PROPS_FILE | |
136 | + echo "zookeeper.console.threshold="$ZK_LOG_LEVEL >> $LOGGER_PROPS_FILE | |
137 | + echo "log4j.rootLogger=\${zookeeper.root.logger}" >> $LOGGER_PROPS_FILE | |
138 | + echo "log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender" >> $LOGGER_PROPS_FILE | |
139 | + echo "log4j.appender.CONSOLE.Threshold=\${zookeeper.console.threshold}" >> $LOGGER_PROPS_FILE | |
140 | + echo "log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout" >> $LOGGER_PROPS_FILE | |
141 | + echo "log4j.appender.CONSOLE.layout.ConversionPattern=%d{ISO8601} [myid:%X{myid}] - %-5p [%t:%C{1}@%L] - %m%n" >> $LOGGER_PROPS_FILE | |
142 | + echo "Wrote log4j configuration to $LOGGER_PROPS_FILE" | |
143 | +} | |
144 | + | |
145 | +function create_java_env() { | |
146 | + rm -f $JAVA_ENV_FILE | |
147 | + echo "Creating JVM configuration file" | |
148 | + echo "ZOO_LOG_DIR=$ZK_LOG_DIR" >> $JAVA_ENV_FILE | |
149 | + echo "JVMFLAGS=\"-Xmx$ZK_HEAP_SIZE -Xms$ZK_HEAP_SIZE\"" >> $JAVA_ENV_FILE | |
150 | + echo "Wrote JVM configuration to $JAVA_ENV_FILE" | |
151 | +} | |
152 | + | |
153 | +validate_env && create_config && create_log_props && create_data_dirs && create_java_env | ... | ... |
docker/zookeeper/zk-ok.sh
renamed from
docker/thingsboard/build_and_deploy.sh
1 | -#!/bin/bash | |
1 | +#!/usr/bin/env bash | |
2 | 2 | # |
3 | 3 | # Copyright © 2016-2017 The Thingsboard Authors |
4 | 4 | # |
... | ... | @@ -15,12 +15,14 @@ |
15 | 15 | # limitations under the License. |
16 | 16 | # |
17 | 17 | |
18 | +# zk-ok.sh uses the ruok ZooKeeper four letter work to determine if the instance | |
19 | +# is health. The $? variable will be set to 0 if server responds that it is | |
20 | +# healthy, or 1 if the server fails to respond. | |
18 | 21 | |
19 | -cp ../../application/target/thingsboard.deb thingsboard.deb | |
20 | - | |
21 | -docker build -t thingsboard/application:1.2.3 -t thingsboard/application:latest . | |
22 | - | |
23 | -docker login | |
24 | - | |
25 | -docker push thingsboard/application:1.2.3 | |
26 | -docker push thingsboard/application:latest | |
\ No newline at end of file | ||
22 | +ZK_CLIENT_PORT=${ZK_CLIENT_PORT:-2181} | |
23 | +OK=$(echo ruok | nc 127.0.0.1 $ZK_CLIENT_PORT) | |
24 | +if [ "$OK" == "imok" ]; then | |
25 | + exit 0 | |
26 | +else | |
27 | + exit 1 | |
28 | +fi | ... | ... |
docker/zookeeper/zookeeper.yaml
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 | +apiVersion: v1 | |
18 | +kind: Service | |
19 | +metadata: | |
20 | + name: zk-headless | |
21 | + labels: | |
22 | + app: zk-headless | |
23 | +spec: | |
24 | + ports: | |
25 | + - port: 2888 | |
26 | + name: server | |
27 | + - port: 3888 | |
28 | + name: leader-election | |
29 | + clusterIP: None | |
30 | + selector: | |
31 | + app: zk | |
32 | +--- | |
33 | +apiVersion: v1 | |
34 | +kind: ConfigMap | |
35 | +metadata: | |
36 | + name: zk-config | |
37 | +data: | |
38 | + ensemble: "zk-0;zk-1;zk-2" | |
39 | + replicas: "3" | |
40 | + jvm.heap: "500m" | |
41 | + tick: "2000" | |
42 | + init: "10" | |
43 | + sync: "5" | |
44 | + client.cnxns: "60" | |
45 | + snap.retain: "3" | |
46 | + purge.interval: "1" | |
47 | + client.port: "2181" | |
48 | + server.port: "2888" | |
49 | + election.port: "3888" | |
50 | +--- | |
51 | +apiVersion: policy/v1beta1 | |
52 | +kind: PodDisruptionBudget | |
53 | +metadata: | |
54 | + name: zk-budget | |
55 | +spec: | |
56 | + selector: | |
57 | + matchLabels: | |
58 | + app: zk | |
59 | + minAvailable: 3 | |
60 | +--- | |
61 | +apiVersion: apps/v1beta1 | |
62 | +kind: StatefulSet | |
63 | +metadata: | |
64 | + name: zk | |
65 | +spec: | |
66 | + serviceName: zk-headless | |
67 | + replicas: 3 | |
68 | + template: | |
69 | + metadata: | |
70 | + labels: | |
71 | + app: zk | |
72 | + annotations: | |
73 | + pod.alpha.kubernetes.io/initialized: "true" | |
74 | + spec: | |
75 | + nodeSelector: | |
76 | + machinetype: other | |
77 | + affinity: | |
78 | + podAntiAffinity: | |
79 | + requiredDuringSchedulingIgnoredDuringExecution: | |
80 | + - labelSelector: | |
81 | + matchExpressions: | |
82 | + - key: "app" | |
83 | + operator: In | |
84 | + values: | |
85 | + - zk-headless | |
86 | + topologyKey: "kubernetes.io/hostname" | |
87 | + containers: | |
88 | + - name: zk | |
89 | + imagePullPolicy: Always | |
90 | + image: thingsboard/zk:1.2.4 | |
91 | + ports: | |
92 | + - containerPort: 2181 | |
93 | + name: client | |
94 | + - containerPort: 2888 | |
95 | + name: server | |
96 | + - containerPort: 3888 | |
97 | + name: leader-election | |
98 | + env: | |
99 | + - name : ZK_ENSEMBLE | |
100 | + valueFrom: | |
101 | + configMapKeyRef: | |
102 | + name: zk-config | |
103 | + key: ensemble | |
104 | + - name : ZK_REPLICAS | |
105 | + valueFrom: | |
106 | + configMapKeyRef: | |
107 | + name: zk-config | |
108 | + key: replicas | |
109 | + - name : ZK_HEAP_SIZE | |
110 | + valueFrom: | |
111 | + configMapKeyRef: | |
112 | + name: zk-config | |
113 | + key: jvm.heap | |
114 | + - name : ZK_TICK_TIME | |
115 | + valueFrom: | |
116 | + configMapKeyRef: | |
117 | + name: zk-config | |
118 | + key: tick | |
119 | + - name : ZK_INIT_LIMIT | |
120 | + valueFrom: | |
121 | + configMapKeyRef: | |
122 | + name: zk-config | |
123 | + key: init | |
124 | + - name : ZK_SYNC_LIMIT | |
125 | + valueFrom: | |
126 | + configMapKeyRef: | |
127 | + name: zk-config | |
128 | + key: tick | |
129 | + - name : ZK_MAX_CLIENT_CNXNS | |
130 | + valueFrom: | |
131 | + configMapKeyRef: | |
132 | + name: zk-config | |
133 | + key: client.cnxns | |
134 | + - name: ZK_SNAP_RETAIN_COUNT | |
135 | + valueFrom: | |
136 | + configMapKeyRef: | |
137 | + name: zk-config | |
138 | + key: snap.retain | |
139 | + - name: ZK_PURGE_INTERVAL | |
140 | + valueFrom: | |
141 | + configMapKeyRef: | |
142 | + name: zk-config | |
143 | + key: purge.interval | |
144 | + - name: ZK_CLIENT_PORT | |
145 | + valueFrom: | |
146 | + configMapKeyRef: | |
147 | + name: zk-config | |
148 | + key: client.port | |
149 | + - name: ZK_SERVER_PORT | |
150 | + valueFrom: | |
151 | + configMapKeyRef: | |
152 | + name: zk-config | |
153 | + key: server.port | |
154 | + - name: ZK_ELECTION_PORT | |
155 | + valueFrom: | |
156 | + configMapKeyRef: | |
157 | + name: zk-config | |
158 | + key: election.port | |
159 | + command: | |
160 | + - sh | |
161 | + - -c | |
162 | + - zk-gen-config.sh && zkServer.sh start-foreground | |
163 | + readinessProbe: | |
164 | + exec: | |
165 | + command: | |
166 | + - "zk-ok.sh" | |
167 | + initialDelaySeconds: 15 | |
168 | + timeoutSeconds: 5 | |
169 | + livenessProbe: | |
170 | + exec: | |
171 | + command: | |
172 | + - "zk-ok.sh" | |
173 | + initialDelaySeconds: 15 | |
174 | + timeoutSeconds: 5 | |
175 | + volumeMounts: | |
176 | + - name: zkdatadir | |
177 | + mountPath: /var/lib/zookeeper | |
178 | + securityContext: | |
179 | + runAsUser: 1000 | |
180 | + fsGroup: 1000 | |
181 | + volumeClaimTemplates: | |
182 | + - metadata: | |
183 | + name: zkdatadir | |
184 | + annotations: | |
185 | + volume.beta.kubernetes.io/storage-class: slow | |
186 | + spec: | |
187 | + accessModes: [ "ReadWriteOnce" ] | |
188 | + resources: | |
189 | + requests: | |
190 | + storage: 1Gi | |
\ No newline at end of file | ... | ... |
... | ... | @@ -41,7 +41,7 @@ import java.security.cert.X509Certificate; |
41 | 41 | */ |
42 | 42 | @Slf4j |
43 | 43 | @Component("MqttSslHandlerProvider") |
44 | -@ConditionalOnProperty(prefix = "mqtt.ssl", value = "key-store", havingValue = "", matchIfMissing = false) | |
44 | +@ConditionalOnProperty(prefix = "mqtt.ssl", value = "enabled", havingValue = "true", matchIfMissing = false) | |
45 | 45 | public class MqttSslHandlerProvider { |
46 | 46 | |
47 | 47 | public static final String TLS = "TLS"; | ... | ... |
... | ... | @@ -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 | ... | ... |