Showing
57 changed files
with
2329 additions
and
1029 deletions
Too many changes to show.
To preserve performance only 57 of 60 files are displayed.
... | ... | @@ -294,7 +294,7 @@ public class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcesso |
294 | 294 | private void handleGetAttributesRequest(DeviceToDeviceActorMsg src) { |
295 | 295 | GetAttributesRequest request = (GetAttributesRequest) src.getPayload(); |
296 | 296 | ListenableFuture<List<AttributeKvEntry>> clientAttributesFuture = getAttributeKvEntries(deviceId, DataConstants.CLIENT_SCOPE, request.getClientAttributeNames()); |
297 | - ListenableFuture<List<AttributeKvEntry>> sharedAttributesFuture = getAttributeKvEntries(deviceId, DataConstants.SHARED_SCOPE, request.getClientAttributeNames()); | |
297 | + ListenableFuture<List<AttributeKvEntry>> sharedAttributesFuture = getAttributeKvEntries(deviceId, DataConstants.SHARED_SCOPE, request.getSharedAttributeNames()); | |
298 | 298 | |
299 | 299 | Futures.addCallback(Futures.allAsList(Arrays.asList(clientAttributesFuture, sharedAttributesFuture)), new FutureCallback<List<List<AttributeKvEntry>>>() { |
300 | 300 | @Override | ... | ... |
... | ... | @@ -32,6 +32,7 @@ import org.thingsboard.server.actors.rpc.RpcManagerActor; |
32 | 32 | import org.thingsboard.server.actors.rpc.RpcSessionCreateRequestMsg; |
33 | 33 | import org.thingsboard.server.actors.session.SessionManagerActor; |
34 | 34 | import org.thingsboard.server.actors.stats.StatsActor; |
35 | +import org.thingsboard.server.common.data.Device; | |
35 | 36 | import org.thingsboard.server.common.data.id.DeviceId; |
36 | 37 | import org.thingsboard.server.common.data.id.EntityId; |
37 | 38 | import org.thingsboard.server.common.data.id.TenantId; |
... | ... | @@ -48,6 +49,7 @@ import org.thingsboard.server.gen.cluster.ClusterAPIProtos; |
48 | 49 | import org.thingsboard.server.service.cluster.discovery.DiscoveryService; |
49 | 50 | import org.thingsboard.server.service.cluster.discovery.ServerInstance; |
50 | 51 | import org.thingsboard.server.service.cluster.rpc.ClusterRpcService; |
52 | +import org.thingsboard.server.service.state.DeviceStateService; | |
51 | 53 | import scala.concurrent.Await; |
52 | 54 | import scala.concurrent.Future; |
53 | 55 | import scala.concurrent.duration.Duration; |
... | ... | @@ -81,6 +83,9 @@ public class DefaultActorService implements ActorService { |
81 | 83 | @Autowired |
82 | 84 | private DiscoveryService discoveryService; |
83 | 85 | |
86 | + @Autowired | |
87 | + private DeviceStateService deviceStateService; | |
88 | + | |
84 | 89 | private ActorSystem system; |
85 | 90 | |
86 | 91 | private ActorRef appActor; |
... | ... | @@ -199,7 +204,7 @@ public class DefaultActorService implements ActorService { |
199 | 204 | public void onReceivedMsg(ServerAddress source, ClusterAPIProtos.ClusterMessage msg) { |
200 | 205 | ServerAddress serverAddress = new ServerAddress(source.getHost(), source.getPort()); |
201 | 206 | log.info("Received msg [{}] from [{}]", msg.getMessageType().name(), serverAddress); |
202 | - if(log.isDebugEnabled()){ | |
207 | + if (log.isDebugEnabled()) { | |
203 | 208 | log.info("MSG: ", msg); |
204 | 209 | } |
205 | 210 | switch (msg.getMessageType()) { |
... | ... | @@ -236,6 +241,9 @@ public class DefaultActorService implements ActorService { |
236 | 241 | case CLUSTER_RPC_FROM_DEVICE_RESPONSE_MESSAGE: |
237 | 242 | actorContext.getDeviceRpcService().processRemoteResponseFromDevice(serverAddress, msg.getPayload().toByteArray()); |
238 | 243 | break; |
244 | + case CLUSTER_DEVICE_STATE_SERVICE_MESSAGE: | |
245 | + actorContext.getDeviceStateService().onRemoteMsg(serverAddress, msg.getPayload().toByteArray()); | |
246 | + break; | |
239 | 247 | } |
240 | 248 | } |
241 | 249 | |
... | ... | @@ -254,4 +262,8 @@ public class DefaultActorService implements ActorService { |
254 | 262 | rpcManagerActor.tell(msg, ActorRef.noSender()); |
255 | 263 | } |
256 | 264 | |
265 | + @Override | |
266 | + public void onDeviceAdded(Device device) { | |
267 | + deviceStateService.onDeviceAdded(device); | |
268 | + } | |
257 | 269 | } | ... | ... |
application/src/main/java/org/thingsboard/server/actors/shared/rulechain/TenantRuleChainManager.java
... | ... | @@ -33,9 +33,7 @@ public class TenantRuleChainManager extends RuleChainManager { |
33 | 33 | |
34 | 34 | @Override |
35 | 35 | public void init(ActorContext context) { |
36 | - if (systemContext.isTenantComponentsInitEnabled()) { | |
37 | - super.init(context); | |
38 | - } | |
36 | + super.init(context); | |
39 | 37 | } |
40 | 38 | |
41 | 39 | @Override | ... | ... |
... | ... | @@ -36,6 +36,7 @@ import org.springframework.context.annotation.Lazy; |
36 | 36 | import org.springframework.stereotype.Service; |
37 | 37 | import org.springframework.util.Assert; |
38 | 38 | import org.thingsboard.server.common.msg.cluster.ServerAddress; |
39 | +import org.thingsboard.server.service.state.DeviceStateService; | |
39 | 40 | import org.thingsboard.server.service.telemetry.TelemetrySubscriptionService; |
40 | 41 | import org.thingsboard.server.utils.MiscUtils; |
41 | 42 | |
... | ... | @@ -74,6 +75,10 @@ public class ZkDiscoveryService implements DiscoveryService, PathChildrenCacheLi |
74 | 75 | @Lazy |
75 | 76 | private TelemetrySubscriptionService tsSubService; |
76 | 77 | |
78 | + @Autowired | |
79 | + @Lazy | |
80 | + private DeviceStateService deviceStateService; | |
81 | + | |
77 | 82 | private final List<DiscoveryServiceListener> listeners = new CopyOnWriteArrayList<>(); |
78 | 83 | |
79 | 84 | private CuratorFramework client; |
... | ... | @@ -203,6 +208,7 @@ public class ZkDiscoveryService implements DiscoveryService, PathChildrenCacheLi |
203 | 208 | switch (pathChildrenCacheEvent.getType()) { |
204 | 209 | case CHILD_ADDED: |
205 | 210 | tsSubService.onClusterUpdate(); |
211 | + deviceStateService.onClusterUpdate(); | |
206 | 212 | listeners.forEach(listener -> listener.onServerAdded(instance)); |
207 | 213 | break; |
208 | 214 | case CHILD_UPDATED: |
... | ... | @@ -210,6 +216,7 @@ public class ZkDiscoveryService implements DiscoveryService, PathChildrenCacheLi |
210 | 216 | break; |
211 | 217 | case CHILD_REMOVED: |
212 | 218 | tsSubService.onClusterUpdate(); |
219 | + deviceStateService.onClusterUpdate(); | |
213 | 220 | listeners.forEach(listener -> listener.onServerRemoved(instance)); |
214 | 221 | break; |
215 | 222 | default: | ... | ... |
... | ... | @@ -211,7 +211,13 @@ public class CassandraDatabaseUpgradeService implements DatabaseUpgradeService { |
211 | 211 | |
212 | 212 | private void loadCql(Path cql) throws Exception { |
213 | 213 | List<String> statements = new CQLStatementsParser(cql).getStatements(); |
214 | - statements.forEach(statement -> installCluster.getSession().execute(statement)); | |
214 | + statements.forEach(statement -> { | |
215 | + installCluster.getSession().execute(statement); | |
216 | + try { | |
217 | + Thread.sleep(2500); | |
218 | + } catch (InterruptedException e) {} | |
219 | + }); | |
220 | + Thread.sleep(5000); | |
215 | 221 | } |
216 | 222 | |
217 | 223 | } | ... | ... |
... | ... | @@ -19,16 +19,15 @@ import lombok.extern.slf4j.Slf4j; |
19 | 19 | import org.springframework.beans.factory.annotation.Autowired; |
20 | 20 | import org.springframework.context.annotation.Profile; |
21 | 21 | import org.springframework.stereotype.Service; |
22 | +import org.thingsboard.server.common.data.SearchTextBased; | |
22 | 23 | import org.thingsboard.server.common.data.Tenant; |
23 | -import org.thingsboard.server.common.data.id.IdBased; | |
24 | +import org.thingsboard.server.common.data.id.UUIDBased; | |
25 | +import org.thingsboard.server.common.data.page.TextPageData; | |
24 | 26 | import org.thingsboard.server.common.data.page.TextPageLink; |
25 | 27 | import org.thingsboard.server.common.data.rule.RuleChain; |
26 | 28 | import org.thingsboard.server.dao.rule.RuleChainService; |
27 | 29 | import org.thingsboard.server.dao.tenant.TenantService; |
28 | 30 | |
29 | -import java.util.List; | |
30 | -import java.util.UUID; | |
31 | - | |
32 | 31 | @Service |
33 | 32 | @Profile("install") |
34 | 33 | @Slf4j |
... | ... | @@ -59,8 +58,8 @@ public class DefaultDataUpdateService implements DataUpdateService { |
59 | 58 | new PaginatedUpdater<String, Tenant>() { |
60 | 59 | |
61 | 60 | @Override |
62 | - protected List<Tenant> findEntities(String region, TextPageLink pageLink) { | |
63 | - return tenantService.findTenants(pageLink).getData(); | |
61 | + protected TextPageData<Tenant> findEntities(String region, TextPageLink pageLink) { | |
62 | + return tenantService.findTenants(pageLink); | |
64 | 63 | } |
65 | 64 | |
66 | 65 | @Override |
... | ... | @@ -76,7 +75,7 @@ public class DefaultDataUpdateService implements DataUpdateService { |
76 | 75 | } |
77 | 76 | }; |
78 | 77 | |
79 | - public abstract class PaginatedUpdater<I, D extends IdBased<?>> { | |
78 | + public abstract class PaginatedUpdater<I, D extends SearchTextBased<? extends UUIDBased>> { | |
80 | 79 | |
81 | 80 | private static final int DEFAULT_LIMIT = 100; |
82 | 81 | |
... | ... | @@ -84,20 +83,18 @@ public class DefaultDataUpdateService implements DataUpdateService { |
84 | 83 | TextPageLink pageLink = new TextPageLink(DEFAULT_LIMIT); |
85 | 84 | boolean hasNext = true; |
86 | 85 | while (hasNext) { |
87 | - List<D> entities = findEntities(id, pageLink); | |
88 | - for (D entity : entities) { | |
86 | + TextPageData<D> entities = findEntities(id, pageLink); | |
87 | + for (D entity : entities.getData()) { | |
89 | 88 | updateEntity(entity); |
90 | 89 | } |
91 | - hasNext = entities.size() == pageLink.getLimit(); | |
90 | + hasNext = entities.hasNext(); | |
92 | 91 | if (hasNext) { |
93 | - int index = entities.size() - 1; | |
94 | - UUID idOffset = entities.get(index).getUuidId(); | |
95 | - pageLink.setIdOffset(idOffset); | |
92 | + pageLink = entities.getNextPageLink(); | |
96 | 93 | } |
97 | 94 | } |
98 | 95 | } |
99 | 96 | |
100 | - protected abstract List<D> findEntities(I id, TextPageLink pageLink); | |
97 | + protected abstract TextPageData<D> findEntities(I id, TextPageLink pageLink); | |
101 | 98 | |
102 | 99 | protected abstract void updateEntity(D entity); |
103 | 100 | ... | ... |
... | ... | @@ -70,8 +70,7 @@ public class SqlDatabaseUpgradeService implements DatabaseUpgradeService { |
70 | 70 | log.info("Updating schema ..."); |
71 | 71 | Path schemaUpdateFile = Paths.get(installScripts.getDataDir(), "upgrade", "1.3.1", SCHEMA_UPDATE_SQL); |
72 | 72 | try (Connection conn = DriverManager.getConnection(dbUrl, dbUserName, dbPassword)) { |
73 | - String sql = new String(Files.readAllBytes(schemaUpdateFile), Charset.forName("UTF-8")); | |
74 | - conn.createStatement().execute(sql); //NOSONAR, ignoring because method used to execute thingsboard database upgrade script | |
73 | + loadSql(schemaUpdateFile, conn); | |
75 | 74 | } |
76 | 75 | log.info("Schema updated."); |
77 | 76 | break; |
... | ... | @@ -87,8 +86,7 @@ public class SqlDatabaseUpgradeService implements DatabaseUpgradeService { |
87 | 86 | |
88 | 87 | log.info("Updating schema ..."); |
89 | 88 | schemaUpdateFile = Paths.get(installScripts.getDataDir(), "upgrade", "1.4.0", SCHEMA_UPDATE_SQL); |
90 | - String sql = new String(Files.readAllBytes(schemaUpdateFile), Charset.forName("UTF-8")); | |
91 | - conn.createStatement().execute(sql); //NOSONAR, ignoring because method used to execute thingsboard database upgrade script | |
89 | + loadSql(schemaUpdateFile, conn); | |
92 | 90 | log.info("Schema updated."); |
93 | 91 | |
94 | 92 | log.info("Restoring dashboards ..."); |
... | ... | @@ -105,8 +103,7 @@ public class SqlDatabaseUpgradeService implements DatabaseUpgradeService { |
105 | 103 | try (Connection conn = DriverManager.getConnection(dbUrl, dbUserName, dbPassword)) { |
106 | 104 | log.info("Updating schema ..."); |
107 | 105 | schemaUpdateFile = Paths.get(installScripts.getDataDir(), "upgrade", "2.0.0", SCHEMA_UPDATE_SQL); |
108 | - String sql = new String(Files.readAllBytes(schemaUpdateFile), Charset.forName("UTF-8")); | |
109 | - conn.createStatement().execute(sql); //NOSONAR, ignoring because method used to execute thingsboard database upgrade script | |
106 | + loadSql(schemaUpdateFile, conn); | |
110 | 107 | log.info("Schema updated."); |
111 | 108 | } |
112 | 109 | break; |
... | ... | @@ -114,4 +111,10 @@ public class SqlDatabaseUpgradeService implements DatabaseUpgradeService { |
114 | 111 | throw new RuntimeException("Unable to upgrade SQL database, unsupported fromVersion: " + fromVersion); |
115 | 112 | } |
116 | 113 | } |
114 | + | |
115 | + private void loadSql(Path sqlFile, Connection conn) throws Exception { | |
116 | + String sql = new String(Files.readAllBytes(sqlFile), Charset.forName("UTF-8")); | |
117 | + conn.createStatement().execute(sql); //NOSONAR, ignoring because method used to execute thingsboard database upgrade script | |
118 | + Thread.sleep(5000); | |
119 | + } | |
117 | 120 | } | ... | ... |
... | ... | @@ -23,11 +23,13 @@ import com.google.common.util.concurrent.Futures; |
23 | 23 | import com.google.common.util.concurrent.ListenableFuture; |
24 | 24 | import com.google.common.util.concurrent.ListeningScheduledExecutorService; |
25 | 25 | import com.google.common.util.concurrent.MoreExecutors; |
26 | +import com.google.protobuf.InvalidProtocolBufferException; | |
26 | 27 | import lombok.Getter; |
27 | 28 | import lombok.extern.slf4j.Slf4j; |
28 | 29 | import org.springframework.beans.factory.annotation.Autowired; |
29 | 30 | import org.springframework.beans.factory.annotation.Value; |
30 | 31 | import org.springframework.stereotype.Service; |
32 | +import org.thingsboard.rule.engine.api.RpcError; | |
31 | 33 | import org.thingsboard.server.actors.service.ActorService; |
32 | 34 | import org.thingsboard.server.common.data.DataConstants; |
33 | 35 | import org.thingsboard.server.common.data.Device; |
... | ... | @@ -36,13 +38,19 @@ import org.thingsboard.server.common.data.id.DeviceId; |
36 | 38 | import org.thingsboard.server.common.data.id.TenantId; |
37 | 39 | import org.thingsboard.server.common.data.kv.AttributeKvEntry; |
38 | 40 | import org.thingsboard.server.common.data.page.TextPageLink; |
41 | +import org.thingsboard.server.common.data.plugin.ComponentLifecycleState; | |
39 | 42 | import org.thingsboard.server.common.msg.TbMsg; |
40 | 43 | import org.thingsboard.server.common.msg.TbMsgDataType; |
41 | 44 | import org.thingsboard.server.common.msg.TbMsgMetaData; |
45 | +import org.thingsboard.server.common.msg.cluster.ServerAddress; | |
42 | 46 | import org.thingsboard.server.common.msg.system.ServiceToRuleEngineMsg; |
43 | 47 | import org.thingsboard.server.dao.attributes.AttributesService; |
44 | 48 | import org.thingsboard.server.dao.device.DeviceService; |
45 | 49 | import org.thingsboard.server.dao.tenant.TenantService; |
50 | +import org.thingsboard.server.gen.cluster.ClusterAPIProtos; | |
51 | +import org.thingsboard.server.service.cluster.routing.ClusterRoutingService; | |
52 | +import org.thingsboard.server.service.cluster.rpc.ClusterRpcService; | |
53 | +import org.thingsboard.server.service.rpc.FromDeviceRpcResponse; | |
46 | 54 | import org.thingsboard.server.service.telemetry.TelemetrySubscriptionService; |
47 | 55 | |
48 | 56 | import javax.annotation.Nullable; |
... | ... | @@ -54,6 +62,7 @@ import java.util.HashSet; |
54 | 62 | import java.util.List; |
55 | 63 | import java.util.Optional; |
56 | 64 | import java.util.Set; |
65 | +import java.util.UUID; | |
57 | 66 | import java.util.concurrent.ConcurrentHashMap; |
58 | 67 | import java.util.concurrent.ConcurrentMap; |
59 | 68 | import java.util.concurrent.ExecutionException; |
... | ... | @@ -98,6 +107,12 @@ public class DefaultDeviceStateService implements DeviceStateService { |
98 | 107 | @Autowired |
99 | 108 | private TelemetrySubscriptionService tsSubService; |
100 | 109 | |
110 | + @Autowired | |
111 | + private ClusterRoutingService routingService; | |
112 | + | |
113 | + @Autowired | |
114 | + private ClusterRpcService clusterRpcService; | |
115 | + | |
101 | 116 | @Value("${state.defaultInactivityTimeoutInSec}") |
102 | 117 | @Getter |
103 | 118 | private long defaultInactivityTimeoutInSec; |
... | ... | @@ -172,12 +187,57 @@ public class DefaultDeviceStateService implements DeviceStateService { |
172 | 187 | } |
173 | 188 | |
174 | 189 | @Override |
175 | - public Optional<DeviceState> getDeviceState(DeviceId deviceId) { | |
176 | - DeviceStateData state = deviceStates.get(deviceId); | |
177 | - if (state != null) { | |
178 | - return Optional.of(state.getState()); | |
190 | + public void onClusterUpdate() { | |
191 | + queueExecutor.submit(this::onClusterUpdateSync); | |
192 | + } | |
193 | + | |
194 | + @Override | |
195 | + public void onRemoteMsg(ServerAddress serverAddress, byte[] data) { | |
196 | + ClusterAPIProtos.DeviceStateServiceMsgProto proto; | |
197 | + try { | |
198 | + proto = ClusterAPIProtos.DeviceStateServiceMsgProto.parseFrom(data); | |
199 | + } catch (InvalidProtocolBufferException e) { | |
200 | + throw new RuntimeException(e); | |
201 | + } | |
202 | + TenantId tenantId = new TenantId(new UUID(proto.getTenantIdMSB(), proto.getTenantIdLSB())); | |
203 | + DeviceId deviceId = new DeviceId(new UUID(proto.getDeviceIdMSB(), proto.getDeviceIdLSB())); | |
204 | + if (proto.getDeleted()) { | |
205 | + queueExecutor.submit(() -> onDeviceDeleted(tenantId, deviceId)); | |
179 | 206 | } else { |
180 | - return Optional.empty(); | |
207 | + Device device = deviceService.findDeviceById(deviceId); | |
208 | + if (device != null) { | |
209 | + if (proto.getAdded()) { | |
210 | + onDeviceAdded(device); | |
211 | + } else if (proto.getUpdated()) { | |
212 | + onDeviceUpdated(device); | |
213 | + } | |
214 | + } | |
215 | + } | |
216 | + } | |
217 | + | |
218 | + private void onClusterUpdateSync() { | |
219 | + List<Tenant> tenants = tenantService.findTenants(new TextPageLink(Integer.MAX_VALUE)).getData(); | |
220 | + for (Tenant tenant : tenants) { | |
221 | + List<ListenableFuture<DeviceStateData>> fetchFutures = new ArrayList<>(); | |
222 | + List<Device> devices = deviceService.findDevicesByTenantId(tenant.getId(), new TextPageLink(Integer.MAX_VALUE)).getData(); | |
223 | + for (Device device : devices) { | |
224 | + if (!routingService.resolveById(device.getId()).isPresent()) { | |
225 | + if (!deviceStates.containsKey(device.getId())) { | |
226 | + fetchFutures.add(fetchDeviceState(device)); | |
227 | + } | |
228 | + } else { | |
229 | + Set<DeviceId> tenantDeviceSet = tenantDevices.get(tenant.getId()); | |
230 | + if (tenantDeviceSet != null) { | |
231 | + tenantDeviceSet.remove(device.getId()); | |
232 | + } | |
233 | + deviceStates.remove(device.getId()); | |
234 | + } | |
235 | + } | |
236 | + try { | |
237 | + Futures.successfulAsList(fetchFutures).get().forEach(this::addDeviceUsingState); | |
238 | + } catch (InterruptedException | ExecutionException e) { | |
239 | + log.warn("Failed to init device state service from DB", e); | |
240 | + } | |
181 | 241 | } |
182 | 242 | } |
183 | 243 | |
... | ... | @@ -187,7 +247,9 @@ public class DefaultDeviceStateService implements DeviceStateService { |
187 | 247 | List<ListenableFuture<DeviceStateData>> fetchFutures = new ArrayList<>(); |
188 | 248 | List<Device> devices = deviceService.findDevicesByTenantId(tenant.getId(), new TextPageLink(Integer.MAX_VALUE)).getData(); |
189 | 249 | for (Device device : devices) { |
190 | - fetchFutures.add(fetchDeviceState(device)); | |
250 | + if (!routingService.resolveById(device.getId()).isPresent()) { | |
251 | + fetchFutures.add(fetchDeviceState(device)); | |
252 | + } | |
191 | 253 | } |
192 | 254 | try { |
193 | 255 | Futures.successfulAsList(fetchFutures).get().forEach(this::addDeviceUsingState); |
... | ... | @@ -209,7 +271,7 @@ public class DefaultDeviceStateService implements DeviceStateService { |
209 | 271 | DeviceStateData stateData = deviceStates.get(deviceId); |
210 | 272 | DeviceState state = stateData.getState(); |
211 | 273 | state.setActive(ts < state.getLastActivityTime() + state.getInactivityTimeout()); |
212 | - if (!state.isActive() && state.getLastInactivityAlarmTime() < state.getLastActivityTime()) { | |
274 | + if (!state.isActive() && (state.getLastInactivityAlarmTime() == 0L || state.getLastInactivityAlarmTime() < state.getLastActivityTime())) { | |
213 | 275 | state.setLastInactivityAlarmTime(ts); |
214 | 276 | pushRuleEngineMessage(stateData, INACTIVITY_EVENT); |
215 | 277 | saveAttribute(deviceId, INACTIVITY_ALARM_TIME, ts); |
... | ... | @@ -219,7 +281,7 @@ public class DefaultDeviceStateService implements DeviceStateService { |
219 | 281 | } |
220 | 282 | |
221 | 283 | private void onDeviceConnectSync(DeviceId deviceId) { |
222 | - DeviceStateData stateData = deviceStates.get(deviceId); | |
284 | + DeviceStateData stateData = getOrFetchDeviceStateData(deviceId); | |
223 | 285 | if (stateData != null) { |
224 | 286 | long ts = System.currentTimeMillis(); |
225 | 287 | stateData.getState().setLastConnectTime(ts); |
... | ... | @@ -229,7 +291,7 @@ public class DefaultDeviceStateService implements DeviceStateService { |
229 | 291 | } |
230 | 292 | |
231 | 293 | private void onDeviceDisconnectSync(DeviceId deviceId) { |
232 | - DeviceStateData stateData = deviceStates.get(deviceId); | |
294 | + DeviceStateData stateData = getOrFetchDeviceStateData(deviceId); | |
233 | 295 | if (stateData != null) { |
234 | 296 | long ts = System.currentTimeMillis(); |
235 | 297 | stateData.getState().setLastDisconnectTime(ts); |
... | ... | @@ -239,7 +301,7 @@ public class DefaultDeviceStateService implements DeviceStateService { |
239 | 301 | } |
240 | 302 | |
241 | 303 | private void onDeviceActivitySync(DeviceId deviceId) { |
242 | - DeviceStateData stateData = deviceStates.get(deviceId); | |
304 | + DeviceStateData stateData = getOrFetchDeviceStateData(deviceId); | |
243 | 305 | if (stateData != null) { |
244 | 306 | DeviceState state = stateData.getState(); |
245 | 307 | long ts = System.currentTimeMillis(); |
... | ... | @@ -251,6 +313,23 @@ public class DefaultDeviceStateService implements DeviceStateService { |
251 | 313 | } |
252 | 314 | } |
253 | 315 | |
316 | + private DeviceStateData getOrFetchDeviceStateData(DeviceId deviceId) { | |
317 | + DeviceStateData deviceStateData = deviceStates.get(deviceId); | |
318 | + if (deviceStateData == null) { | |
319 | + if (!routingService.resolveById(deviceId).isPresent()) { | |
320 | + Device device = deviceService.findDeviceById(deviceId); | |
321 | + if (device != null) { | |
322 | + try { | |
323 | + deviceStateData = fetchDeviceState(device).get(); | |
324 | + } catch (InterruptedException | ExecutionException e) { | |
325 | + log.debug("[{}] Failed to fetch device state!", deviceId, e); | |
326 | + } | |
327 | + } | |
328 | + } | |
329 | + } | |
330 | + return deviceStateData; | |
331 | + } | |
332 | + | |
254 | 333 | private void onInactivityTimeoutUpdate(DeviceId deviceId, long inactivityTimeout) { |
255 | 334 | if (inactivityTimeout == 0L) { |
256 | 335 | return; |
... | ... | @@ -269,37 +348,65 @@ public class DefaultDeviceStateService implements DeviceStateService { |
269 | 348 | } |
270 | 349 | |
271 | 350 | private void onDeviceAddedSync(Device device) { |
272 | - Futures.addCallback(fetchDeviceState(device), new FutureCallback<DeviceStateData>() { | |
273 | - @Override | |
274 | - public void onSuccess(@Nullable DeviceStateData state) { | |
275 | - addDeviceUsingState(state); | |
276 | - } | |
351 | + Optional<ServerAddress> address = routingService.resolveById(device.getId()); | |
352 | + if (!address.isPresent()) { | |
353 | + Futures.addCallback(fetchDeviceState(device), new FutureCallback<DeviceStateData>() { | |
354 | + @Override | |
355 | + public void onSuccess(@Nullable DeviceStateData state) { | |
356 | + addDeviceUsingState(state); | |
357 | + } | |
358 | + | |
359 | + @Override | |
360 | + public void onFailure(Throwable t) { | |
361 | + log.warn("Failed to register device to the state service", t); | |
362 | + } | |
363 | + }); | |
364 | + } else { | |
365 | + sendDeviceEvent(device.getTenantId(), device.getId(), address.get(), true, false, false); | |
366 | + } | |
367 | + } | |
277 | 368 | |
278 | - @Override | |
279 | - public void onFailure(Throwable t) { | |
280 | - log.warn("Failed to register device to the state service", t); | |
281 | - } | |
282 | - }); | |
369 | + private void sendDeviceEvent(TenantId tenantId, DeviceId deviceId, ServerAddress address, boolean added, boolean updated, boolean deleted) { | |
370 | + log.trace("[{}][{}] Device is monitored on other server: {}", tenantId, deviceId, address); | |
371 | + ClusterAPIProtos.DeviceStateServiceMsgProto.Builder builder = ClusterAPIProtos.DeviceStateServiceMsgProto.newBuilder(); | |
372 | + builder.setTenantIdMSB(tenantId.getId().getMostSignificantBits()); | |
373 | + builder.setTenantIdLSB(tenantId.getId().getLeastSignificantBits()); | |
374 | + builder.setDeviceIdMSB(deviceId.getId().getMostSignificantBits()); | |
375 | + builder.setDeviceIdLSB(deviceId.getId().getLeastSignificantBits()); | |
376 | + builder.setAdded(added); | |
377 | + builder.setUpdated(updated); | |
378 | + builder.setDeleted(deleted); | |
379 | + clusterRpcService.tell(address, ClusterAPIProtos.MessageType.CLUSTER_DEVICE_STATE_SERVICE_MESSAGE, builder.build().toByteArray()); | |
283 | 380 | } |
284 | 381 | |
285 | 382 | private void onDeviceUpdatedSync(Device device) { |
286 | - DeviceStateData stateData = deviceStates.get(device.getId()); | |
287 | - if (stateData != null) { | |
288 | - TbMsgMetaData md = new TbMsgMetaData(); | |
289 | - md.putValue("deviceName", device.getName()); | |
290 | - md.putValue("deviceType", device.getType()); | |
291 | - stateData.setMetaData(md); | |
383 | + Optional<ServerAddress> address = routingService.resolveById(device.getId()); | |
384 | + if (!address.isPresent()) { | |
385 | + DeviceStateData stateData = getOrFetchDeviceStateData(device.getId()); | |
386 | + if (stateData != null) { | |
387 | + TbMsgMetaData md = new TbMsgMetaData(); | |
388 | + md.putValue("deviceName", device.getName()); | |
389 | + md.putValue("deviceType", device.getType()); | |
390 | + stateData.setMetaData(md); | |
391 | + } | |
392 | + } else { | |
393 | + sendDeviceEvent(device.getTenantId(), device.getId(), address.get(), false, true, false); | |
292 | 394 | } |
293 | 395 | } |
294 | 396 | |
295 | 397 | private void onDeviceDeleted(TenantId tenantId, DeviceId deviceId) { |
296 | - deviceStates.remove(deviceId); | |
297 | - Set<DeviceId> deviceIds = tenantDevices.get(tenantId); | |
298 | - if (deviceIds != null) { | |
299 | - deviceIds.remove(deviceId); | |
300 | - if (deviceIds.isEmpty()) { | |
301 | - tenantDevices.remove(tenantId); | |
398 | + Optional<ServerAddress> address = routingService.resolveById(deviceId); | |
399 | + if (!address.isPresent()) { | |
400 | + deviceStates.remove(deviceId); | |
401 | + Set<DeviceId> deviceIds = tenantDevices.get(tenantId); | |
402 | + if (deviceIds != null) { | |
403 | + deviceIds.remove(deviceId); | |
404 | + if (deviceIds.isEmpty()) { | |
405 | + tenantDevices.remove(tenantId); | |
406 | + } | |
302 | 407 | } |
408 | + } else { | |
409 | + sendDeviceEvent(tenantId, deviceId, address.get(), false, false, true); | |
303 | 410 | } |
304 | 411 | } |
305 | 412 | ... | ... |
... | ... | @@ -17,6 +17,7 @@ package org.thingsboard.server.service.state; |
17 | 17 | |
18 | 18 | import org.thingsboard.server.common.data.Device; |
19 | 19 | import org.thingsboard.server.common.data.id.DeviceId; |
20 | +import org.thingsboard.server.common.msg.cluster.ServerAddress; | |
20 | 21 | |
21 | 22 | import java.util.Optional; |
22 | 23 | |
... | ... | @@ -39,6 +40,7 @@ public interface DeviceStateService { |
39 | 40 | |
40 | 41 | void onDeviceInactivityTimeoutUpdate(DeviceId deviceId, long inactivityTimeout); |
41 | 42 | |
42 | - Optional<DeviceState> getDeviceState(DeviceId deviceId); | |
43 | + void onClusterUpdate(); | |
43 | 44 | |
45 | + void onRemoteMsg(ServerAddress serverAddress, byte[] bytes); | |
44 | 46 | } | ... | ... |
... | ... | @@ -362,7 +362,7 @@ public class DefaultTelemetrySubscriptionService implements TelemetrySubscriptio |
362 | 362 | |
363 | 363 | DonAsynchron.withCallback(tsService.findAll(entityId, queries), |
364 | 364 | missedUpdates -> { |
365 | - if (!missedUpdates.isEmpty()) { | |
365 | + if (missedUpdates != null && !missedUpdates.isEmpty()) { | |
366 | 366 | tellRemoteSubUpdate(address, sessionId, new SubscriptionUpdate(subscription.getSubscriptionId(), missedUpdates)); |
367 | 367 | } |
368 | 368 | }, | ... | ... |
... | ... | @@ -57,6 +57,8 @@ enum MessageType { |
57 | 57 | CLUSTER_TELEMETRY_ATTR_UPDATE_MESSAGE = 10; |
58 | 58 | CLUSTER_TELEMETRY_TS_UPDATE_MESSAGE = 11; |
59 | 59 | CLUSTER_RPC_FROM_DEVICE_RESPONSE_MESSAGE = 12; |
60 | + | |
61 | + CLUSTER_DEVICE_STATE_SERVICE_MESSAGE = 13; | |
60 | 62 | } |
61 | 63 | |
62 | 64 | // Messages related to CLUSTER_TELEMETRY_MESSAGE |
... | ... | @@ -128,3 +130,13 @@ message FromDeviceRPCResponseProto { |
128 | 130 | string response = 3; |
129 | 131 | int32 error = 4; |
130 | 132 | } |
133 | + | |
134 | +message DeviceStateServiceMsgProto { | |
135 | + int64 tenantIdMSB = 1; | |
136 | + int64 tenantIdLSB = 2; | |
137 | + int64 deviceIdMSB = 3; | |
138 | + int64 deviceIdLSB = 4; | |
139 | + bool added = 5; | |
140 | + bool updated = 6; | |
141 | + bool deleted = 7; | |
142 | +} | |
\ No newline at end of file | ... | ... |
... | ... | @@ -64,6 +64,7 @@ public abstract class BaseHttpDeviceApiTest extends AbstractControllerTest { |
64 | 64 | mockMvc.perform( |
65 | 65 | asyncDispatch(doPost("/api/v1/" + deviceCredentials.getCredentialsId() + "/attributes", attrMap, new String[]{}).andReturn())) |
66 | 66 | .andExpect(status().isOk()); |
67 | + Thread.sleep(2000); | |
67 | 68 | doGetAsync("/api/v1/" + deviceCredentials.getCredentialsId() + "/attributes?clientKeys=keyA,keyB,keyC").andExpect(status().isOk()); |
68 | 69 | } |
69 | 70 | ... | ... |
... | ... | @@ -98,6 +98,7 @@ public class DashboardInfo extends SearchTextBased<DashboardId> implements HasNa |
98 | 98 | public boolean updateAssignedCustomer(Customer customer) { |
99 | 99 | ShortCustomerInfo customerInfo = customer.toShortCustomerInfo(); |
100 | 100 | if (this.assignedCustomers != null && this.assignedCustomers.contains(customerInfo)) { |
101 | + this.assignedCustomers.remove(customerInfo); | |
101 | 102 | this.assignedCustomers.add(customerInfo); |
102 | 103 | return true; |
103 | 104 | } else { | ... | ... |
... | ... | @@ -15,11 +15,13 @@ |
15 | 15 | */ |
16 | 16 | package org.thingsboard.server.common.transport; |
17 | 17 | |
18 | -import org.thingsboard.server.common.data.security.DeviceCredentialsFilter; | |
18 | +import org.thingsboard.server.common.data.Device; | |
19 | 19 | import org.thingsboard.server.common.msg.aware.SessionAwareMsg; |
20 | 20 | |
21 | 21 | public interface SessionMsgProcessor { |
22 | 22 | |
23 | 23 | void process(SessionAwareMsg msg); |
24 | 24 | |
25 | + void onDeviceAdded(Device device); | |
26 | + | |
25 | 27 | } | ... | ... |
... | ... | @@ -67,9 +67,9 @@ public abstract class AbstractCassandraCluster { |
67 | 67 | private long initTimeout; |
68 | 68 | @Value("${cassandra.init_retry_interval_ms}") |
69 | 69 | private long initRetryInterval; |
70 | - @Value("${cassandra.max_requests_per_connection_local:128}") | |
70 | + @Value("${cassandra.max_requests_per_connection_local:32768}") | |
71 | 71 | private int max_requests_local; |
72 | - @Value("${cassandra.max_requests_per_connection_remote:128}") | |
72 | + @Value("${cassandra.max_requests_per_connection_remote:32768}") | |
73 | 73 | private int max_requests_remote; |
74 | 74 | |
75 | 75 | @Autowired | ... | ... |
... | ... | @@ -19,12 +19,12 @@ |
19 | 19 | <modelVersion>4.0.0</modelVersion> |
20 | 20 | <parent> |
21 | 21 | <groupId>org.thingsboard</groupId> |
22 | - <version>2.0.1</version> | |
22 | + <version>2.0.2</version> | |
23 | 23 | <artifactId>thingsboard</artifactId> |
24 | 24 | </parent> |
25 | 25 | <groupId>org.thingsboard</groupId> |
26 | 26 | <artifactId>netty-mqtt</artifactId> |
27 | - <version>2.0.1</version> | |
27 | + <version>2.0.2</version> | |
28 | 28 | <packaging>jar</packaging> |
29 | 29 | |
30 | 30 | <name>Netty MQTT Client</name> | ... | ... |
... | ... | @@ -98,33 +98,25 @@ final class MqttChannelHandler extends SimpleChannelInboundHandler<MqttMessage> |
98 | 98 | } |
99 | 99 | |
100 | 100 | private void invokeHandlersForIncomingPublish(MqttPublishMessage message) { |
101 | - for (MqttSubscribtion subscribtion : ImmutableSet.copyOf(this.client.getSubscriptions().values())) { | |
102 | - if (subscribtion.matches(message.variableHeader().topicName())) { | |
103 | - if (subscribtion.isOnce() && subscribtion.isCalled()) { | |
101 | + boolean handlerInvoked = false; | |
102 | + for (MqttSubscription subscription : ImmutableSet.copyOf(this.client.getSubscriptions().values())) { | |
103 | + if (subscription.matches(message.variableHeader().topicName())) { | |
104 | + if (subscription.isOnce() && subscription.isCalled()) { | |
104 | 105 | continue; |
105 | 106 | } |
106 | 107 | message.payload().markReaderIndex(); |
107 | - subscribtion.setCalled(true); | |
108 | - subscribtion.getHandler().onMessage(message.variableHeader().topicName(), message.payload()); | |
109 | - if (subscribtion.isOnce()) { | |
110 | - this.client.off(subscribtion.getTopic(), subscribtion.getHandler()); | |
108 | + subscription.setCalled(true); | |
109 | + subscription.getHandler().onMessage(message.variableHeader().topicName(), message.payload()); | |
110 | + if (subscription.isOnce()) { | |
111 | + this.client.off(subscription.getTopic(), subscription.getHandler()); | |
111 | 112 | } |
112 | 113 | message.payload().resetReaderIndex(); |
114 | + handlerInvoked = true; | |
113 | 115 | } |
114 | 116 | } |
115 | - /*Set<MqttSubscribtion> subscribtions = ImmutableSet.copyOf(this.client.getSubscriptions().get(message.variableHeader().topicName())); | |
116 | - for (MqttSubscribtion subscribtion : subscribtions) { | |
117 | - if(subscribtion.isOnce() && subscribtion.isCalled()){ | |
118 | - continue; | |
119 | - } | |
120 | - message.payload().markReaderIndex(); | |
121 | - subscribtion.setCalled(true); | |
122 | - subscribtion.getHandler().onMessage(message.variableHeader().topicName(), message.payload()); | |
123 | - if(subscribtion.isOnce()){ | |
124 | - this.client.off(subscribtion.getTopic(), subscribtion.getHandler()); | |
125 | - } | |
126 | - message.payload().resetReaderIndex(); | |
127 | - }*/ | |
117 | + if (!handlerInvoked && client.getDefaultHandler() != null) { | |
118 | + client.getDefaultHandler().onMessage(message.variableHeader().topicName(), message.payload()); | |
119 | + } | |
128 | 120 | message.payload().release(); |
129 | 121 | } |
130 | 122 | |
... | ... | @@ -133,7 +125,7 @@ final class MqttChannelHandler extends SimpleChannelInboundHandler<MqttMessage> |
133 | 125 | case CONNECTION_ACCEPTED: |
134 | 126 | this.connectFuture.setSuccess(new MqttConnectResult(true, MqttConnectReturnCode.CONNECTION_ACCEPTED, channel.closeFuture())); |
135 | 127 | |
136 | - this.client.getPendingSubscribtions().entrySet().stream().filter((e) -> !e.getValue().isSent()).forEach((e) -> { | |
128 | + this.client.getPendingSubscriptions().entrySet().stream().filter((e) -> !e.getValue().isSent()).forEach((e) -> { | |
137 | 129 | channel.write(e.getValue().getSubscribeMessage()); |
138 | 130 | e.getValue().setSent(true); |
139 | 131 | }); |
... | ... | @@ -148,6 +140,9 @@ final class MqttChannelHandler extends SimpleChannelInboundHandler<MqttMessage> |
148 | 140 | } |
149 | 141 | }); |
150 | 142 | channel.flush(); |
143 | + if (this.client.isReconnect()) { | |
144 | + this.client.onSuccessfulReconnect(); | |
145 | + } | |
151 | 146 | break; |
152 | 147 | |
153 | 148 | case CONNECTION_REFUSED_BAD_USER_NAME_OR_PASSWORD: |
... | ... | @@ -163,19 +158,19 @@ final class MqttChannelHandler extends SimpleChannelInboundHandler<MqttMessage> |
163 | 158 | } |
164 | 159 | |
165 | 160 | private void handleSubAck(MqttSubAckMessage message) { |
166 | - MqttPendingSubscribtion pendingSubscription = this.client.getPendingSubscribtions().remove(message.variableHeader().messageId()); | |
161 | + MqttPendingSubscription pendingSubscription = this.client.getPendingSubscriptions().remove(message.variableHeader().messageId()); | |
167 | 162 | if (pendingSubscription == null) { |
168 | 163 | return; |
169 | 164 | } |
170 | 165 | pendingSubscription.onSubackReceived(); |
171 | - for (MqttPendingSubscribtion.MqttPendingHandler handler : pendingSubscription.getHandlers()) { | |
172 | - MqttSubscribtion subscribtion = new MqttSubscribtion(pendingSubscription.getTopic(), handler.getHandler(), handler.isOnce()); | |
173 | - this.client.getSubscriptions().put(pendingSubscription.getTopic(), subscribtion); | |
174 | - this.client.getHandlerToSubscribtion().put(handler.getHandler(), subscribtion); | |
166 | + for (MqttPendingSubscription.MqttPendingHandler handler : pendingSubscription.getHandlers()) { | |
167 | + MqttSubscription subscription = new MqttSubscription(pendingSubscription.getTopic(), handler.getHandler(), handler.isOnce()); | |
168 | + this.client.getSubscriptions().put(pendingSubscription.getTopic(), subscription); | |
169 | + this.client.getHandlerToSubscribtion().put(handler.getHandler(), subscription); | |
175 | 170 | } |
176 | 171 | this.client.getPendingSubscribeTopics().remove(pendingSubscription.getTopic()); |
177 | 172 | |
178 | - this.client.getServerSubscribtions().add(pendingSubscription.getTopic()); | |
173 | + this.client.getServerSubscriptions().add(pendingSubscription.getTopic()); | |
179 | 174 | |
180 | 175 | if (!pendingSubscription.getFuture().isDone()) { |
181 | 176 | pendingSubscription.getFuture().setSuccess(null); |
... | ... | @@ -215,13 +210,13 @@ final class MqttChannelHandler extends SimpleChannelInboundHandler<MqttMessage> |
215 | 210 | } |
216 | 211 | |
217 | 212 | private void handleUnsuback(MqttUnsubAckMessage message) { |
218 | - MqttPendingUnsubscribtion unsubscribtion = this.client.getPendingServerUnsubscribes().get(message.variableHeader().messageId()); | |
219 | - if (unsubscribtion == null) { | |
213 | + MqttPendingUnsubscription unsubscription = this.client.getPendingServerUnsubscribes().get(message.variableHeader().messageId()); | |
214 | + if (unsubscription == null) { | |
220 | 215 | return; |
221 | 216 | } |
222 | - unsubscribtion.onUnsubackReceived(); | |
223 | - this.client.getServerSubscribtions().remove(unsubscribtion.getTopic()); | |
224 | - unsubscribtion.getFuture().setSuccess(null); | |
217 | + unsubscription.onUnsubackReceived(); | |
218 | + this.client.getServerSubscriptions().remove(unsubscription.getTopic()); | |
219 | + unsubscription.getFuture().setSuccess(null); | |
225 | 220 | this.client.getPendingServerUnsubscribes().remove(message.variableHeader().messageId()); |
226 | 221 | } |
227 | 222 | ... | ... |
... | ... | @@ -92,7 +92,7 @@ public interface MqttClient { |
92 | 92 | |
93 | 93 | /** |
94 | 94 | * Subscribe on the given topic. When a message is received, MqttClient will invoke the {@link MqttHandler#onMessage(String, ByteBuf)} function of the given handler |
95 | - * This subscribtion is only once. If the MqttClient has received 1 message, the subscribtion will be removed | |
95 | + * This subscription is only once. If the MqttClient has received 1 message, the subscription will be removed | |
96 | 96 | * |
97 | 97 | * @param topic The topic filter to subscribe to |
98 | 98 | * @param handler The handler to invoke when we receive a message |
... | ... | @@ -102,7 +102,7 @@ public interface MqttClient { |
102 | 102 | |
103 | 103 | /** |
104 | 104 | * Subscribe on the given topic, with the given qos. When a message is received, MqttClient will invoke the {@link MqttHandler#onMessage(String, ByteBuf)} function of the given handler |
105 | - * This subscribtion is only once. If the MqttClient has received 1 message, the subscribtion will be removed | |
105 | + * This subscription is only once. If the MqttClient has received 1 message, the subscription will be removed | |
106 | 106 | * |
107 | 107 | * @param topic The topic filter to subscribe to |
108 | 108 | * @param handler The handler to invoke when we receive a message |
... | ... | @@ -112,7 +112,7 @@ public interface MqttClient { |
112 | 112 | Future<Void> once(String topic, MqttHandler handler, MqttQoS qos); |
113 | 113 | |
114 | 114 | /** |
115 | - * Remove the subscribtion for the given topic and handler | |
115 | + * Remove the subscription for the given topic and handler | |
116 | 116 | * If you want to unsubscribe from all handlers known for this topic, use {@link #off(String)} |
117 | 117 | * |
118 | 118 | * @param topic The topic to unsubscribe for |
... | ... | @@ -122,7 +122,7 @@ public interface MqttClient { |
122 | 122 | Future<Void> off(String topic, MqttHandler handler); |
123 | 123 | |
124 | 124 | /** |
125 | - * Remove all subscribtions for the given topic. | |
125 | + * Remove all subscriptions for the given topic. | |
126 | 126 | * If you want to specify which handler to unsubscribe, use {@link #off(String, MqttHandler)} |
127 | 127 | * |
128 | 128 | * @param topic The topic to unsubscribe for |
... | ... | @@ -172,24 +172,18 @@ public interface MqttClient { |
172 | 172 | */ |
173 | 173 | MqttClientConfig getClientConfig(); |
174 | 174 | |
175 | - /** | |
176 | - * Construct the MqttClientImpl with default config | |
177 | - */ | |
178 | - static MqttClient create(){ | |
179 | - return new MqttClientImpl(); | |
180 | - } | |
181 | 175 | |
182 | 176 | /** |
183 | 177 | * Construct the MqttClientImpl with additional config. |
184 | 178 | * This config can also be changed using the {@link #getClientConfig()} function |
185 | 179 | * |
186 | 180 | * @param config The config object to use while looking for settings |
181 | + * @param defaultHandler The handler for incoming messages that do not match any topic subscriptions | |
187 | 182 | */ |
188 | - static MqttClient create(MqttClientConfig config){ | |
189 | - return new MqttClientImpl(config); | |
183 | + static MqttClient create(MqttClientConfig config, MqttHandler defaultHandler){ | |
184 | + return new MqttClientImpl(config, defaultHandler); | |
190 | 185 | } |
191 | 186 | |
192 | - | |
193 | 187 | /** |
194 | 188 | * Send disconnect and close channel |
195 | 189 | * | ... | ... |
... | ... | @@ -15,6 +15,8 @@ |
15 | 15 | */ |
16 | 16 | package org.thingsboard.mqtt; |
17 | 17 | |
18 | +import io.netty.channel.ChannelId; | |
19 | + | |
18 | 20 | /** |
19 | 21 | * Created by Valerii Sosliuk on 12/30/2017. |
20 | 22 | */ |
... | ... | @@ -25,5 +27,11 @@ public interface MqttClientCallback { |
25 | 27 | * |
26 | 28 | * @param cause the reason behind the loss of connection. |
27 | 29 | */ |
28 | - public void connectionLost(Throwable cause); | |
30 | + void connectionLost(Throwable cause); | |
31 | + | |
32 | + /** | |
33 | + * This method is called when the connection to the server is recovered. | |
34 | + * | |
35 | + */ | |
36 | + void onSuccessfulReconnect(); | |
29 | 37 | } | ... | ... |
... | ... | @@ -40,23 +40,26 @@ import java.util.concurrent.atomic.AtomicInteger; |
40 | 40 | @SuppressWarnings({"WeakerAccess", "unused"}) |
41 | 41 | final class MqttClientImpl implements MqttClient { |
42 | 42 | |
43 | - private final Set<String> serverSubscribtions = new HashSet<>(); | |
44 | - private final IntObjectHashMap<MqttPendingUnsubscribtion> pendingServerUnsubscribes = new IntObjectHashMap<>(); | |
43 | + private final Set<String> serverSubscriptions = new HashSet<>(); | |
44 | + private final IntObjectHashMap<MqttPendingUnsubscription> pendingServerUnsubscribes = new IntObjectHashMap<>(); | |
45 | 45 | private final IntObjectHashMap<MqttIncomingQos2Publish> qos2PendingIncomingPublishes = new IntObjectHashMap<>(); |
46 | 46 | private final IntObjectHashMap<MqttPendingPublish> pendingPublishes = new IntObjectHashMap<>(); |
47 | - private final HashMultimap<String, MqttSubscribtion> subscriptions = HashMultimap.create(); | |
48 | - private final IntObjectHashMap<MqttPendingSubscribtion> pendingSubscribtions = new IntObjectHashMap<>(); | |
47 | + private final HashMultimap<String, MqttSubscription> subscriptions = HashMultimap.create(); | |
48 | + private final IntObjectHashMap<MqttPendingSubscription> pendingSubscriptions = new IntObjectHashMap<>(); | |
49 | 49 | private final Set<String> pendingSubscribeTopics = new HashSet<>(); |
50 | - private final HashMultimap<MqttHandler, MqttSubscribtion> handlerToSubscribtion = HashMultimap.create(); | |
50 | + private final HashMultimap<MqttHandler, MqttSubscription> handlerToSubscribtion = HashMultimap.create(); | |
51 | 51 | private final AtomicInteger nextMessageId = new AtomicInteger(1); |
52 | 52 | |
53 | 53 | private final MqttClientConfig clientConfig; |
54 | 54 | |
55 | + private final MqttHandler defaultHandler; | |
56 | + | |
55 | 57 | private EventLoopGroup eventLoop; |
56 | 58 | |
57 | - private Channel channel; | |
59 | + private volatile Channel channel; | |
58 | 60 | |
59 | - private boolean disconnected = false; | |
61 | + private volatile boolean disconnected = false; | |
62 | + private volatile boolean reconnect = false; | |
60 | 63 | private String host; |
61 | 64 | private int port; |
62 | 65 | private MqttClientCallback callback; |
... | ... | @@ -65,8 +68,9 @@ final class MqttClientImpl implements MqttClient { |
65 | 68 | /** |
66 | 69 | * Construct the MqttClientImpl with default config |
67 | 70 | */ |
68 | - public MqttClientImpl() { | |
71 | + public MqttClientImpl(MqttHandler defaultHandler) { | |
69 | 72 | this.clientConfig = new MqttClientConfig(); |
73 | + this.defaultHandler = defaultHandler; | |
70 | 74 | } |
71 | 75 | |
72 | 76 | /** |
... | ... | @@ -75,8 +79,9 @@ final class MqttClientImpl implements MqttClient { |
75 | 79 | * |
76 | 80 | * @param clientConfig The config object to use while looking for settings |
77 | 81 | */ |
78 | - public MqttClientImpl(MqttClientConfig clientConfig) { | |
82 | + public MqttClientImpl(MqttClientConfig clientConfig, MqttHandler defaultHandler) { | |
79 | 83 | this.clientConfig = clientConfig; |
84 | + this.defaultHandler = defaultHandler; | |
80 | 85 | } |
81 | 86 | |
82 | 87 | /** |
... | ... | @@ -100,12 +105,15 @@ final class MqttClientImpl implements MqttClient { |
100 | 105 | */ |
101 | 106 | @Override |
102 | 107 | public Future<MqttConnectResult> connect(String host, int port) { |
108 | + return connect(host, port, false); | |
109 | + } | |
110 | + | |
111 | + private Future<MqttConnectResult> connect(String host, int port, boolean reconnect) { | |
103 | 112 | if (this.eventLoop == null) { |
104 | 113 | this.eventLoop = new NioEventLoopGroup(); |
105 | 114 | } |
106 | 115 | this.host = host; |
107 | 116 | this.port = port; |
108 | - | |
109 | 117 | Promise<MqttConnectResult> connectFuture = new DefaultPromise<>(this.eventLoop.next()); |
110 | 118 | Bootstrap bootstrap = new Bootstrap(); |
111 | 119 | bootstrap.group(this.eventLoop); |
... | ... | @@ -113,22 +121,47 @@ final class MqttClientImpl implements MqttClient { |
113 | 121 | bootstrap.remoteAddress(host, port); |
114 | 122 | bootstrap.handler(new MqttChannelInitializer(connectFuture, host, port, clientConfig.getSslContext())); |
115 | 123 | ChannelFuture future = bootstrap.connect(); |
124 | + | |
116 | 125 | future.addListener((ChannelFutureListener) f -> { |
117 | 126 | if (f.isSuccess()) { |
118 | 127 | MqttClientImpl.this.channel = f.channel(); |
119 | - } else if (clientConfig.isReconnect() && !disconnected) { | |
120 | - eventLoop.schedule((Runnable) () -> connect(host, port), 1L, TimeUnit.SECONDS); | |
128 | + MqttClientImpl.this.channel.closeFuture().addListener((ChannelFutureListener) channelFuture -> { | |
129 | + if (isConnected()) { | |
130 | + return; | |
131 | + } | |
132 | + ChannelClosedException e = new ChannelClosedException("Channel is closed!"); | |
133 | + if (callback != null) { | |
134 | + callback.connectionLost(e); | |
135 | + } | |
136 | + pendingSubscriptions.clear(); | |
137 | + serverSubscriptions.clear(); | |
138 | + subscriptions.clear(); | |
139 | + pendingServerUnsubscribes.clear(); | |
140 | + qos2PendingIncomingPublishes.clear(); | |
141 | + pendingPublishes.clear(); | |
142 | + pendingSubscribeTopics.clear(); | |
143 | + handlerToSubscribtion.clear(); | |
144 | + scheduleConnectIfRequired(host, port, true); | |
145 | + }); | |
146 | + } else { | |
147 | + scheduleConnectIfRequired(host, port, reconnect); | |
121 | 148 | } |
122 | 149 | }); |
123 | 150 | return connectFuture; |
124 | 151 | } |
125 | 152 | |
153 | + private void scheduleConnectIfRequired(String host, int port, boolean reconnect) { | |
154 | + if (clientConfig.isReconnect() && !disconnected) { | |
155 | + if (reconnect) { | |
156 | + this.reconnect = true; | |
157 | + } | |
158 | + eventLoop.schedule((Runnable) () -> connect(host, port, reconnect), 1L, TimeUnit.SECONDS); | |
159 | + } | |
160 | + } | |
161 | + | |
126 | 162 | @Override |
127 | 163 | public boolean isConnected() { |
128 | - if (!disconnected) { | |
129 | - return channel == null ? false : channel.isActive(); | |
130 | - }; | |
131 | - return false; | |
164 | + return !disconnected && channel != null && channel.isActive(); | |
132 | 165 | } |
133 | 166 | |
134 | 167 | @Override |
... | ... | @@ -183,12 +216,12 @@ final class MqttClientImpl implements MqttClient { |
183 | 216 | */ |
184 | 217 | @Override |
185 | 218 | public Future<Void> on(String topic, MqttHandler handler, MqttQoS qos) { |
186 | - return createSubscribtion(topic, handler, false, qos); | |
219 | + return createSubscription(topic, handler, false, qos); | |
187 | 220 | } |
188 | 221 | |
189 | 222 | /** |
190 | 223 | * Subscribe on the given topic. When a message is received, MqttClient will invoke the {@link MqttHandler#onMessage(String, ByteBuf)} function of the given handler |
191 | - * This subscribtion is only once. If the MqttClient has received 1 message, the subscribtion will be removed | |
224 | + * This subscription is only once. If the MqttClient has received 1 message, the subscription will be removed | |
192 | 225 | * |
193 | 226 | * @param topic The topic filter to subscribe to |
194 | 227 | * @param handler The handler to invoke when we receive a message |
... | ... | @@ -201,7 +234,7 @@ final class MqttClientImpl implements MqttClient { |
201 | 234 | |
202 | 235 | /** |
203 | 236 | * Subscribe on the given topic, with the given qos. When a message is received, MqttClient will invoke the {@link MqttHandler#onMessage(String, ByteBuf)} function of the given handler |
204 | - * This subscribtion is only once. If the MqttClient has received 1 message, the subscribtion will be removed | |
237 | + * This subscription is only once. If the MqttClient has received 1 message, the subscription will be removed | |
205 | 238 | * |
206 | 239 | * @param topic The topic filter to subscribe to |
207 | 240 | * @param handler The handler to invoke when we receive a message |
... | ... | @@ -210,11 +243,11 @@ final class MqttClientImpl implements MqttClient { |
210 | 243 | */ |
211 | 244 | @Override |
212 | 245 | public Future<Void> once(String topic, MqttHandler handler, MqttQoS qos) { |
213 | - return createSubscribtion(topic, handler, true, qos); | |
246 | + return createSubscription(topic, handler, true, qos); | |
214 | 247 | } |
215 | 248 | |
216 | 249 | /** |
217 | - * Remove the subscribtion for the given topic and handler | |
250 | + * Remove the subscription for the given topic and handler | |
218 | 251 | * If you want to unsubscribe from all handlers known for this topic, use {@link #off(String)} |
219 | 252 | * |
220 | 253 | * @param topic The topic to unsubscribe for |
... | ... | @@ -224,8 +257,8 @@ final class MqttClientImpl implements MqttClient { |
224 | 257 | @Override |
225 | 258 | public Future<Void> off(String topic, MqttHandler handler) { |
226 | 259 | Promise<Void> future = new DefaultPromise<>(this.eventLoop.next()); |
227 | - for (MqttSubscribtion subscribtion : this.handlerToSubscribtion.get(handler)) { | |
228 | - this.subscriptions.remove(topic, subscribtion); | |
260 | + for (MqttSubscription subscription : this.handlerToSubscribtion.get(handler)) { | |
261 | + this.subscriptions.remove(topic, subscription); | |
229 | 262 | } |
230 | 263 | this.handlerToSubscribtion.removeAll(handler); |
231 | 264 | this.checkSubscribtions(topic, future); |
... | ... | @@ -233,7 +266,7 @@ final class MqttClientImpl implements MqttClient { |
233 | 266 | } |
234 | 267 | |
235 | 268 | /** |
236 | - * Remove all subscribtions for the given topic. | |
269 | + * Remove all subscriptions for the given topic. | |
237 | 270 | * If you want to specify which handler to unsubscribe, use {@link #off(String, MqttHandler)} |
238 | 271 | * |
239 | 272 | * @param topic The topic to unsubscribe for |
... | ... | @@ -242,12 +275,12 @@ final class MqttClientImpl implements MqttClient { |
242 | 275 | @Override |
243 | 276 | public Future<Void> off(String topic) { |
244 | 277 | Promise<Void> future = new DefaultPromise<>(this.eventLoop.next()); |
245 | - ImmutableSet<MqttSubscribtion> subscribtions = ImmutableSet.copyOf(this.subscriptions.get(topic)); | |
246 | - for (MqttSubscribtion subscribtion : subscribtions) { | |
247 | - for (MqttSubscribtion handSub : this.handlerToSubscribtion.get(subscribtion.getHandler())) { | |
278 | + ImmutableSet<MqttSubscription> subscriptions = ImmutableSet.copyOf(this.subscriptions.get(topic)); | |
279 | + for (MqttSubscription subscription : subscriptions) { | |
280 | + for (MqttSubscription handSub : this.handlerToSubscribtion.get(subscription.getHandler())) { | |
248 | 281 | this.subscriptions.remove(topic, handSub); |
249 | 282 | } |
250 | - this.handlerToSubscribtion.remove(subscribtion.getHandler(), subscribtion); | |
283 | + this.handlerToSubscribtion.remove(subscription.getHandler(), subscription); | |
251 | 284 | } |
252 | 285 | this.checkSubscribtions(topic, future); |
253 | 286 | return future; |
... | ... | @@ -310,7 +343,7 @@ final class MqttClientImpl implements MqttClient { |
310 | 343 | ChannelFuture channelFuture = this.sendAndFlushPacket(message); |
311 | 344 | |
312 | 345 | if (channelFuture != null) { |
313 | - pendingPublish.setSent(channelFuture != null); | |
346 | + pendingPublish.setSent(true); | |
314 | 347 | if (channelFuture.cause() != null) { |
315 | 348 | future.setFailure(channelFuture.cause()); |
316 | 349 | return future; |
... | ... | @@ -352,6 +385,15 @@ final class MqttClientImpl implements MqttClient { |
352 | 385 | |
353 | 386 | ///////////////////////////////////////////// PRIVATE API ///////////////////////////////////////////// |
354 | 387 | |
388 | + public boolean isReconnect() { | |
389 | + return reconnect; | |
390 | + } | |
391 | + | |
392 | + public void onSuccessfulReconnect() { | |
393 | + callback.onSuccessfulReconnect(); | |
394 | + } | |
395 | + | |
396 | + | |
355 | 397 | ChannelFuture sendAndFlushPacket(Object message) { |
356 | 398 | if (this.channel == null) { |
357 | 399 | return null; |
... | ... | @@ -359,11 +401,7 @@ final class MqttClientImpl implements MqttClient { |
359 | 401 | if (this.channel.isActive()) { |
360 | 402 | return this.channel.writeAndFlush(message); |
361 | 403 | } |
362 | - ChannelClosedException e = new ChannelClosedException("Channel is closed"); | |
363 | - if (callback != null) { | |
364 | - callback.connectionLost(e); | |
365 | - } | |
366 | - return this.channel.newFailedFuture(e); | |
404 | + return this.channel.newFailedFuture(new ChannelClosedException("Channel is closed!")); | |
367 | 405 | } |
368 | 406 | |
369 | 407 | private MqttMessageIdVariableHeader getNewMessageId() { |
... | ... | @@ -371,18 +409,18 @@ final class MqttClientImpl implements MqttClient { |
371 | 409 | return MqttMessageIdVariableHeader.from(this.nextMessageId.getAndIncrement()); |
372 | 410 | } |
373 | 411 | |
374 | - private Future<Void> createSubscribtion(String topic, MqttHandler handler, boolean once, MqttQoS qos) { | |
412 | + private Future<Void> createSubscription(String topic, MqttHandler handler, boolean once, MqttQoS qos) { | |
375 | 413 | if (this.pendingSubscribeTopics.contains(topic)) { |
376 | - Optional<Map.Entry<Integer, MqttPendingSubscribtion>> subscribtionEntry = this.pendingSubscribtions.entrySet().stream().filter((e) -> e.getValue().getTopic().equals(topic)).findAny(); | |
377 | - if (subscribtionEntry.isPresent()) { | |
378 | - subscribtionEntry.get().getValue().addHandler(handler, once); | |
379 | - return subscribtionEntry.get().getValue().getFuture(); | |
414 | + Optional<Map.Entry<Integer, MqttPendingSubscription>> subscriptionEntry = this.pendingSubscriptions.entrySet().stream().filter((e) -> e.getValue().getTopic().equals(topic)).findAny(); | |
415 | + if (subscriptionEntry.isPresent()) { | |
416 | + subscriptionEntry.get().getValue().addHandler(handler, once); | |
417 | + return subscriptionEntry.get().getValue().getFuture(); | |
380 | 418 | } |
381 | 419 | } |
382 | - if (this.serverSubscribtions.contains(topic)) { | |
383 | - MqttSubscribtion subscribtion = new MqttSubscribtion(topic, handler, once); | |
384 | - this.subscriptions.put(topic, subscribtion); | |
385 | - this.handlerToSubscribtion.put(handler, subscribtion); | |
420 | + if (this.serverSubscriptions.contains(topic)) { | |
421 | + MqttSubscription subscription = new MqttSubscription(topic, handler, once); | |
422 | + this.subscriptions.put(topic, subscription); | |
423 | + this.handlerToSubscribtion.put(handler, subscription); | |
386 | 424 | return this.channel.newSucceededFuture(); |
387 | 425 | } |
388 | 426 | |
... | ... | @@ -393,27 +431,27 @@ final class MqttClientImpl implements MqttClient { |
393 | 431 | MqttSubscribePayload payload = new MqttSubscribePayload(Collections.singletonList(subscription)); |
394 | 432 | MqttSubscribeMessage message = new MqttSubscribeMessage(fixedHeader, variableHeader, payload); |
395 | 433 | |
396 | - final MqttPendingSubscribtion pendingSubscribtion = new MqttPendingSubscribtion(future, topic, message); | |
397 | - pendingSubscribtion.addHandler(handler, once); | |
398 | - this.pendingSubscribtions.put(variableHeader.messageId(), pendingSubscribtion); | |
434 | + final MqttPendingSubscription pendingSubscription = new MqttPendingSubscription(future, topic, message); | |
435 | + pendingSubscription.addHandler(handler, once); | |
436 | + this.pendingSubscriptions.put(variableHeader.messageId(), pendingSubscription); | |
399 | 437 | this.pendingSubscribeTopics.add(topic); |
400 | - pendingSubscribtion.setSent(this.sendAndFlushPacket(message) != null); //If not sent, we will send it when the connection is opened | |
438 | + pendingSubscription.setSent(this.sendAndFlushPacket(message) != null); //If not sent, we will send it when the connection is opened | |
401 | 439 | |
402 | - pendingSubscribtion.startRetransmitTimer(this.eventLoop.next(), this::sendAndFlushPacket); | |
440 | + pendingSubscription.startRetransmitTimer(this.eventLoop.next(), this::sendAndFlushPacket); | |
403 | 441 | |
404 | 442 | return future; |
405 | 443 | } |
406 | 444 | |
407 | 445 | private void checkSubscribtions(String topic, Promise<Void> promise) { |
408 | - if (!(this.subscriptions.containsKey(topic) && this.subscriptions.get(topic).size() != 0) && this.serverSubscribtions.contains(topic)) { | |
446 | + if (!(this.subscriptions.containsKey(topic) && this.subscriptions.get(topic).size() != 0) && this.serverSubscriptions.contains(topic)) { | |
409 | 447 | MqttFixedHeader fixedHeader = new MqttFixedHeader(MqttMessageType.UNSUBSCRIBE, false, MqttQoS.AT_LEAST_ONCE, false, 0); |
410 | 448 | MqttMessageIdVariableHeader variableHeader = getNewMessageId(); |
411 | 449 | MqttUnsubscribePayload payload = new MqttUnsubscribePayload(Collections.singletonList(topic)); |
412 | 450 | MqttUnsubscribeMessage message = new MqttUnsubscribeMessage(fixedHeader, variableHeader, payload); |
413 | 451 | |
414 | - MqttPendingUnsubscribtion pendingUnsubscribtion = new MqttPendingUnsubscribtion(promise, topic, message); | |
415 | - this.pendingServerUnsubscribes.put(variableHeader.messageId(), pendingUnsubscribtion); | |
416 | - pendingUnsubscribtion.startRetransmissionTimer(this.eventLoop.next(), this::sendAndFlushPacket); | |
452 | + MqttPendingUnsubscription pendingUnsubscription = new MqttPendingUnsubscription(promise, topic, message); | |
453 | + this.pendingServerUnsubscribes.put(variableHeader.messageId(), pendingUnsubscription); | |
454 | + pendingUnsubscription.startRetransmissionTimer(this.eventLoop.next(), this::sendAndFlushPacket); | |
417 | 455 | |
418 | 456 | this.sendAndFlushPacket(message); |
419 | 457 | } else { |
... | ... | @@ -421,11 +459,11 @@ final class MqttClientImpl implements MqttClient { |
421 | 459 | } |
422 | 460 | } |
423 | 461 | |
424 | - IntObjectHashMap<MqttPendingSubscribtion> getPendingSubscribtions() { | |
425 | - return pendingSubscribtions; | |
462 | + IntObjectHashMap<MqttPendingSubscription> getPendingSubscriptions() { | |
463 | + return pendingSubscriptions; | |
426 | 464 | } |
427 | 465 | |
428 | - HashMultimap<String, MqttSubscribtion> getSubscriptions() { | |
466 | + HashMultimap<String, MqttSubscription> getSubscriptions() { | |
429 | 467 | return subscriptions; |
430 | 468 | } |
431 | 469 | |
... | ... | @@ -433,15 +471,15 @@ final class MqttClientImpl implements MqttClient { |
433 | 471 | return pendingSubscribeTopics; |
434 | 472 | } |
435 | 473 | |
436 | - HashMultimap<MqttHandler, MqttSubscribtion> getHandlerToSubscribtion() { | |
474 | + HashMultimap<MqttHandler, MqttSubscription> getHandlerToSubscribtion() { | |
437 | 475 | return handlerToSubscribtion; |
438 | 476 | } |
439 | 477 | |
440 | - Set<String> getServerSubscribtions() { | |
441 | - return serverSubscribtions; | |
478 | + Set<String> getServerSubscriptions() { | |
479 | + return serverSubscriptions; | |
442 | 480 | } |
443 | 481 | |
444 | - IntObjectHashMap<MqttPendingUnsubscribtion> getPendingServerUnsubscribes() { | |
482 | + IntObjectHashMap<MqttPendingUnsubscription> getPendingServerUnsubscribes() { | |
445 | 483 | return pendingServerUnsubscribes; |
446 | 484 | } |
447 | 485 | |
... | ... | @@ -481,4 +519,9 @@ final class MqttClientImpl implements MqttClient { |
481 | 519 | ch.pipeline().addLast("mqttHandler", new MqttChannelHandler(MqttClientImpl.this, connectFuture)); |
482 | 520 | } |
483 | 521 | } |
522 | + | |
523 | + MqttHandler getDefaultHandler() { | |
524 | + return defaultHandler; | |
525 | + } | |
526 | + | |
484 | 527 | } | ... | ... |
netty-mqtt/src/main/java/org/thingsboard/mqtt/MqttPendingSubscription.java
renamed from
netty-mqtt/src/main/java/org/thingsboard/mqtt/MqttPendingSubscribtion.java
... | ... | @@ -23,7 +23,7 @@ import java.util.HashSet; |
23 | 23 | import java.util.Set; |
24 | 24 | import java.util.function.Consumer; |
25 | 25 | |
26 | -final class MqttPendingSubscribtion { | |
26 | +final class MqttPendingSubscription { | |
27 | 27 | |
28 | 28 | private final Promise<Void> future; |
29 | 29 | private final String topic; |
... | ... | @@ -34,7 +34,7 @@ final class MqttPendingSubscribtion { |
34 | 34 | |
35 | 35 | private boolean sent = false; |
36 | 36 | |
37 | - MqttPendingSubscribtion(Promise<Void> future, String topic, MqttSubscribeMessage message) { | |
37 | + MqttPendingSubscription(Promise<Void> future, String topic, MqttSubscribeMessage message) { | |
38 | 38 | this.future = future; |
39 | 39 | this.topic = topic; |
40 | 40 | this.subscribeMessage = message; | ... | ... |
netty-mqtt/src/main/java/org/thingsboard/mqtt/MqttPendingUnsubscription.java
renamed from
netty-mqtt/src/main/java/org/thingsboard/mqtt/MqttPendingUnsubscribtion.java
... | ... | @@ -21,14 +21,14 @@ import io.netty.util.concurrent.Promise; |
21 | 21 | |
22 | 22 | import java.util.function.Consumer; |
23 | 23 | |
24 | -final class MqttPendingUnsubscribtion { | |
24 | +final class MqttPendingUnsubscription { | |
25 | 25 | |
26 | 26 | private final Promise<Void> future; |
27 | 27 | private final String topic; |
28 | 28 | |
29 | 29 | private final RetransmissionHandler<MqttUnsubscribeMessage> retransmissionHandler = new RetransmissionHandler<>(); |
30 | 30 | |
31 | - MqttPendingUnsubscribtion(Promise<Void> future, String topic, MqttUnsubscribeMessage unsubscribeMessage) { | |
31 | + MqttPendingUnsubscription(Promise<Void> future, String topic, MqttUnsubscribeMessage unsubscribeMessage) { | |
32 | 32 | this.future = future; |
33 | 33 | this.topic = topic; |
34 | 34 | ... | ... |
netty-mqtt/src/main/java/org/thingsboard/mqtt/MqttSubscription.java
renamed from
netty-mqtt/src/main/java/org/thingsboard/mqtt/MqttSubscribtion.java
... | ... | @@ -17,7 +17,7 @@ package org.thingsboard.mqtt; |
17 | 17 | |
18 | 18 | import java.util.regex.Pattern; |
19 | 19 | |
20 | -final class MqttSubscribtion { | |
20 | +final class MqttSubscription { | |
21 | 21 | |
22 | 22 | private final String topic; |
23 | 23 | private final Pattern topicRegex; |
... | ... | @@ -27,7 +27,7 @@ final class MqttSubscribtion { |
27 | 27 | |
28 | 28 | private boolean called; |
29 | 29 | |
30 | - MqttSubscribtion(String topic, MqttHandler handler, boolean once) { | |
30 | + MqttSubscription(String topic, MqttHandler handler, boolean once) { | |
31 | 31 | if(topic == null){ |
32 | 32 | throw new NullPointerException("topic"); |
33 | 33 | } |
... | ... | @@ -65,7 +65,7 @@ final class MqttSubscribtion { |
65 | 65 | if (this == o) return true; |
66 | 66 | if (o == null || getClass() != o.getClass()) return false; |
67 | 67 | |
68 | - MqttSubscribtion that = (MqttSubscribtion) o; | |
68 | + MqttSubscription that = (MqttSubscription) o; | |
69 | 69 | |
70 | 70 | return once == that.once && topic.equals(that.topic) && handler.equals(that.handler); |
71 | 71 | } | ... | ... |
... | ... | @@ -22,7 +22,7 @@ |
22 | 22 | <modelVersion>4.0.0</modelVersion> |
23 | 23 | <parent> |
24 | 24 | <groupId>org.thingsboard</groupId> |
25 | - <version>2.0.1</version> | |
25 | + <version>2.0.2</version> | |
26 | 26 | <artifactId>rule-engine</artifactId> |
27 | 27 | </parent> |
28 | 28 | <groupId>org.thingsboard.rule-engine</groupId> | ... | ... |
... | ... | @@ -22,7 +22,7 @@ |
22 | 22 | <modelVersion>4.0.0</modelVersion> |
23 | 23 | <parent> |
24 | 24 | <groupId>org.thingsboard</groupId> |
25 | - <version>2.0.1</version> | |
25 | + <version>2.0.2</version> | |
26 | 26 | <artifactId>rule-engine</artifactId> |
27 | 27 | </parent> |
28 | 28 | <groupId>org.thingsboard.rule-engine</groupId> | ... | ... |
... | ... | @@ -111,8 +111,9 @@ public class TbMqttNode implements TbNode { |
111 | 111 | if (!StringUtils.isEmpty(this.config.getClientId())) { |
112 | 112 | config.setClientId(this.config.getClientId()); |
113 | 113 | } |
114 | + config.setCleanSession(this.config.isCleanSession()); | |
114 | 115 | this.config.getCredentials().configure(config); |
115 | - MqttClient client = MqttClient.create(config); | |
116 | + MqttClient client = MqttClient.create(config, null); | |
116 | 117 | client.setEventLoop(this.eventLoopGroup); |
117 | 118 | Future<MqttConnectResult> connectFuture = client.connect(this.config.getHost(), this.config.getPort()); |
118 | 119 | MqttConnectResult result; | ... | ... |
... | ... | @@ -30,6 +30,7 @@ public class TbMqttNodeConfiguration implements NodeConfiguration<TbMqttNodeConf |
30 | 30 | private int connectTimeoutSec; |
31 | 31 | private String clientId; |
32 | 32 | |
33 | + private boolean cleanSession; | |
33 | 34 | private boolean ssl; |
34 | 35 | private MqttClientCredentials credentials; |
35 | 36 | |
... | ... | @@ -40,6 +41,7 @@ public class TbMqttNodeConfiguration implements NodeConfiguration<TbMqttNodeConf |
40 | 41 | configuration.setHost("localhost"); |
41 | 42 | configuration.setPort(1883); |
42 | 43 | configuration.setConnectTimeoutSec(10); |
44 | + configuration.setCleanSession(true); | |
43 | 45 | configuration.setSsl(false); |
44 | 46 | configuration.setCredentials(new AnonymousCredentials()); |
45 | 47 | return configuration; | ... | ... |
... | ... | @@ -16,7 +16,10 @@ |
16 | 16 | package org.thingsboard.rule.engine.rpc; |
17 | 17 | |
18 | 18 | import com.datastax.driver.core.utils.UUIDs; |
19 | +import com.fasterxml.jackson.databind.ObjectMapper; | |
20 | +import com.fasterxml.jackson.databind.JsonNode; | |
19 | 21 | import com.google.gson.Gson; |
22 | +import com.google.gson.JsonElement; | |
20 | 23 | import com.google.gson.JsonObject; |
21 | 24 | import com.google.gson.JsonParser; |
22 | 25 | import lombok.extern.slf4j.Slf4j; |
... | ... | @@ -35,6 +38,7 @@ import org.thingsboard.server.common.data.id.DeviceId; |
35 | 38 | import org.thingsboard.server.common.data.plugin.ComponentType; |
36 | 39 | import org.thingsboard.server.common.msg.TbMsg; |
37 | 40 | |
41 | +import java.io.IOException; | |
38 | 42 | import java.util.Random; |
39 | 43 | import java.util.UUID; |
40 | 44 | import java.util.concurrent.TimeUnit; |
... | ... | @@ -86,10 +90,18 @@ public class TbSendRPCRequestNode implements TbNode { |
86 | 90 | tmp = msg.getMetaData().getValue("expirationTime"); |
87 | 91 | long expirationTime = !StringUtils.isEmpty(tmp) ? Long.parseLong(tmp) : (System.currentTimeMillis() + TimeUnit.SECONDS.toMillis(config.getTimeoutInSeconds())); |
88 | 92 | |
93 | + String params; | |
94 | + JsonElement paramsEl = json.get("params"); | |
95 | + if (paramsEl.isJsonPrimitive()) { | |
96 | + params = paramsEl.getAsString(); | |
97 | + } else { | |
98 | + params = gson.toJson(paramsEl); | |
99 | + } | |
100 | + | |
89 | 101 | RuleEngineDeviceRpcRequest request = RuleEngineDeviceRpcRequest.builder() |
90 | 102 | .oneway(oneway) |
91 | 103 | .method(json.get("method").getAsString()) |
92 | - .body(gson.toJson(json.get("params"))) | |
104 | + .body(params) | |
93 | 105 | .deviceId(new DeviceId(msg.getOriginator().getId())) |
94 | 106 | .requestId(requestId) |
95 | 107 | .requestUUID(requestUUID) | ... | ... |
rule-engine/rule-engine-components/src/main/resources/public/static/rulenode/rulenode-core-config.js
1 | -!function(e){function t(a){if(n[a])return n[a].exports;var r=n[a]={exports:{},id:a,loaded:!1};return e[a].call(r.exports,r,r.exports,t),r.loaded=!0,r.exports}var n={};return t.m=e,t.c=n,t.p="/static/",t(0)}(function(e){for(var t in e)if(Object.prototype.hasOwnProperty.call(e,t))switch(typeof e[t]){case"function":break;case"object":e[t]=function(t){var n=t.slice(1),a=e[t[0]];return function(e,t,r){a.apply(this,[e,t,r].concat(n))}}(e[t]);break;default:e[t]=e[e[t]]}return e}([function(e,t,n){e.exports=n(72)},function(e,t){},1,1,1,function(e,t){e.exports=' <section ng-form name=attributesConfigForm layout=column> <md-input-container class=md-block> <label translate>attribute.attributes-scope</label> <md-select ng-model=configuration.scope ng-disabled=$root.loading> <md-option ng-repeat="scope in types.attributesScope" ng-value=scope.value> {{scope.name | translate}} </md-option> </md-select> </md-input-container> </section> '},function(e,t){e.exports=" <section class=tb-alarm-config ng-form name=alarmConfigForm layout=column> <label translate class=\"tb-title no-padding\">tb.rulenode.alarm-details-builder</label> <tb-js-func ng-model=configuration.alarmDetailsBuildJs function-name=Details function-args=\"{{ ['msg', 'metadata', 'msgType'] }}\" no-validate=true> </tb-js-func> <div layout=row style=padding-bottom:15px> <md-button ng-click=testDetailsBuildJs($event) class=\"md-primary md-raised\"> {{ 'tb.rulenode.test-details-function' | translate }} </md-button> </div> <md-input-container class=md-block> <label translate>tb.rulenode.alarm-type</label> <input ng-required=true name=alarmType ng-model=configuration.alarmType> <div ng-messages=alarmConfigForm.alarmType.$error> <div ng-message=required translate>tb.rulenode.alarm-type-required</div> </div> </md-input-container> </section> "},function(e,t){e.exports=" <section class=tb-alarm-config ng-form name=alarmConfigForm layout=column> <label translate class=\"tb-title no-padding\">tb.rulenode.alarm-details-builder</label> <tb-js-func ng-model=configuration.alarmDetailsBuildJs function-name=Details function-args=\"{{ ['msg', 'metadata', 'msgType'] }}\" no-validate=true> </tb-js-func> <div layout=row style=padding-bottom:15px> <md-button ng-click=testDetailsBuildJs($event) class=\"md-primary md-raised\"> {{ 'tb.rulenode.test-details-function' | translate }} </md-button> </div> <section layout=column layout-gt-sm=row> <md-input-container flex class=md-block> <label translate>tb.rulenode.alarm-type</label> <input ng-required=true name=alarmType ng-model=configuration.alarmType> <div ng-messages=alarmConfigForm.alarmType.$error> <div ng-message=required translate>tb.rulenode.alarm-type-required</div> </div> </md-input-container> <md-input-container flex class=md-block> <label translate>tb.rulenode.alarm-severity</label> <md-select required name=severity ng-model=configuration.severity> <md-option ng-repeat=\"(severityKey, severity) in types.alarmSeverity\" ng-value=severityKey> {{ severity.name | translate}} </md-option> </md-select> <div ng-messages=alarmConfigForm.severity.$error> <div ng-message=required translate>tb.rulenode.alarm-severity-required</div> </div> </md-input-container> </section> <md-checkbox aria-label=\"{{ 'tb.rulenode.propagate' | translate }}\" ng-model=configuration.propagate>{{ 'tb.rulenode.propagate' | translate }} </md-checkbox> </section> "},function(e,t){e.exports=" <section class=tb-generator-config ng-form name=generatorConfigForm layout=column> <md-input-container class=md-block> <label translate>tb.rulenode.message-count</label> <input ng-required=true type=number step=1 name=messageCount ng-model=configuration.msgCount min=0> <div ng-messages=generatorConfigForm.messageCount.$error multiple=multiple md-auto-hide=false> <div ng-message=required translate>tb.rulenode.message-count-required</div> <div ng-message=min translate>tb.rulenode.min-message-count-message</div> </div> </md-input-container> <md-input-container class=md-block> <label translate>tb.rulenode.period-seconds</label> <input ng-required=true type=number step=1 name=periodInSeconds ng-model=configuration.periodInSeconds min=1> <div ng-messages=generatorConfigForm.periodInSeconds.$error multiple=multiple md-auto-hide=false> <div ng-message=required translate>tb.rulenode.period-seconds-required</div> <div ng-message=min translate>tb.rulenode.min-period-seconds-message</div> </div> </md-input-container> <div layout=column> <label class=tb-small>{{ 'tb.rulenode.originator' | translate }}</label> <tb-entity-select the-form=generatorConfigForm tb-required=false ng-model=originator> </tb-entity-select> </div> <label translate class=\"tb-title no-padding\">tb.rulenode.generate</label> <tb-js-func ng-model=configuration.jsScript function-name=Generate function-args=\"{{ ['prevMsg', 'prevMetadata', 'prevMsgType'] }}\" no-validate=true> </tb-js-func> <div layout=row> <md-button ng-click=testScript($event) class=\"md-primary md-raised\"> {{ 'tb.rulenode.test-generator-function' | translate }} </md-button> </div> </section> "},function(e,t){e.exports=' <section ng-form name=kafkaConfigForm layout=column> <md-input-container class=md-block> <label translate>tb.rulenode.topic-pattern</label> <input ng-required=true name=topicPattern ng-model=configuration.topicPattern> <div ng-messages=kafkaConfigForm.topicPattern.$error> <div ng-message=required translate>tb.rulenode.topic-pattern-required</div> </div> </md-input-container> <md-input-container class=md-block> <label translate>tb.rulenode.bootstrap-servers</label> <input ng-required=true name=bootstrapServers ng-model=configuration.bootstrapServers> <div ng-messages=kafkaConfigForm.bootstrapServers.$error> <div ng-message=required translate>tb.rulenode.bootstrap-servers-required</div> </div> </md-input-container> <md-input-container class=md-block> <label translate>tb.rulenode.retries</label> <input type=number step=1 name=retries ng-model=configuration.retries min=0> <div ng-messages=kafkaConfigForm.retries.$error> <div ng-message=min translate>tb.rulenode.min-retries-message</div> </div> </md-input-container> <md-input-container class=md-block> <label translate>tb.rulenode.batch-size-bytes</label> <input type=number step=1 name=batchSize ng-model=configuration.batchSize min=0> <div ng-messages=kafkaConfigForm.batchSize.$error> <div ng-message=min translate>tb.rulenode.min-batch-size-bytes-message</div> </div> </md-input-container> <md-input-container class=md-block> <label translate>tb.rulenode.linger-ms</label> <input type=number step=1 name=linger ng-model=configuration.linger min=0> <div ng-messages=kafkaConfigForm.linger.$error> <div ng-message=min translate>tb.rulenode.min-linger-ms-message</div> </div> </md-input-container> <md-input-container class=md-block> <label translate>tb.rulenode.buffer-memory-bytes</label> <input type=number step=1 name=bufferMemory ng-model=configuration.bufferMemory min=0> <div ng-messages=kafkaConfigForm.bufferMemory.$error> <div ng-message=min translate>tb.rulenode.min-buffer-memory-bytes-message</div> </div> </md-input-container> <md-input-container class=md-block> <label translate>tb.rulenode.acks</label> <md-select ng-model=configuration.acks ng-disabled=$root.loading> <md-option ng-repeat="ackValue in ackValues" ng-value=ackValue> {{ ackValue }} </md-option> </md-select> </md-input-container> <md-input-container class=md-block> <label translate>tb.rulenode.key-serializer</label> <input ng-required=true name=keySerializer ng-model=configuration.keySerializer> <div ng-messages=kafkaConfigForm.keySerializer.$error> <div ng-message=required translate>tb.rulenode.key-serializer-required</div> </div> </md-input-container> <md-input-container class=md-block> <label translate>tb.rulenode.value-serializer</label> <input ng-required=true name=valueSerializer ng-model=configuration.valueSerializer> <div ng-messages=kafkaConfigForm.valueSerializer.$error> <div ng-message=required translate>tb.rulenode.value-serializer-required</div> </div> </md-input-container> <label translate class=tb-title>tb.rulenode.other-properties</label> <tb-kv-map-config ng-model=configuration.otherProperties ng-required=false key-text="\'tb.rulenode.key\'" key-required-text="\'tb.rulenode.key-required\'" val-text="\'tb.rulenode.value\'" val-required-text="\'tb.rulenode.value-required\'"> </tb-kv-map-config> </section> '},function(e,t){e.exports=" <section layout=column> <label translate class=\"tb-title no-padding\">tb.rulenode.to-string</label> <tb-js-func ng-model=configuration.jsScript function-name=ToString function-args=\"{{ ['msg', 'metadata', 'msgType'] }}\" no-validate=true> </tb-js-func> <div layout=row> <md-button ng-click=testScript($event) class=\"md-primary md-raised\"> {{ 'tb.rulenode.test-to-string-function' | translate }} </md-button> </div> </section> "},function(e,t){e.exports=' <section class=tb-mqtt-config ng-form name=mqttConfigForm layout=column> <md-input-container class=md-block> <label translate>tb.rulenode.topic-pattern</label> <input ng-required=true name=topicPattern ng-model=configuration.topicPattern> <div ng-messages=mqttConfigForm.topicPattern.$error> <div translate ng-message=required>tb.rulenode.topic-pattern-required</div> </div> <div class=tb-hint translate>tb.rulenode.mqtt-topic-pattern-hint</div> </md-input-container> <div flex layout=column layout-gt-sm=row> <md-input-container flex=60 class=md-block> <label translate>tb.rulenode.host</label> <input ng-required=true name=host ng-model=configuration.host> <div ng-messages=mqttConfigForm.host.$error> <div translate ng-message=required>tb.rulenode.host-required</div> </div> </md-input-container> <md-input-container flex=40 class=md-block> <label translate>tb.rulenode.port</label> <input type=number step=1 min=1 max=65535 ng-required=true name=port ng-model=configuration.port> <div ng-messages=mqttConfigForm.port.$error> <div translate ng-message=required>tb.rulenode.port-required</div> <div translate ng-message=min>tb.rulenode.port-range</div> <div translate ng-message=max>tb.rulenode.port-range</div> </div> </md-input-container> <md-input-container flex=40 class=md-block> <label translate>tb.rulenode.connect-timeout</label> <input type=number step=1 min=1 max=200 ng-required=true name=connectTimeoutSec ng-model=configuration.connectTimeoutSec> <div ng-messages=mqttConfigForm.connectTimeoutSec.$error> <div translate ng-message=required>tb.rulenode.connect-timeout-required</div> <div translate ng-message=min>tb.rulenode.connect-timeout-range</div> <div translate ng-message=max>tb.rulenode.connect-timeout-range</div> </div> </md-input-container> </div> <md-input-container class=md-block> <label translate>tb.rulenode.client-id</label> <input name=clientId ng-model=configuration.clientId> </md-input-container> <md-checkbox ng-disabled="$root.loading || readonly" aria-label="{{ \'tb.rulenode.enable-ssl\' | translate }}" ng-model=configuration.ssl> {{ \'tb.rulenode.enable-ssl\' | translate }} </md-checkbox> <md-expansion-panel-group class=tb-credentials-panel-group ng-class="{\'disabled\': $root.loading || readonly}" md-component-id=credentialsPanelGroup> <md-expansion-panel md-component-id=credentialsPanel> <md-expansion-panel-collapsed> <div class=tb-panel-title>{{ \'tb.rulenode.credentials\' | translate }}</div> <div class=tb-panel-prompt>{{ ruleNodeTypes.mqttCredentialTypes[configuration.credentials.type].name | translate }}</div> <span flex></span> <md-expansion-panel-icon></md-expansion-panel-icon> </md-expansion-panel-collapsed> <md-expansion-panel-expanded> <md-expansion-panel-header ng-click="$mdExpansionPanel(\'credentialsPanel\').collapse()"> <div class=tb-panel-title>{{ \'tb.rulenode.credentials\' | translate }}</div> <div class=tb-panel-prompt>{{ ruleNodeTypes.mqttCredentialTypes[configuration.credentials.type].name | translate }}</div> <span flex></span> <md-expansion-panel-icon></md-expansion-panel-icon> </md-expansion-panel-header> <md-expansion-panel-content> <div layout=column> <md-input-container class=md-block> <label translate>tb.rulenode.credentials-type</label> <md-select ng-required=true name=credentialsType ng-model=configuration.credentials.type ng-disabled="$root.loading || readonly" ng-change=credentialsTypeChanged()> <md-option ng-repeat="(credentialsType, credentialsValue) in ruleNodeTypes.mqttCredentialTypes" ng-value=credentialsValue.value> {{credentialsValue.name | translate}} </md-option> </md-select> <div ng-messages=mqttConfigForm.credentialsType.$error> <div translate ng-message=required>tb.rulenode.credentials-type-required</div> </div> </md-input-container> <section flex layout=column ng-if="configuration.credentials.type == ruleNodeTypes.mqttCredentialTypes.basic.value"> <md-input-container class=md-block> <label translate>tb.rulenode.username</label> <input ng-required=true name=mqttUsername ng-model=configuration.credentials.username> <div ng-messages=mqttConfigForm.mqttUsername.$error> <div translate ng-message=required>tb.rulenode.username-required</div> </div> </md-input-container> <md-input-container class=md-block> <label translate>tb.rulenode.password</label> <input type=password ng-required=true name=mqttPassword ng-model=configuration.credentials.password> <div ng-messages=mqttConfigForm.mqttPassword.$error> <div translate ng-message=required>tb.rulenode.password-required</div> </div> </md-input-container> </section> <section flex layout=column ng-if="configuration.credentials.type == ruleNodeTypes.mqttCredentialTypes[\'cert.PEM\'].value" class=dropdown-section> <div class=tb-container ng-class="configuration.credentials.caCertFileName ? \'ng-valid\' : \'ng-invalid\'"> <label class=tb-label translate>tb.rulenode.ca-cert</label> <div flow-init={singleFile:true} flow-file-added="certFileAdded($file, \'caCert\')" class=tb-file-select-container> <div class=tb-file-clear-container> <md-button ng-click="clearCertFile(\'caCert\')" class="tb-file-clear-btn md-icon-button md-primary" aria-label="{{ \'action.remove\' | translate }}"> <md-tooltip md-direction=top> {{ \'action.remove\' | translate }} </md-tooltip> <md-icon aria-label="{{ \'action.remove\' | translate }}" class=material-icons>close</md-icon> </md-button> </div> <div class="alert tb-flow-drop" flow-drop> <label for=caCertSelect translate>tb.rulenode.drop-file</label> <input class=file-input flow-btn id=caCertSelect> </div> </div> </div> <div class=dropdown-messages> <div ng-if=!configuration.credentials.caCertFileName class=tb-error-message translate>tb.rulenode.no-file</div> <div ng-if=configuration.credentials.caCertFileName>{{configuration.credentials.caCertFileName}}</div> </div> <div class=tb-container ng-class="configuration.credentials.certFileName ? \'ng-valid\' : \'ng-invalid\'"> <label class=tb-label translate>tb.rulenode.cert</label> <div flow-init={singleFile:true} flow-file-added="certFileAdded($file, \'Cert\')" class=tb-file-select-container> <div class=tb-file-clear-container> <md-button ng-click="clearCertFile(\'Cert\')" class="tb-file-clear-btn md-icon-button md-primary" aria-label="{{ \'action.remove\' | translate }}"> <md-tooltip md-direction=top> {{ \'action.remove\' | translate }} </md-tooltip> <md-icon aria-label="{{ \'action.remove\' | translate }}" class=material-icons>close</md-icon> </md-button> </div> <div class="alert tb-flow-drop" flow-drop> <label for=CertSelect translate>tb.rulenode.drop-file</label> <input class=file-input flow-btn id=CertSelect> </div> </div> </div> <div class=dropdown-messages> <div ng-if=!configuration.credentials.certFileName class=tb-error-message translate>tb.rulenode.no-file</div> <div ng-if=configuration.credentials.certFileName>{{configuration.credentials.certFileName}}</div> </div> <div class=tb-container ng-class="configuration.credentials.privateKeyFileName ? \'ng-valid\' : \'ng-invalid\'"> <label class=tb-label translate>tb.rulenode.private-key</label> <div flow-init={singleFile:true} flow-file-added="certFileAdded($file, \'privateKey\')" class=tb-file-select-container> <div class=tb-file-clear-container> <md-button ng-click="clearCertFile(\'privateKey\')" class="tb-file-clear-btn md-icon-button md-primary" aria-label="{{ \'action.remove\' | translate }}"> <md-tooltip md-direction=top> {{ \'action.remove\' | translate }} </md-tooltip> <md-icon aria-label="{{ \'action.remove\' | translate }}" class=material-icons>close</md-icon> </md-button> </div> <div class="alert tb-flow-drop" flow-drop> <label for=privateKeySelect translate>tb.rulenode.drop-file</label> <input class=file-input flow-btn id=privateKeySelect> </div> </div> </div> <div class=dropdown-messages> <div ng-if=!configuration.credentials.privateKeyFileName class=tb-error-message translate>tb.rulenode.no-file</div> <div ng-if=configuration.credentials.privateKeyFileName>{{configuration.credentials.privateKeyFileName}}</div> </div> <md-input-container class=md-block> <label translate>tb.rulenode.private-key-password</label> <input type=password name=privateKeyPassword ng-model=configuration.credentials.password> </md-input-container> </section> </div> </md-expansion-panel-content> </md-expansion-panel-expanded> </md-expansion-panel> </md-expansion-panel-group> </section>'},function(e,t){e.exports=' <section ng-form name=rabbitMqConfigForm layout=column> <md-input-container class=md-block> <label translate>tb.rulenode.exchange-name-pattern</label> <input name=exchangeNamePattern ng-model=configuration.exchangeNamePattern> </md-input-container> <md-input-container class=md-block> <label translate>tb.rulenode.routing-key-pattern</label> <input name=routingKeyPattern ng-model=configuration.routingKeyPattern> </md-input-container> <md-input-container class=md-block> <label translate>tb.rulenode.message-properties</label> <md-select ng-model=configuration.messageProperties ng-disabled="$root.loading || readonly"> <md-option ng-repeat="property in messageProperties" ng-value=property> {{ property }} </md-option> </md-select> </md-input-container> <div layout-gt-sm=row> <md-input-container class=md-block flex=100 flex-gt-sm=60> <label translate>tb.rulenode.host</label> <input ng-required=true name=host ng-model=configuration.host> <div ng-messages=rabbitMqConfigForm.host.$error> <div ng-message=required translate>tb.rulenode.host-required</div> </div> </md-input-container> <md-input-container class=md-block flex=100 flex-gt-sm=40> <label translate>tb.rulenode.port</label> <input ng-required=true type=number step=1 name=port ng-model=configuration.port min=0 max=65535> <div ng-messages=rabbitMqConfigForm.port.$error> <div ng-message=required translate>tb.rulenode.port-required</div> <div ng-message=min translate>tb.rulenode.port-range</div> <div ng-message=max translate>tb.rulenode.port-range</div> </div> </md-input-container> </div> <md-input-container class=md-block> <label translate>tb.rulenode.virtual-host</label> <input name=virtualHost ng-model=configuration.virtualHost> </md-input-container> <md-input-container class=md-block> <label translate>tb.rulenode.username</label> <input name=virtualHost ng-model=configuration.username> </md-input-container> <md-input-container class=md-block> <label translate>tb.rulenode.password</label> <input name=virtualHost type=password ng-model=configuration.password> </md-input-container> <md-input-container class=md-block> <md-checkbox ng-disabled="$root.loading || readonly" aria-label="{{ \'tb.rulenode.automatic-recovery\' | translate }}" ng-model=ruleNode.automaticRecoveryEnabled>{{ \'tb.rulenode.automatic-recovery\' | translate }} </md-checkbox> </md-input-container> <md-input-container class=md-block> <label translate>tb.rulenode.connection-timeout-ms</label> <input type=number step=1 name=connectionTimeout ng-model=configuration.connectionTimeout min=0> <div ng-messages=rabbitMqConfigForm.connectionTimeout.$error> <div ng-message=min translate>tb.rulenode.min-connection-timeout-ms-message</div> </div> </md-input-container> <md-input-container class=md-block> <label translate>tb.rulenode.handshake-timeout-ms</label> <input type=number step=1 name=handshakeTimeout ng-model=configuration.handshakeTimeout min=0> <div ng-messages=rabbitMqConfigForm.handshakeTimeout.$error> <div ng-message=min translate>tb.rulenode.min-handshake-timeout-ms-message</div> </div> </md-input-container> <label translate class=tb-title>tb.rulenode.client-properties</label> <tb-kv-map-config ng-model=configuration.clientProperties ng-required=false key-text="\'tb.rulenode.key\'" key-required-text="\'tb.rulenode.key-required\'" val-text="\'tb.rulenode.value\'" val-required-text="\'tb.rulenode.value-required\'"> </tb-kv-map-config> </section> '},function(e,t){e.exports=' <section ng-form name=restApiCallConfigForm layout=column> <md-input-container class=md-block> <label translate>tb.rulenode.endpoint-url-pattern</label> <input ng-required=true name=endpointUrlPattern ng-model=configuration.restEndpointUrlPattern> <div ng-messages=restApiCallConfigForm.endpointUrlPattern.$error> <div ng-message=required translate>tb.rulenode.endpoint-url-pattern-required</div> </div> <div class=tb-hint translate>tb.rulenode.endpoint-url-pattern-hint</div> </md-input-container> <md-input-container class=md-block> <label translate>tb.rulenode.request-method</label> <md-select ng-model=configuration.requestMethod ng-disabled=$root.loading> <md-option ng-repeat="type in ruleNodeTypes.httpRequestType" ng-value=type> {{ type }} </md-option> </md-select> </md-input-container> <label translate class=tb-title>tb.rulenode.headers</label> <div class=tb-hint translate>tb.rulenode.headers-hint</div> <tb-kv-map-config ng-model=configuration.headers ng-required=false key-text="\'tb.rulenode.header\'" key-required-text="\'tb.rulenode.header-required\'" val-text="\'tb.rulenode.value\'" val-required-text="\'tb.rulenode.value-required\'"> </tb-kv-map-config> </section> '},function(e,t){e.exports=" <section ng-form name=rpcReplyConfigForm layout=column> <md-input-container class=md-block> <label translate>tb.rulenode.request-id-metadata-attribute</label> <input name=requestIdMetaDataAttribute ng-model=configuration.requestIdMetaDataAttribute> </md-input-container> </section> "},function(e,t){e.exports=" <section ng-form name=rpcRequestConfigForm layout=column> <md-input-container class=md-block> <label translate>tb.rulenode.timeout-sec</label> <input ng-required=true type=number step=1 name=timeoutInSeconds ng-model=configuration.timeoutInSeconds min=0> <div ng-messages=rpcRequestConfigForm.timeoutInSeconds.$error multiple=multiple md-auto-hide=false> <div ng-message=required translate>tb.rulenode.timeout-required</div> <div ng-message=min translate>tb.rulenode.min-timeout-message</div> </div> </md-input-container> </section> "},function(e,t){e.exports=' <section ng-form name=sendEmailConfigForm layout=column> <md-checkbox ng-disabled="$root.loading || readonly" aria-label="{{ \'tb.rulenode.use-system-smtp-settings\' | translate }}" ng-model=configuration.useSystemSmtpSettings> {{ \'tb.rulenode.use-system-smtp-settings\' | translate }} </md-checkbox> <section layout=column ng-if=!configuration.useSystemSmtpSettings> <md-input-container class=md-block> <label translate>tb.rulenode.smtp-protocol</label> <md-select ng-disabled="$root.loading || readonly" ng-model=configuration.smtpProtocol> <md-option ng-repeat="smtpProtocol in smtpProtocols" value={{smtpProtocol}}> {{smtpProtocol.toUpperCase()}} </md-option> </md-select> </md-input-container> <div layout-gt-sm=row> <md-input-container class=md-block flex=100 flex-gt-sm=60> <label translate>tb.rulenode.smtp-host</label> <input ng-required=true name=smtpHost ng-model=configuration.smtpHost> <div ng-messages=sendEmailConfigForm.smtpHost.$error> <div translate ng-message=required>tb.rulenode.smtp-host-required</div> </div> </md-input-container> <md-input-container class=md-block flex=100 flex-gt-sm=40> <label translate>tb.rulenode.smtp-port</label> <input type=number step=1 min=1 max=65535 ng-required=true name=port ng-model=configuration.smtpPort> <div ng-messages=sendEmailConfigForm.port.$error> <div translate ng-message=required>tb.rulenode.smtp-port-required</div> <div translate ng-message=min>tb.rulenode.smtp-port-range</div> <div translate ng-message=max>tb.rulenode.smtp-port-range</div> </div> </md-input-container> </div> <md-input-container class=md-block> <label translate>tb.rulenode.timeout-msec</label> <input type=number step=1 min=0 ng-required=true name=timeout ng-model=configuration.timeout> <div ng-messages=sendEmailConfigForm.timeout.$error> <div translate ng-message=required>tb.rulenode.timeout-required</div> <div translate ng-message=min>tb.rulenode.min-timeout-msec-message</div> </div> </md-input-container> <md-checkbox ng-disabled="$root.loading || readonly" aria-label="{{ \'tb.rulenode.enable-tls\' | translate }}" ng-model=configuration.enableTls>{{ \'tb.rulenode.enable-tls\' | translate }}</md-checkbox> <md-input-container class=md-block> <label translate>tb.rulenode.username</label> <input name=username placeholder="{{ \'tb.rulenode.enter-username\' | translate }}" ng-model=configuration.username> </md-input-container> <md-input-container class=md-block> <label translate>tb.rulenode.password</label> <input name=password placeholder="{{ \'tb.rulenode.enter-password\' | translate }}" type=password ng-model=configuration.password> </md-input-container> </section> </section> '},function(e,t){e.exports=" <section ng-form name=snsConfigForm layout=column> <md-input-container class=md-block> <label translate>tb.rulenode.topic-arn-pattern</label> <input ng-required=true name=topicArnPattern ng-model=configuration.topicArnPattern> <div ng-messages=snsConfigForm.topicArnPattern.$error> <div ng-message=required translate>tb.rulenode.topic-arn-pattern-required</div> </div> <div class=tb-hint translate>tb.rulenode.topic-arn-pattern-hint</div> </md-input-container> <md-input-container class=md-block> <label translate>tb.rulenode.aws-access-key-id</label> <input ng-required=true name=accessKeyId ng-model=configuration.accessKeyId> <div ng-messages=snsConfigForm.accessKeyId.$error> <div ng-message=required translate>tb.rulenode.aws-access-key-id-required</div> </div> </md-input-container> <md-input-container class=md-block> <label translate>tb.rulenode.aws-secret-access-key</label> <input ng-required=true name=secretAccessKey ng-model=configuration.secretAccessKey> <div ng-messages=snsConfigForm.secretAccessKey.$error> <div ng-message=required translate>tb.rulenode.aws-secret-access-key-required</div> </div> </md-input-container> <md-input-container class=md-block> <label translate>tb.rulenode.aws-region</label> <input ng-required=true name=region ng-model=configuration.region> <div ng-messages=snsConfigForm.region.$error> <div ng-message=required translate>tb.rulenode.aws-region-required</div> </div> </md-input-container> </section> "},function(e,t){e.exports=' <section ng-form name=sqsConfigForm layout=column> <md-input-container class=md-block> <label translate>tb.rulenode.queue-type</label> <md-select ng-model=configuration.queueType ng-disabled="$root.loading || readonly"> <md-option ng-repeat="type in ruleNodeTypes.sqsQueueType" ng-value=type.value> {{ type.name | translate }} </md-option> </md-select> </md-input-container> <md-input-container class=md-block> <label translate>tb.rulenode.queue-url-pattern</label> <input ng-required=true name=queueUrlPattern ng-model=configuration.queueUrlPattern> <div ng-messages=sqsConfigForm.queueUrlPattern.$error> <div ng-message=required translate>tb.rulenode.queue-url-pattern-required</div> </div> <div class=tb-hint translate>tb.rulenode.queue-url-pattern-hint</div> </md-input-container> <md-input-container class=md-block ng-if="configuration.queueType == ruleNodeTypes.sqsQueueType.STANDARD.value"> <label translate>tb.rulenode.delay-seconds</label> <input type=number step=1 name=delaySeconds ng-model=configuration.delaySeconds min=0 max=900> <div ng-messages=sqsConfigForm.delaySeconds.$error> <div ng-message=min translate>tb.rulenode.min-delay-seconds-message</div> <div ng-message=max translate>tb.rulenode.max-delay-seconds-message</div> </div> </md-input-container> <label translate class=tb-title>tb.rulenode.message-attributes</label> <div class=tb-hint translate>tb.rulenode.message-attributes-hint</div> <tb-kv-map-config ng-model=configuration.messageAttributes ng-required=false key-text="\'tb.rulenode.name\'" key-required-text="\'tb.rulenode.name-required\'" val-text="\'tb.rulenode.value\'" val-required-text="\'tb.rulenode.value-required\'"> </tb-kv-map-config> <md-input-container class=md-block> <label translate>tb.rulenode.aws-access-key-id</label> <input ng-required=true name=accessKeyId ng-model=configuration.accessKeyId> <div ng-messages=snsConfigForm.accessKeyId.$error> <div ng-message=required translate>tb.rulenode.aws-access-key-id-required</div> </div> </md-input-container> <md-input-container class=md-block> <label translate>tb.rulenode.aws-secret-access-key</label> <input ng-required=true name=secretAccessKey ng-model=configuration.secretAccessKey> <div ng-messages=snsConfigForm.secretAccessKey.$error> <div ng-message=required translate>tb.rulenode.aws-secret-access-key-required</div> </div> </md-input-container> <md-input-container class=md-block> <label translate>tb.rulenode.aws-region</label> <input ng-required=true name=region ng-model=configuration.region> <div ng-messages=snsConfigForm.region.$error> <div ng-message=required translate>tb.rulenode.aws-region-required</div> </div> </md-input-container> </section> '},function(e,t){e.exports=" <section ng-form name=timeseriesConfigForm layout=column> <md-input-container class=md-block> <label translate>tb.rulenode.default-ttl</label> <input ng-required=true type=number step=1 name=defaultTTL ng-model=configuration.defaultTTL min=0> <div ng-messages=timeseriesConfigForm.defaultTTL.$error multiple=multiple md-auto-hide=false> <div ng-message=required translate>tb.rulenode.default-ttl-required</div> <div ng-message=min translate>tb.rulenode.min-default-ttl-message</div> </div> </md-input-container> </section> "},function(e,t){e.exports=' <section layout=column> <div layout=row> <md-input-container class=md-block style=min-width:100px> <label translate>relation.direction</label> <md-select required ng-model=query.direction> <md-option ng-repeat="direction in types.entitySearchDirection" ng-value=direction> {{ (\'relation.search-direction.\' + direction) | translate}} </md-option> </md-select> </md-input-container> <md-input-container class=md-block> <label translate>tb.rulenode.max-relation-level</label> <input name=maxRelationLevel type=number min=1 step=1 placeholder="{{ \'tb.rulenode.unlimited-level\' | translate }}" ng-model=query.maxLevel aria-label="{{ \'tb.rulenode.max-relation-level\' | translate }}"> </md-input-container> </div> <div class=md-caption style=color:rgba(0,0,0,.57) translate>relation.relation-type</div> <tb-relation-type-autocomplete flex hide-label ng-model=query.relationType tb-required=false> </tb-relation-type-autocomplete> <div class="md-caption tb-required" style=color:rgba(0,0,0,.57) translate>device.device-types</div> <tb-entity-subtype-list tb-required=true entity-type=types.entityType.device ng-model=query.deviceTypes> </tb-entity-subtype-list> </section> '},function(e,t){e.exports=" <section layout=column> <label translate class=\"tb-title tb-required\">tb.rulenode.attr-mapping</label> <md-checkbox aria-label=\"{{ 'tb.rulenode.latest-telemetry' | translate }}\" ng-model=configuration.telemetry>{{ 'tb.rulenode.latest-telemetry' | translate }} </md-checkbox> <tb-kv-map-config ng-model=configuration.attrMapping ng-required=true required-text=\"'tb.rulenode.attr-mapping-required'\" key-text=\"configuration.telemetry ? 'tb.rulenode.source-telemetry' : 'tb.rulenode.source-attribute'\" key-required-text=\"configuration.telemetry ? 'tb.rulenode.source-telemetry-required' : 'tb.rulenode.source-attribute-required'\" val-text=\"'tb.rulenode.target-attribute'\" val-required-text=\"'tb.rulenode.target-attribute-required'\"> </tb-kv-map-config> </section> "; | |
2 | -},function(e,t){e.exports=' <section layout=column> <label translate class="tb-title tb-required">tb.rulenode.device-relations-query</label> <tb-device-relations-query-config style=padding-bottom:15px ng-model=configuration.deviceRelationsQuery> </tb-device-relations-query-config> <label translate class="tb-title no-padding">tb.rulenode.client-attributes</label> <md-chips style=padding-bottom:15px ng-required=false readonly=readonly ng-model=configuration.clientAttributeNames placeholder="{{\'tb.rulenode.client-attributes\' | translate}}" md-separator-keys=separatorKeys> </md-chips> <label translate class="tb-title no-padding">tb.rulenode.shared-attributes</label> <md-chips style=padding-bottom:15px ng-required=false readonly=readonly ng-model=configuration.sharedAttributeNames placeholder="{{\'tb.rulenode.shared-attributes\' | translate}}" md-separator-keys=separatorKeys> </md-chips> <label translate class="tb-title no-padding">tb.rulenode.server-attributes</label> <md-chips style=padding-bottom:15px ng-required=false readonly=readonly ng-model=configuration.serverAttributeNames placeholder="{{\'tb.rulenode.server-attributes\' | translate}}" md-separator-keys=separatorKeys> </md-chips> <label translate class="tb-title no-padding">tb.rulenode.latest-timeseries</label> <md-chips ng-required=false readonly=readonly ng-model=configuration.latestTsKeyNames placeholder="{{\'tb.rulenode.latest-timeseries\' | translate}}" md-separator-keys=separatorKeys> </md-chips> </section> '},function(e,t){e.exports=' <section layout=column> <label translate class="tb-title no-padding">tb.rulenode.client-attributes</label> <md-chips style=padding-bottom:15px ng-required=false readonly=readonly ng-model=configuration.clientAttributeNames placeholder="{{\'tb.rulenode.client-attributes\' | translate}}" md-separator-keys=separatorKeys> </md-chips> <label translate class="tb-title no-padding">tb.rulenode.shared-attributes</label> <md-chips style=padding-bottom:15px ng-required=false readonly=readonly ng-model=configuration.sharedAttributeNames placeholder="{{\'tb.rulenode.shared-attributes\' | translate}}" md-separator-keys=separatorKeys> </md-chips> <label translate class="tb-title no-padding">tb.rulenode.server-attributes</label> <md-chips style=padding-bottom:15px ng-required=false readonly=readonly ng-model=configuration.serverAttributeNames placeholder="{{\'tb.rulenode.server-attributes\' | translate}}" md-separator-keys=separatorKeys> </md-chips> <label translate class="tb-title no-padding">tb.rulenode.latest-timeseries</label> <md-chips ng-required=false readonly=readonly ng-model=configuration.latestTsKeyNames placeholder="{{\'tb.rulenode.latest-timeseries\' | translate}}" md-separator-keys=separatorKeys> </md-chips> </section> '},function(e,t){e.exports=' <section layout=column> <label translate class="tb-title tb-required">tb.rulenode.fields-mapping</label> <tb-kv-map-config ng-model=configuration.fieldsMapping ng-required=true required-text="\'tb.rulenode.fields-mapping-required\'" key-text="\'tb.rulenode.source-field\'" key-required-text="\'tb.rulenode.source-field-required\'" val-text="\'tb.rulenode.target-attribute\'" val-required-text="\'tb.rulenode.target-attribute-required\'"> </tb-kv-map-config> </section> '},function(e,t){e.exports=" <section layout=column> <label translate class=\"tb-title tb-required\">tb.rulenode.relations-query</label> <tb-relations-query-config style=padding-bottom:15px ng-model=configuration.relationsQuery> </tb-relations-query-config> <label translate class=\"tb-title tb-required\">tb.rulenode.attr-mapping</label> <md-checkbox aria-label=\"{{ 'tb.rulenode.latest-telemetry' | translate }}\" ng-model=configuration.telemetry>{{ 'tb.rulenode.latest-telemetry' | translate }} </md-checkbox> <tb-kv-map-config ng-model=configuration.attrMapping ng-required=true required-text=\"'tb.rulenode.attr-mapping-required'\" key-text=\"configuration.telemetry ? 'tb.rulenode.source-telemetry' : 'tb.rulenode.source-attribute'\" key-required-text=\"configuration.telemetry ? 'tb.rulenode.source-telemetry-required' : 'tb.rulenode.source-attribute-required'\" val-text=\"'tb.rulenode.target-attribute'\" val-required-text=\"'tb.rulenode.target-attribute-required'\"> </tb-kv-map-config> </section> "},21,function(e,t){e.exports=" <section ng-form name=checkRelationConfigForm> <md-input-container class=md-block style=min-width:100px> <label translate>relation.direction</label> <md-select required ng-model=configuration.direction> <md-option ng-repeat=\"direction in types.entitySearchDirection\" ng-value=direction> {{ ('relation.search-direction.' + direction) | translate}} </md-option> </md-select> </md-input-container> <div layout=row class=tb-entity-select> <tb-entity-type-select style=min-width:100px the-form=checkRelationConfigForm tb-required=true ng-model=configuration.entityType> </tb-entity-type-select> <tb-entity-autocomplete flex ng-if=configuration.entityType the-form=checkRelationConfigForm tb-required=true entity-type=configuration.entityType ng-model=configuration.entityId> </tb-entity-autocomplete> </div> <tb-relation-type-autocomplete hide-label ng-model=configuration.relationType tb-required=true> </tb-relation-type-autocomplete> </section> "},function(e,t){e.exports=' <section layout=column> <label translate class="tb-title no-padding" ng-class="{\'tb-required\': required}">tb.rulenode.message-types-filter</label> <md-chips id=message_type_chips ng-required=required readonly=readonly ng-model=messageTypes md-autocomplete-snap md-transform-chip=transformMessageTypeChip($chip) md-require-match=false> <md-autocomplete id=message_type md-no-cache=true md-selected-item=selectedMessageType md-search-text=messageTypeSearchText md-items="item in messageTypesSearch(messageTypeSearchText)" md-item-text=item.name md-min-length=0 placeholder="{{\'tb.rulenode.message-type\' | translate }}" md-menu-class=tb-message-type-autocomplete> <span md-highlight-text=messageTypeSearchText md-highlight-flags=^i>{{item}}</span> <md-not-found> <div class=tb-not-found> <div class=tb-no-entries ng-if="!messageTypeSearchText || !messageTypeSearchText.length"> <span translate>tb.rulenode.no-message-types-found</span> </div> <div ng-if="messageTypeSearchText && messageTypeSearchText.length"> <span translate translate-values=\'{ messageType: "{{messageTypeSearchText | truncate:true:6:'...'}}" }\'>tb.rulenode.no-message-type-matching</span> <span> <a translate ng-click="createMessageType($event, \'#message_type_chips\')">tb.rulenode.create-new-message-type</a> </span> </div> </div> </md-not-found> </md-autocomplete> <md-chip-template> <span>{{$chip.name}}</span> </md-chip-template> </md-chips> <div class=tb-error-messages ng-messages=ngModelCtrl.$error role=alert> <div translate ng-message=messageTypes class=tb-error-message>tb.rulenode.message-types-required</div> </div> </section>'},function(e,t){e.exports=" <section layout=column> <label translate class=\"tb-title no-padding\">tb.rulenode.filter</label> <tb-js-func ng-model=configuration.jsScript function-name=Filter function-args=\"{{ ['msg', 'metadata', 'msgType'] }}\" no-validate=true> </tb-js-func> <div layout=row> <md-button ng-click=testScript($event) class=\"md-primary md-raised\"> {{ 'tb.rulenode.test-filter-function' | translate }} </md-button> </div> </section> "},function(e,t){e.exports=" <section layout=column> <label translate class=\"tb-title no-padding\">tb.rulenode.switch</label> <tb-js-func ng-model=configuration.jsScript function-name=Switch function-args=\"{{ ['msg', 'metadata', 'msgType'] }}\" no-validate=true> </tb-js-func> <div layout=row> <md-button ng-click=testScript($event) class=\"md-primary md-raised\"> {{ 'tb.rulenode.test-switch-function' | translate }} </md-button> </div> </section> "},function(e,t){e.exports=' <section class=tb-kv-map-config layout=column> <div class=header flex layout=row> <span class=cell flex translate>{{ keyText }}</span> <span class=cell flex translate>{{ valText }}</span> <span ng-show=!disabled style=width:52px> </span> </div> <div class=body> <div class=row ng-form name=kvForm flex layout=row layout-align="start center" ng-repeat="keyVal in kvList track by $index"> <md-input-container class="cell md-block" flex md-no-float> <input placeholder="{{ keyText | translate }}" ng-required=true name=key ng-model=keyVal.key> <div ng-messages=kvForm.key.$error> <div translate ng-message=required>{{keyRequiredText}}</div> </div> </md-input-container> <md-input-container class="cell md-block" flex md-no-float> <input placeholder="{{ valText | translate }}" ng-required=true name=value ng-model=keyVal.value> <div ng-messages=kvForm.value.$error> <div translate ng-message=required>{{valRequiredText}}</div> </div> </md-input-container> <md-button ng-show=!disabled ng-disabled=loading class="md-icon-button md-primary" ng-click=removeKeyVal($index) aria-label="{{ \'action.remove\' | translate }}"> <md-tooltip md-direction=top> {{ \'tb.key-val.remove-entry\' | translate }} </md-tooltip> <md-icon aria-label="{{ \'action.delete\' | translate }}" class=material-icons> close </md-icon> </md-button> </div> </div> <div class=tb-error-messages ng-messages=ngModelCtrl.$error role=alert> <div translate ng-message=kvMap class=tb-error-message>{{requiredText}}</div> </div> <div> <md-button ng-show=!disabled ng-disabled=loading class="md-primary md-raised" ng-click=addKeyVal() aria-label="{{ \'action.add\' | translate }}"> <md-tooltip md-direction=top> {{ \'tb.key-val.add-entry\' | translate }} </md-tooltip> <md-icon aria-label="{{ \'action.add\' | translate }}" class=material-icons> add </md-icon> {{ \'action.add\' | translate }} </md-button> </div> </section> '},function(e,t){e.exports=" <section layout=column> <div layout=row> <md-input-container class=md-block style=min-width:100px> <label translate>relation.direction</label> <md-select required ng-model=query.direction> <md-option ng-repeat=\"direction in types.entitySearchDirection\" ng-value=direction> {{ ('relation.search-direction.' + direction) | translate}} </md-option> </md-select> </md-input-container> <md-input-container class=md-block> <label translate>tb.rulenode.max-relation-level</label> <input name=maxRelationLevel type=number min=1 step=1 placeholder=\"{{ 'tb.rulenode.unlimited-level' | translate }}\" ng-model=query.maxLevel aria-label=\"{{ 'tb.rulenode.max-relation-level' | translate }}\"> </md-input-container> </div> <div class=md-caption style=padding-bottom:10px;color:rgba(0,0,0,.57) translate>relation.relation-filters</div> <tb-relation-filters ng-model=query.filters> </tb-relation-filters> </section> "},function(e,t){e.exports=' <section layout=column> <md-input-container class=md-block> <label translate>tb.rulenode.originator-source</label> <md-select required ng-model=configuration.originatorSource> <md-option ng-repeat="source in ruleNodeTypes.originatorSource" ng-value=source.value> {{ source.name | translate}} </md-option> </md-select> </md-input-container> <section layout=column ng-if="configuration.originatorSource == ruleNodeTypes.originatorSource.RELATED.value"> <label translate class="tb-title tb-required">tb.rulenode.relations-query</label> <tb-relations-query-config style=padding-bottom:15px ng-model=configuration.relationsQuery> </tb-relations-query-config> </section> </section> '},function(e,t){e.exports=" <section layout=column> <label translate class=\"tb-title no-padding\">tb.rulenode.transform</label> <tb-js-func ng-model=configuration.jsScript function-name=Transform function-args=\"{{ ['msg', 'metadata', 'msgType'] }}\" no-validate=true> </tb-js-func> <div layout=row style=padding-bottom:15px> <md-button ng-click=testScript($event) class=\"md-primary md-raised\"> {{ 'tb.rulenode.test-transformer-function' | translate }} </md-button> </div> </section> "},function(e,t){e.exports=" <section ng-form name=toEmailConfigForm layout=column> <md-input-container class=md-block> <label translate>tb.rulenode.from-template</label> <textarea ng-required=true name=fromTemplate ng-model=configuration.fromTemplate rows=2></textarea> <div ng-messages=toEmailConfigForm.fromTemplate.$error> <div ng-message=required translate>tb.rulenode.from-template-required</div> </div> <div class=tb-hint translate>tb.rulenode.from-template-hint</div> </md-input-container> <md-input-container class=md-block> <label translate>tb.rulenode.to-template</label> <textarea ng-required=true name=toTemplate ng-model=configuration.toTemplate rows=2></textarea> <div ng-messages=toEmailConfigForm.toTemplate.$error> <div ng-message=required translate>tb.rulenode.to-template-required</div> </div> <div class=tb-hint translate>tb.rulenode.mail-address-list-template-hint</div> </md-input-container> <md-input-container class=md-block> <label translate>tb.rulenode.cc-template</label> <textarea name=ccTemplate ng-model=configuration.ccTemplate rows=2></textarea> <div class=tb-hint translate>tb.rulenode.mail-address-list-template-hint</div> </md-input-container> <md-input-container class=md-block> <label translate>tb.rulenode.bcc-template</label> <textarea name=ccTemplate ng-model=configuration.bccTemplate rows=2></textarea> <div class=tb-hint translate>tb.rulenode.mail-address-list-template-hint</div> </md-input-container> <md-input-container class=md-block> <label translate>tb.rulenode.subject-template</label> <textarea ng-required=true name=subjectTemplate ng-model=configuration.subjectTemplate rows=2></textarea> <div ng-messages=toEmailConfigForm.subjectTemplate.$error> <div ng-message=required translate>tb.rulenode.subject-template-required</div> </div> <div class=tb-hint translate>tb.rulenode.subject-template-hint</div> </md-input-container> <md-input-container class=md-block> <label translate>tb.rulenode.body-template</label> <textarea ng-required=true name=bodyTemplate ng-model=configuration.bodyTemplate rows=6></textarea> <div ng-messages=toEmailConfigForm.bodyTemplate.$error> <div ng-message=required translate>tb.rulenode.body-template-required</div> </div> <div class=tb-hint translate>tb.rulenode.body-template-hint</div> </md-input-container> </section> "},function(e,t,n){"use strict";function a(e){return e&&e.__esModule?e:{default:e}}function r(e,t){var n=function(n,a,r,i){var l=o.default;a.html(l),n.types=t,n.$watch("configuration",function(e,t){angular.equals(e,t)||i.$setViewValue(n.configuration)}),i.$render=function(){n.configuration=i.$viewValue},e(a.contents())(n)};return{restrict:"E",require:"^ngModel",scope:{},link:n}}r.$inject=["$compile","types"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=r;var i=n(5),o=a(i)},function(e,t,n){"use strict";function a(e){return e&&e.__esModule?e:{default:e}}function r(e,t,n,a){var r=function(r,i,l,s){var u=o.default;i.html(u),r.types=n,r.$watch("configuration",function(e,t){angular.equals(e,t)||s.$setViewValue(r.configuration)}),s.$render=function(){r.configuration=s.$viewValue},r.testDetailsBuildJs=function(e){var n=angular.copy(r.configuration.alarmDetailsBuildJs);a.testNodeScript(e,n,"json",t.instant("tb.rulenode.details")+"","Details",["msg","metadata","msgType"],r.ruleNodeId).then(function(e){r.configuration.alarmDetailsBuildJs=e,s.$setDirty()})},e(i.contents())(r)};return{restrict:"E",require:"^ngModel",scope:{ruleNodeId:"="},link:r}}r.$inject=["$compile","$translate","types","ruleNodeScriptTest"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=r;var i=n(6),o=a(i)},function(e,t,n){"use strict";function a(e){return e&&e.__esModule?e:{default:e}}function r(e,t,n,a){var r=function(r,i,l,s){var u=o.default;i.html(u),r.types=n,r.$watch("configuration",function(e,t){angular.equals(e,t)||s.$setViewValue(r.configuration)}),s.$render=function(){r.configuration=s.$viewValue},r.testDetailsBuildJs=function(e){var n=angular.copy(r.configuration.alarmDetailsBuildJs);a.testNodeScript(e,n,"json",t.instant("tb.rulenode.details")+"","Details",["msg","metadata","msgType"],r.ruleNodeId).then(function(e){r.configuration.alarmDetailsBuildJs=e,s.$setDirty()})},e(i.contents())(r)};return{restrict:"E",require:"^ngModel",scope:{ruleNodeId:"="},link:r}}r.$inject=["$compile","$translate","types","ruleNodeScriptTest"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=r;var i=n(7),o=a(i)},function(e,t,n){"use strict";function a(e){return e&&e.__esModule?e:{default:e}}function r(e,t,n,a){var r=function(r,i,l,s){var u=o.default;i.html(u),r.types=n,r.originator=null,r.$watch("configuration",function(e,t){angular.equals(e,t)||s.$setViewValue(r.configuration)}),s.$render=function(){r.configuration=s.$viewValue,r.configuration.originatorId&&r.configuration.originatorType?r.originator={id:r.configuration.originatorId,entityType:r.configuration.originatorType}:r.originator=null,r.$watch("originator",function(e,t){angular.equals(e,t)||(r.originator?(s.$viewValue.originatorId=r.originator.id,s.$viewValue.originatorType=r.originator.entityType):(s.$viewValue.originatorId=null,s.$viewValue.originatorType=null))},!0)},r.testScript=function(e){var n=angular.copy(r.configuration.jsScript);a.testNodeScript(e,n,"generate",t.instant("tb.rulenode.generator")+"","Generate",["prevMsg","prevMetadata","prevMsgType"],r.ruleNodeId).then(function(e){r.configuration.jsScript=e,s.$setDirty()})},e(i.contents())(r)};return{restrict:"E",require:"^ngModel",scope:{ruleNodeId:"="},link:r}}r.$inject=["$compile","$translate","types","ruleNodeScriptTest"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=r,n(1);var i=n(8),o=a(i)},function(e,t,n){"use strict";function a(e){return e&&e.__esModule?e:{default:e}}Object.defineProperty(t,"__esModule",{value:!0});var r=n(51),i=a(r),o=n(36),l=a(o),s=n(39),u=a(s),d=n(38),c=a(d),m=n(37),p=a(m),g=n(42),f=a(g),b=n(46),v=a(b),y=n(47),q=a(y),h=n(45),T=a(h),$=n(41),k=a($),w=n(49),C=a(w),_=n(50),x=a(_),E=n(44),M=a(E),S=n(43),N=a(S),V=n(48),P=a(V);t.default=angular.module("thingsboard.ruleChain.config.action",[]).directive("tbActionNodeTimeseriesConfig",i.default).directive("tbActionNodeAttributesConfig",l.default).directive("tbActionNodeGeneratorConfig",u.default).directive("tbActionNodeCreateAlarmConfig",c.default).directive("tbActionNodeClearAlarmConfig",p.default).directive("tbActionNodeLogConfig",f.default).directive("tbActionNodeRpcReplyConfig",v.default).directive("tbActionNodeRpcRequestConfig",q.default).directive("tbActionNodeRestApiCallConfig",T.default).directive("tbActionNodeKafkaConfig",k.default).directive("tbActionNodeSnsConfig",C.default).directive("tbActionNodeSqsConfig",x.default).directive("tbActionNodeRabbitMqConfig",M.default).directive("tbActionNodeMqttConfig",N.default).directive("tbActionNodeSendEmailConfig",P.default).name},function(e,t,n){"use strict";function a(e){return e&&e.__esModule?e:{default:e}}function r(e){var t=function(t,n,a,r){var i=o.default;n.html(i),t.ackValues=["all","-1","0","1"],t.$watch("configuration",function(e,n){angular.equals(e,n)||r.$setViewValue(t.configuration)}),r.$render=function(){t.configuration=r.$viewValue},e(n.contents())(t)};return{restrict:"E",require:"^ngModel",scope:{},link:t}}r.$inject=["$compile"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=r;var i=n(9),o=a(i)},function(e,t,n){"use strict";function a(e){return e&&e.__esModule?e:{default:e}}function r(e,t,n){var a=function(a,r,i,l){var s=o.default;r.html(s),a.$watch("configuration",function(e,t){angular.equals(e,t)||l.$setViewValue(a.configuration)}),l.$render=function(){a.configuration=l.$viewValue},a.testScript=function(e){var r=angular.copy(a.configuration.jsScript);n.testNodeScript(e,r,"string",t.instant("tb.rulenode.to-string")+"","ToString",["msg","metadata","msgType"],a.ruleNodeId).then(function(e){a.configuration.jsScript=e,l.$setDirty()})},e(r.contents())(a)};return{restrict:"E",require:"^ngModel",scope:{ruleNodeId:"="},link:a}}r.$inject=["$compile","$translate","ruleNodeScriptTest"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=r;var i=n(10),o=a(i)},function(e,t,n){"use strict";function a(e){return e&&e.__esModule?e:{default:e}}function r(e,t,n){var a=function(a,r,i,l){var s=o.default;r.html(s),a.$mdExpansionPanel=t,a.ruleNodeTypes=n,a.credentialsTypeChanged=function(){var e=a.configuration.credentials.type;a.configuration.credentials={},a.configuration.credentials.type=e,a.updateValidity()},a.certFileAdded=function(e,t){var n=new FileReader;n.onload=function(n){a.$apply(function(){if(n.target.result){l.$setDirty();var r=n.target.result;r&&r.length>0&&("caCert"==t&&(a.configuration.credentials.caCertFileName=e.name,a.configuration.credentials.caCert=r),"privateKey"==t&&(a.configuration.credentials.privateKeyFileName=e.name,a.configuration.credentials.privateKey=r),"Cert"==t&&(a.configuration.credentials.certFileName=e.name,a.configuration.credentials.cert=r)),a.updateValidity()}})},n.readAsText(e.file)},a.clearCertFile=function(e){l.$setDirty(),"caCert"==e&&(a.configuration.credentials.caCertFileName=null,a.configuration.credentials.caCert=null),"privateKey"==e&&(a.configuration.credentials.privateKeyFileName=null,a.configuration.credentials.privateKey=null),"Cert"==e&&(a.configuration.credentials.certFileName=null,a.configuration.credentials.cert=null),a.updateValidity()},a.updateValidity=function(){var e=!0,t=a.configuration.credentials;t.type==n.mqttCredentialTypes["cert.PEM"].value&&(t.caCert&&t.cert&&t.privateKey||(e=!1)),l.$setValidity("Certs",e)},a.$watch("configuration",function(e,t){angular.equals(e,t)||l.$setViewValue(a.configuration)}),l.$render=function(){a.configuration=l.$viewValue},e(r.contents())(a)};return{restrict:"E",require:"^ngModel",scope:{readonly:"=ngReadonly"},link:a}}r.$inject=["$compile","$mdExpansionPanel","ruleNodeTypes"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=r,n(2);var i=n(11),o=a(i)},function(e,t,n){"use strict";function a(e){return e&&e.__esModule?e:{default:e}}function r(e){var t=function(t,n,a,r){var i=o.default;n.html(i),t.messageProperties=[null,"BASIC","TEXT_PLAIN","MINIMAL_BASIC","MINIMAL_PERSISTENT_BASIC","PERSISTENT_BASIC","PERSISTENT_TEXT_PLAIN"],t.$watch("configuration",function(e,n){angular.equals(e,n)||r.$setViewValue(t.configuration)}),r.$render=function(){t.configuration=r.$viewValue},e(n.contents())(t)};return{restrict:"E",require:"^ngModel",scope:{readonly:"=ngReadonly"},link:t}}r.$inject=["$compile"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=r;var i=n(12),o=a(i)},function(e,t,n){"use strict";function a(e){return e&&e.__esModule?e:{default:e}}function r(e,t){var n=function(n,a,r,i){var l=o.default;a.html(l),n.ruleNodeTypes=t,n.$watch("configuration",function(e,t){angular.equals(e,t)||i.$setViewValue(n.configuration)}),i.$render=function(){n.configuration=i.$viewValue},e(a.contents())(n)};return{restrict:"E",require:"^ngModel",scope:{},link:n}}r.$inject=["$compile","ruleNodeTypes"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=r;var i=n(13),o=a(i)},function(e,t,n){"use strict";function a(e){return e&&e.__esModule?e:{default:e}}function r(e){var t=function(t,n,a,r){var i=o.default;n.html(i),t.$watch("configuration",function(e,n){angular.equals(e,n)||r.$setViewValue(t.configuration)}),r.$render=function(){t.configuration=r.$viewValue},e(n.contents())(t)};return{restrict:"E",require:"^ngModel",scope:{},link:t}}r.$inject=["$compile"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=r;var i=n(14),o=a(i)},function(e,t,n){"use strict";function a(e){return e&&e.__esModule?e:{default:e}}function r(e){var t=function(t,n,a,r){var i=o.default;n.html(i),t.$watch("configuration",function(e,n){angular.equals(e,n)||r.$setViewValue(t.configuration)}),r.$render=function(){t.configuration=r.$viewValue},e(n.contents())(t)};return{restrict:"E",require:"^ngModel",scope:{},link:t}}r.$inject=["$compile"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=r;var i=n(15),o=a(i)},function(e,t,n){"use strict";function a(e){return e&&e.__esModule?e:{default:e}}function r(e){var t=function(t,n,a,r){var i=o.default;n.html(i),t.smtpProtocols=["smtp","smtps"],t.$watch("configuration",function(e,n){angular.equals(e,n)||r.$setViewValue(t.configuration)}),r.$render=function(){t.configuration=r.$viewValue},e(n.contents())(t)};return{restrict:"E",require:"^ngModel",scope:{readonly:"=ngReadonly"},link:t}}r.$inject=["$compile"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=r;var i=n(16),o=a(i)},function(e,t,n){"use strict";function a(e){return e&&e.__esModule?e:{default:e}}function r(e){var t=function(t,n,a,r){var i=o.default;n.html(i),t.$watch("configuration",function(e,n){angular.equals(e,n)||r.$setViewValue(t.configuration)}),r.$render=function(){t.configuration=r.$viewValue},e(n.contents())(t)};return{restrict:"E",require:"^ngModel",scope:{},link:t}}r.$inject=["$compile"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=r;var i=n(17),o=a(i)},function(e,t,n){"use strict";function a(e){return e&&e.__esModule?e:{default:e}}function r(e,t){var n=function(n,a,r,i){var l=o.default;a.html(l),n.ruleNodeTypes=t,n.$watch("configuration",function(e,t){angular.equals(e,t)||i.$setViewValue(n.configuration)}),i.$render=function(){n.configuration=i.$viewValue},e(a.contents())(n)};return{restrict:"E",require:"^ngModel",scope:{readonly:"=ngReadonly"},link:n}}r.$inject=["$compile","ruleNodeTypes"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=r;var i=n(18),o=a(i)},function(e,t,n){"use strict";function a(e){return e&&e.__esModule?e:{default:e}}function r(e){var t=function(t,n,a,r){var i=o.default;n.html(i),t.$watch("configuration",function(e,n){angular.equals(e,n)||r.$setViewValue(t.configuration)}),r.$render=function(){t.configuration=r.$viewValue},e(n.contents())(t)};return{restrict:"E",require:"^ngModel",scope:{},link:t}}r.$inject=["$compile"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=r;var i=n(19),o=a(i)},function(e,t,n){"use strict";function a(e){return e&&e.__esModule?e:{default:e}}function r(e,t){var n=function(n,a,r,i){var l=o.default;a.html(l),n.types=t,n.$watch("query",function(e,t){angular.equals(e,t)||i.$setViewValue(n.query)}),i.$render=function(){n.query=i.$viewValue},e(a.contents())(n)};return{restrict:"E",require:"^ngModel",scope:{},link:n}}r.$inject=["$compile","types"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=r;var i=n(20),o=a(i)},function(e,t){"use strict";function n(e){var t=function(t,n,a,r){n.html("<div></div>"),t.$watch("configuration",function(e,n){angular.equals(e,n)||r.$setViewValue(t.configuration)}),r.$render=function(){t.configuration=r.$viewValue},e(n.contents())(t)};return{restrict:"E",require:"^ngModel",scope:{},link:t}}n.$inject=["$compile"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=n},function(e,t,n){"use strict";function a(e){return e&&e.__esModule?e:{default:e}}function r(e){var t=function(t,n,a,r){var i=o.default;n.html(i),t.$watch("configuration",function(e,n){angular.equals(e,n)||r.$setViewValue(t.configuration)}),r.$render=function(){t.configuration=r.$viewValue},e(n.contents())(t)};return{restrict:"E",require:"^ngModel",scope:{},link:t}}r.$inject=["$compile"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=r;var i=n(21),o=a(i)},function(e,t,n){"use strict";function a(e){return e&&e.__esModule?e:{default:e}}function r(e,t){var n=function(n,a,r,i){var l=o.default;a.html(l);var s=186;n.separatorKeys=[t.KEY_CODE.ENTER,t.KEY_CODE.COMMA,s],n.$watch("configuration",function(e,t){angular.equals(e,t)||i.$setViewValue(n.configuration)}),i.$render=function(){n.configuration=i.$viewValue},e(a.contents())(n)};return{restrict:"E",require:"^ngModel",scope:{},link:n}}r.$inject=["$compile","$mdConstant"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=r;var i=n(22),o=a(i)},function(e,t,n){"use strict";function a(e){return e&&e.__esModule?e:{default:e}}Object.defineProperty(t,"__esModule",{value:!0});var r=n(57),i=a(r),o=n(58),l=a(o),s=n(55),u=a(s),d=n(59),c=a(d),m=n(54),p=a(m),g=n(60),f=a(g);t.default=angular.module("thingsboard.ruleChain.config.enrichment",[]).directive("tbEnrichmentNodeOriginatorAttributesConfig",i.default).directive("tbEnrichmentNodeOriginatorFieldsConfig",l.default).directive("tbEnrichmentNodeDeviceAttributesConfig",u.default).directive("tbEnrichmentNodeRelatedAttributesConfig",c.default).directive("tbEnrichmentNodeCustomerAttributesConfig",p.default).directive("tbEnrichmentNodeTenantAttributesConfig",f.default).name},function(e,t,n){"use strict";function a(e){return e&&e.__esModule?e:{default:e}}function r(e,t){var n=function(n,a,r,i){var l=o.default;a.html(l);var s=186;n.separatorKeys=[t.KEY_CODE.ENTER,t.KEY_CODE.COMMA,s],n.$watch("configuration",function(e,t){angular.equals(e,t)||i.$setViewValue(n.configuration)}),i.$render=function(){n.configuration=i.$viewValue},e(a.contents())(n)};return{restrict:"E",require:"^ngModel",scope:{},link:n}}r.$inject=["$compile","$mdConstant"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=r;var i=n(23),o=a(i)},function(e,t,n){"use strict";function a(e){return e&&e.__esModule?e:{default:e}}function r(e){var t=function(t,n,a,r){var i=o.default;n.html(i),t.$watch("configuration",function(e,n){angular.equals(e,n)||r.$setViewValue(t.configuration)}),r.$render=function(){t.configuration=r.$viewValue},e(n.contents())(t)};return{restrict:"E",require:"^ngModel",scope:{},link:t}}r.$inject=["$compile"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=r;var i=n(24),o=a(i)},function(e,t,n){"use strict";function a(e){return e&&e.__esModule?e:{default:e}}function r(e){var t=function(t,n,a,r){var i=o.default;n.html(i),t.$watch("configuration",function(e,n){angular.equals(e,n)||r.$setViewValue(t.configuration)}),r.$render=function(){t.configuration=r.$viewValue},e(n.contents())(t)};return{restrict:"E",require:"^ngModel",scope:{},link:t}}r.$inject=["$compile"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=r;var i=n(25),o=a(i)},function(e,t,n){"use strict";function a(e){return e&&e.__esModule?e:{default:e}}function r(e){var t=function(t,n,a,r){var i=o.default;n.html(i),t.$watch("configuration",function(e,n){angular.equals(e,n)||r.$setViewValue(t.configuration)}),r.$render=function(){t.configuration=r.$viewValue},e(n.contents())(t)};return{restrict:"E",require:"^ngModel",scope:{},link:t}}r.$inject=["$compile"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=r;var i=n(26),o=a(i)},function(e,t,n){"use strict";function a(e){return e&&e.__esModule?e:{default:e}}function r(e,t){var n=function(n,a,r,i){var l=o.default;a.html(l),n.types=t,n.$watch("configuration",function(e,t){angular.equals(e,t)||i.$setViewValue(n.configuration)}),i.$render=function(){n.configuration=i.$viewValue},e(a.contents())(n)};return{restrict:"E",require:"^ngModel",scope:{},link:n}}r.$inject=["$compile","types"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=r;var i=n(27),o=a(i)},function(e,t,n){"use strict";function a(e){return e&&e.__esModule?e:{default:e}}Object.defineProperty(t,"__esModule",{value:!0});var r=n(64),i=a(r),o=n(63),l=a(o),s=n(65),u=a(s),d=n(61),c=a(d);t.default=angular.module("thingsboard.ruleChain.config.filter",[]).directive("tbFilterNodeScriptConfig",i.default).directive("tbFilterNodeMessageTypeConfig",l.default).directive("tbFilterNodeSwitchConfig",u.default).directive("tbFilterNodeCheckRelationConfig",c.default).name},function(e,t,n){"use strict";function a(e){return e&&e.__esModule?e:{default:e}}function r(e,t,n){var a=function(a,r,i,l){function s(){if(l.$viewValue){for(var e=[],t=0;t<a.messageTypes.length;t++)e.push(a.messageTypes[t].value);l.$viewValue.messageTypes=e,u()}}function u(){if(a.required){var e=!(!l.$viewValue.messageTypes||!l.$viewValue.messageTypes.length);l.$setValidity("messageTypes",e)}else l.$setValidity("messageTypes",!0)}var d=o.default;r.html(d),a.selectedMessageType=null,a.messageTypeSearchText=null,a.ngModelCtrl=l;var c=[];for(var m in n.messageType){var p={name:n.messageType[m].name,value:n.messageType[m].value};c.push(p)}a.transformMessageTypeChip=function(e){ | |
3 | -var n,a=t("filter")(c,{name:e},!0);return n=a&&a.length?angular.copy(a[0]):{name:e,value:e}},a.messageTypesSearch=function(e){var n=e?t("filter")(c,{name:e}):c;return n.map(function(e){return e.name})},a.createMessageType=function(e,t){var n=angular.element(t,r)[0].firstElementChild,a=angular.element(n),i=a.scope().$mdChipsCtrl.getChipBuffer();e.preventDefault(),e.stopPropagation(),a.scope().$mdChipsCtrl.appendChip(i.trim()),a.scope().$mdChipsCtrl.resetChipBuffer()},l.$render=function(){var e=l.$viewValue,t=[];if(e&&e.messageTypes)for(var r=0;r<e.messageTypes.length;r++){var i=e.messageTypes[r];n.messageType[i]?t.push(angular.copy(n.messageType[i])):t.push({name:i,value:i})}a.messageTypes=t,a.$watch("messageTypes",function(e,t){angular.equals(e,t)||s()},!0)},e(r.contents())(a)};return{restrict:"E",require:"^ngModel",scope:{required:"=ngRequired",readonly:"=ngReadonly"},link:a}}r.$inject=["$compile","$filter","ruleNodeTypes"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=r,n(3);var i=n(28),o=a(i)},function(e,t,n){"use strict";function a(e){return e&&e.__esModule?e:{default:e}}function r(e,t,n){var a=function(a,r,i,l){var s=o.default;r.html(s),a.$watch("configuration",function(e,t){angular.equals(e,t)||l.$setViewValue(a.configuration)}),l.$render=function(){a.configuration=l.$viewValue},a.testScript=function(e){var r=angular.copy(a.configuration.jsScript);n.testNodeScript(e,r,"filter",t.instant("tb.rulenode.filter")+"","Filter",["msg","metadata","msgType"],a.ruleNodeId).then(function(e){a.configuration.jsScript=e,l.$setDirty()})},e(r.contents())(a)};return{restrict:"E",require:"^ngModel",scope:{ruleNodeId:"="},link:a}}r.$inject=["$compile","$translate","ruleNodeScriptTest"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=r;var i=n(29),o=a(i)},function(e,t,n){"use strict";function a(e){return e&&e.__esModule?e:{default:e}}function r(e,t,n){var a=function(a,r,i,l){var s=o.default;r.html(s),a.$watch("configuration",function(e,t){angular.equals(e,t)||l.$setViewValue(a.configuration)}),l.$render=function(){a.configuration=l.$viewValue},a.testScript=function(e){var r=angular.copy(a.configuration.jsScript);n.testNodeScript(e,r,"switch",t.instant("tb.rulenode.switch")+"","Switch",["msg","metadata","msgType"],a.ruleNodeId).then(function(e){a.configuration.jsScript=e,l.$setDirty()})},e(r.contents())(a)};return{restrict:"E",require:"^ngModel",scope:{ruleNodeId:"="},link:a}}r.$inject=["$compile","$translate","ruleNodeScriptTest"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=r;var i=n(30),o=a(i)},function(e,t,n){"use strict";function a(e){return e&&e.__esModule?e:{default:e}}function r(e){var t=function(t,n,a,r){function i(e){e>-1&&t.kvList.splice(e,1)}function l(){t.kvList||(t.kvList=[]),t.kvList.push({key:"",value:""})}function s(){var e={};t.kvList.forEach(function(t){t.key&&(e[t.key]=t.value)}),r.$setViewValue(e),u()}function u(){var e=!0;t.required&&!t.kvList.length&&(e=!1),r.$setValidity("kvMap",e)}var d=o.default;n.html(d),t.ngModelCtrl=r,t.removeKeyVal=i,t.addKeyVal=l,t.kvList=[],t.$watch("query",function(e,n){angular.equals(e,n)||r.$setViewValue(t.query)}),r.$render=function(){if(r.$viewValue){var e=r.$viewValue;t.kvList.length=0;for(var n in e)t.kvList.push({key:n,value:e[n]})}t.$watch("kvList",function(e,t){angular.equals(e,t)||s()},!0),u()},e(n.contents())(t)};return{restrict:"E",require:"^ngModel",scope:{required:"=ngRequired",disabled:"=ngDisabled",requiredText:"=",keyText:"=",keyRequiredText:"=",valText:"=",valRequiredText:"="},link:t}}r.$inject=["$compile"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=r;var i=n(31),o=a(i);n(4)},function(e,t,n){"use strict";function a(e){return e&&e.__esModule?e:{default:e}}function r(e,t){var n=function(n,a,r,i){var l=o.default;a.html(l),n.types=t,n.$watch("query",function(e,t){angular.equals(e,t)||i.$setViewValue(n.query)}),i.$render=function(){n.query=i.$viewValue},e(a.contents())(n)};return{restrict:"E",require:"^ngModel",scope:{},link:n}}r.$inject=["$compile","types"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=r;var i=n(32),o=a(i)},function(e,t,n){"use strict";function a(e){return e&&e.__esModule?e:{default:e}}function r(e,t){var n=function(n,a,r,i){var l=o.default;a.html(l),n.ruleNodeTypes=t,n.$watch("configuration",function(e,t){angular.equals(e,t)||i.$setViewValue(n.configuration)}),i.$render=function(){n.configuration=i.$viewValue},e(a.contents())(n)};return{restrict:"E",require:"^ngModel",scope:{},link:n}}r.$inject=["$compile","ruleNodeTypes"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=r;var i=n(33),o=a(i)},function(e,t,n){"use strict";function a(e){return e&&e.__esModule?e:{default:e}}Object.defineProperty(t,"__esModule",{value:!0});var r=n(68),i=a(r),o=n(70),l=a(o),s=n(71),u=a(s);t.default=angular.module("thingsboard.ruleChain.config.transform",[]).directive("tbTransformationNodeChangeOriginatorConfig",i.default).directive("tbTransformationNodeScriptConfig",l.default).directive("tbTransformationNodeToEmailConfig",u.default).name},function(e,t,n){"use strict";function a(e){return e&&e.__esModule?e:{default:e}}function r(e,t,n){var a=function(a,r,i,l){var s=o.default;r.html(s),a.$watch("configuration",function(e,t){angular.equals(e,t)||l.$setViewValue(a.configuration)}),l.$render=function(){a.configuration=l.$viewValue},a.testScript=function(e){var r=angular.copy(a.configuration.jsScript);n.testNodeScript(e,r,"update",t.instant("tb.rulenode.transformer")+"","Transform",["msg","metadata","msgType"],a.ruleNodeId).then(function(e){a.configuration.jsScript=e,l.$setDirty()})},e(r.contents())(a)};return{restrict:"E",require:"^ngModel",scope:{ruleNodeId:"="},link:a}}r.$inject=["$compile","$translate","ruleNodeScriptTest"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=r;var i=n(34),o=a(i)},function(e,t,n){"use strict";function a(e){return e&&e.__esModule?e:{default:e}}function r(e){var t=function(t,n,a,r){var i=o.default;n.html(i),t.$watch("configuration",function(e,n){angular.equals(e,n)||r.$setViewValue(t.configuration)}),r.$render=function(){t.configuration=r.$viewValue},e(n.contents())(t)};return{restrict:"E",require:"^ngModel",scope:{},link:t}}r.$inject=["$compile"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=r;var i=n(35),o=a(i)},function(e,t,n){"use strict";function a(e){return e&&e.__esModule?e:{default:e}}Object.defineProperty(t,"__esModule",{value:!0});var r=n(75),i=a(r),o=n(62),l=a(o),s=n(56),u=a(s),d=n(69),c=a(d),m=n(40),p=a(m),g=n(53),f=a(g),b=n(67),v=a(b),y=n(52),q=a(y),h=n(66),T=a(h),$=n(74),k=a($);t.default=angular.module("thingsboard.ruleChain.config",[i.default,l.default,u.default,c.default,p.default]).directive("tbNodeEmptyConfig",f.default).directive("tbRelationsQueryConfig",v.default).directive("tbDeviceRelationsQueryConfig",q.default).directive("tbKvMapConfig",T.default).config(k.default).name},function(e,t){"use strict";function n(e){var t={tb:{rulenode:{filter:"Filter",switch:"Switch","message-type":"Message type","message-type-required":"Message type is required.","message-types-filter":"Message types filter","no-message-types-found":"No message types found","no-message-type-matching":"'{{messageType}}' not found.","create-new-message-type":"Create a new one!","message-types-required":"Message types are required.","client-attributes":"Client attributes","shared-attributes":"Shared attributes","server-attributes":"Server attributes","latest-timeseries":"Latest timeseries","relations-query":"Relations query","device-relations-query":"Device relations query","max-relation-level":"Max relation level","unlimited-level":"Unlimited level","latest-telemetry":"Latest telemetry","attr-mapping":"Attributes mapping","source-attribute":"Source attribute","source-attribute-required":"Source attribute is required.","source-telemetry":"Source telemetry","source-telemetry-required":"Source telemetry is required.","target-attribute":"Target attribute","target-attribute-required":"Target attribute is required.","attr-mapping-required":"At least one attribute mapping should be specified.","fields-mapping":"Fields mapping","fields-mapping-required":"At least one field mapping should be specified.","source-field":"Source field","source-field-required":"Source field is required.","originator-source":"Originator source","originator-customer":"Customer","originator-tenant":"Tenant","originator-related":"Related","clone-message":"Clone message",transform:"Transform","default-ttl":"Default TTL in seconds","default-ttl-required":"Default TTL is required.","min-default-ttl-message":"Only 0 minimum TTL is allowed.","message-count":"Message count (0 - unlimited)","message-count-required":"Message count is required.","min-message-count-message":"Only 0 minimum message count is allowed.","period-seconds":"Period in seconds","period-seconds-required":"Period is required.","min-period-seconds-message":"Only 1 second minimum period is allowed.",originator:"Originator","message-body":"Message body","message-metadata":"Message metadata",generate:"Generate","test-generator-function":"Test generator function",generator:"Generator","test-filter-function":"Test filter function","test-switch-function":"Test switch function","test-transformer-function":"Test transformer function",transformer:"Transformer","alarm-create-condition":"Alarm create condition","test-condition-function":"Test condition function","alarm-clear-condition":"Alarm clear condition","alarm-details-builder":"Alarm details builder","test-details-function":"Test details function","alarm-type":"Alarm type","alarm-type-required":"Alarm type is required.","alarm-severity":"Alarm severity","alarm-severity-required":"Alarm severity is required",propagate:"Propagate",condition:"Condition",details:"Details","to-string":"To string","test-to-string-function":"Test to string function","from-template":"From Template","from-template-required":"From Template is required","from-template-hint":"From address template, use <code>${metaKeyName}</code> to substitute variables from metadata","to-template":"To Template","to-template-required":"To Template is required","mail-address-list-template-hint":"Comma separated address list, use <code>${metaKeyName}</code> to substitute variables from metadata","cc-template":"Cc Template","bcc-template":"Bcc Template","subject-template":"Subject Template","subject-template-required":"Subject Template is required","subject-template-hint":"Mail subject template, use <code>${metaKeyName}</code> to substitute variables from metadata","body-template":"Body Template","body-template-required":"Body Template is required","body-template-hint":"Mail body template, use <code>${metaKeyName}</code> to substitute variables from metadata","request-id-metadata-attribute":"Request Id Metadata attribute name","timeout-sec":"Timeout in seconds","timeout-required":"Timeout is required","min-timeout-message":"Only 0 minimum timeout value is allowed.","endpoint-url-pattern":"Endpoint URL pattern","endpoint-url-pattern-required":"Endpoint URL pattern is required","endpoint-url-pattern-hint":"HTTP URL address pattern, use <code>${metaKeyName}</code> to substitute variables from metadata","request-method":"Request method",headers:"Headers","headers-hint":"Use <code>${metaKeyName}</code> in header/value fields to substitute variables from metadata",header:"Header","header-required":"Header is required",value:"Value","value-required":"Value is required","topic-pattern":"Topic pattern","topic-pattern-required":"Topic pattern is required","mqtt-topic-pattern-hint":"MQTT topic pattern, use <code>${metaKeyName}</code> to substitute variables from metadata","bootstrap-servers":"Bootstrap servers","bootstrap-servers-required":"Bootstrap servers value is required","other-properties":"Other properties",key:"Key","key-required":"Key is required",retries:"Automatically retry times if fails","min-retries-message":"Only 0 minimum retries is allowed.","batch-size-bytes":"Produces batch size in bytes","min-batch-size-bytes-message":"Only 0 minimum batch size is allowed.","linger-ms":"Time to buffer locally (ms)","min-linger-ms-message":"Only 0 ms minimum value is allowed.","buffer-memory-bytes":"Client buffer max size in bytes","min-buffer-memory-message":"Only 0 minimum buffer size is allowed.",acks:"Number of acknowledgments","key-serializer":"Key serializer","key-serializer-required":"Key serializer is required","value-serializer":"Value serializer","value-serializer-required":"Value serializer is required","topic-arn-pattern":"Topic ARN pattern","topic-arn-pattern-required":"Topic ARN pattern is required","topic-arn-pattern-hint":"Topic ARN pattern, use <code>${metaKeyName}</code> to substitute variables from metadata","aws-access-key-id":"AWS Access Key ID","aws-access-key-id-required":"AWS Access Key ID is required","aws-secret-access-key":"AWS Secret Access Key","aws-secret-access-key-required":"AWS Secret Access Key is required","aws-region":"AWS Region","aws-region-required":"AWS Region is required","exchange-name-pattern":"Exchange name pattern","routing-key-pattern":"Routing key pattern","message-properties":"Message properties",host:"Host","host-required":"Host is required",port:"Port","port-required":"Port is required","port-range":"Port should be in a range from 1 to 65535.","virtual-host":"Virtual host",username:"Username",password:"Password","automatic-recovery":"Automatic recovery","connection-timeout-ms":"Connection timeout (ms)","min-connection-timeout-ms-message":"Only 0 ms minimum value is allowed.","handshake-timeout-ms":"Handshake timeout (ms)","min-handshake-timeout-ms-message":"Only 0 ms minimum value is allowed.","client-properties":"Client properties","queue-url-pattern":"Queue URL pattern","queue-url-pattern-required":"Queue URL pattern is required","queue-url-pattern-hint":"Queue URL pattern, use <code>${metaKeyName}</code> to substitute variables from metadata","delay-seconds":"Delay (seconds)","min-delay-seconds-message":"Only 0 seconds minimum value is allowed.","max-delay-seconds-message":"Only 900 seconds maximum value is allowed.",name:"Name","name-required":"Name is required","queue-type":"Queue type","sqs-queue-standard":"Standard","sqs-queue-fifo":"FIFO","message-attributes":"Message attributes","message-attributes-hint":"Use <code>${metaKeyName}</code> in name/value fields to substitute variables from metadata","connect-timeout":"Connection timeout (sec)","connect-timeout-required":"Connection timeout is required.","connect-timeout-range":"Connection timeout should be in a range from 1 to 200.","client-id":"Client ID","enable-ssl":"Enable SSL",credentials:"Credentials","credentials-type":"Credentials type","credentials-type-required":"Credentials type is required.","credentials-anonymous":"Anonymous","credentials-basic":"Basic","credentials-pem":"PEM","username-required":"Username is required.","password-required":"Password is required.","ca-cert":"CA certificate file *","private-key":"Private key file *",cert:"Certificate file *","no-file":"No file selected.","drop-file":"Drop a file or click to select a file to upload.","private-key-password":"Private key password","use-system-smtp-settings":"Use system SMTP settings","smtp-protocol":"Protocol","smtp-host":"SMTP host","smtp-host-required":"SMTP host is required.","smtp-port":"SMTP port","smtp-port-required":"You must supply a smtp port.","smtp-port-range":"SMTP port should be in a range from 1 to 65535.","timeout-msec":"Timeout ms","min-timeout-msec-message":"Only 0 ms minimum value is allowed.","enter-username":"Enter username","enter-password":"Enter password","enable-tls":"Enable TLS"},"key-val":{key:"Key",value:"Value","remove-entry":"Remove entry","add-entry":"Add entry"}}};angular.merge(e.en_US,t)}Object.defineProperty(t,"__esModule",{value:!0}),t.default=n},function(e,t,n){"use strict";function a(e){return e&&e.__esModule?e:{default:e}}function r(e,t){(0,o.default)(t);for(var n in t){var a=t[n];e.translations(n,a)}}r.$inject=["$translateProvider","locales"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=r;var i=n(73),o=a(i)},function(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=angular.module("thingsboard.ruleChain.config.types",[]).constant("ruleNodeTypes",{messageType:{POST_ATTRIBUTES_REQUEST:{name:"Post attributes",value:"POST_ATTRIBUTES_REQUEST"},POST_TELEMETRY_REQUEST:{name:"Post telemetry",value:"POST_TELEMETRY_REQUEST"},TO_SERVER_RPC_REQUEST:{name:"RPC Request from Device",value:"TO_SERVER_RPC_REQUEST"},RPC_CALL_FROM_SERVER_TO_DEVICE:{name:"RPC Request to Device",value:"RPC_CALL_FROM_SERVER_TO_DEVICE"},ACTIVITY_EVENT:{name:"Activity Event",value:"ACTIVITY_EVENT"},INACTIVITY_EVENT:{name:"Inactivity Event",value:"INACTIVITY_EVENT"},CONNECT_EVENT:{name:"Connect Event",value:"CONNECT_EVENT"},DISCONNECT_EVENT:{name:"Disconnect Event",value:"DISCONNECT_EVENT"},ENTITY_CREATED:{name:"Entity Created",value:"ENTITY_CREATED"},ENTITY_UPDATED:{name:"Entity Updated",value:"ENTITY_UPDATED"},ENTITY_DELETED:{name:"Entity Deleted",value:"ENTITY_DELETED"},ENTITY_ASSIGNED:{name:"Entity Assigned",value:"ENTITY_ASSIGNED"},ENTITY_UNASSIGNED:{name:"Entity Unassigned",value:"ENTITY_UNASSIGNED"},ATTRIBUTES_UPDATED:{name:"Attributes Updated",value:"ATTRIBUTES_UPDATED"},ATTRIBUTES_DELETED:{name:"Attributes Deleted",value:"ATTRIBUTES_DELETED"}},originatorSource:{CUSTOMER:{name:"tb.rulenode.originator-customer",value:"CUSTOMER"},TENANT:{name:"tb.rulenode.originator-tenant",value:"TENANT"},RELATED:{name:"tb.rulenode.originator-related",value:"RELATED"}},httpRequestType:["GET","POST","PUT","DELETE"],sqsQueueType:{STANDARD:{name:"tb.rulenode.sqs-queue-standard",value:"STANDARD"},FIFO:{name:"tb.rulenode.sqs-queue-fifo",value:"FIFO"}},mqttCredentialTypes:{anonymous:{value:"anonymous",name:"tb.rulenode.credentials-anonymous"},basic:{value:"basic",name:"tb.rulenode.credentials-basic"},"cert.PEM":{value:"cert.PEM",name:"tb.rulenode.credentials-pem"}}}).name}])); | |
1 | +!function(e){function t(a){if(n[a])return n[a].exports;var r=n[a]={exports:{},id:a,loaded:!1};return e[a].call(r.exports,r,r.exports,t),r.loaded=!0,r.exports}var n={};return t.m=e,t.c=n,t.p="/static/",t(0)}(function(e){for(var t in e)if(Object.prototype.hasOwnProperty.call(e,t))switch(typeof e[t]){case"function":break;case"object":e[t]=function(t){var n=t.slice(1),a=e[t[0]];return function(e,t,r){a.apply(this,[e,t,r].concat(n))}}(e[t]);break;default:e[t]=e[e[t]]}return e}([function(e,t,n){e.exports=n(72)},function(e,t){},1,1,1,function(e,t){e.exports=' <section ng-form name=attributesConfigForm layout=column> <md-input-container class=md-block> <label translate>attribute.attributes-scope</label> <md-select ng-model=configuration.scope ng-disabled=$root.loading> <md-option ng-repeat="scope in types.attributesScope" ng-value=scope.value> {{scope.name | translate}} </md-option> </md-select> </md-input-container> </section> '},function(e,t){e.exports=" <section class=tb-alarm-config ng-form name=alarmConfigForm layout=column> <label translate class=\"tb-title no-padding\">tb.rulenode.alarm-details-builder</label> <tb-js-func ng-model=configuration.alarmDetailsBuildJs function-name=Details function-args=\"{{ ['msg', 'metadata', 'msgType'] }}\" no-validate=true> </tb-js-func> <div layout=row style=padding-bottom:15px> <md-button ng-click=testDetailsBuildJs($event) class=\"md-primary md-raised\"> {{ 'tb.rulenode.test-details-function' | translate }} </md-button> </div> <md-input-container class=md-block> <label translate>tb.rulenode.alarm-type</label> <input ng-required=true name=alarmType ng-model=configuration.alarmType> <div ng-messages=alarmConfigForm.alarmType.$error> <div ng-message=required translate>tb.rulenode.alarm-type-required</div> </div> </md-input-container> </section> "},function(e,t){e.exports=" <section class=tb-alarm-config ng-form name=alarmConfigForm layout=column> <label translate class=\"tb-title no-padding\">tb.rulenode.alarm-details-builder</label> <tb-js-func ng-model=configuration.alarmDetailsBuildJs function-name=Details function-args=\"{{ ['msg', 'metadata', 'msgType'] }}\" no-validate=true> </tb-js-func> <div layout=row style=padding-bottom:15px> <md-button ng-click=testDetailsBuildJs($event) class=\"md-primary md-raised\"> {{ 'tb.rulenode.test-details-function' | translate }} </md-button> </div> <section layout=column layout-gt-sm=row> <md-input-container flex class=md-block> <label translate>tb.rulenode.alarm-type</label> <input ng-required=true name=alarmType ng-model=configuration.alarmType> <div ng-messages=alarmConfigForm.alarmType.$error> <div ng-message=required translate>tb.rulenode.alarm-type-required</div> </div> </md-input-container> <md-input-container flex class=md-block> <label translate>tb.rulenode.alarm-severity</label> <md-select required name=severity ng-model=configuration.severity> <md-option ng-repeat=\"(severityKey, severity) in types.alarmSeverity\" ng-value=severityKey> {{ severity.name | translate}} </md-option> </md-select> <div ng-messages=alarmConfigForm.severity.$error> <div ng-message=required translate>tb.rulenode.alarm-severity-required</div> </div> </md-input-container> </section> <md-checkbox aria-label=\"{{ 'tb.rulenode.propagate' | translate }}\" ng-model=configuration.propagate>{{ 'tb.rulenode.propagate' | translate }} </md-checkbox> </section> "},function(e,t){e.exports=" <section class=tb-generator-config ng-form name=generatorConfigForm layout=column> <md-input-container class=md-block> <label translate>tb.rulenode.message-count</label> <input ng-required=true type=number step=1 name=messageCount ng-model=configuration.msgCount min=0> <div ng-messages=generatorConfigForm.messageCount.$error multiple=multiple md-auto-hide=false> <div ng-message=required translate>tb.rulenode.message-count-required</div> <div ng-message=min translate>tb.rulenode.min-message-count-message</div> </div> </md-input-container> <md-input-container class=md-block> <label translate>tb.rulenode.period-seconds</label> <input ng-required=true type=number step=1 name=periodInSeconds ng-model=configuration.periodInSeconds min=1> <div ng-messages=generatorConfigForm.periodInSeconds.$error multiple=multiple md-auto-hide=false> <div ng-message=required translate>tb.rulenode.period-seconds-required</div> <div ng-message=min translate>tb.rulenode.min-period-seconds-message</div> </div> </md-input-container> <div layout=column> <label class=tb-small>{{ 'tb.rulenode.originator' | translate }}</label> <tb-entity-select the-form=generatorConfigForm tb-required=false ng-model=originator> </tb-entity-select> </div> <label translate class=\"tb-title no-padding\">tb.rulenode.generate</label> <tb-js-func ng-model=configuration.jsScript function-name=Generate function-args=\"{{ ['prevMsg', 'prevMetadata', 'prevMsgType'] }}\" no-validate=true> </tb-js-func> <div layout=row> <md-button ng-click=testScript($event) class=\"md-primary md-raised\"> {{ 'tb.rulenode.test-generator-function' | translate }} </md-button> </div> </section> "},function(e,t){e.exports=' <section ng-form name=kafkaConfigForm layout=column> <md-input-container class=md-block> <label translate>tb.rulenode.topic-pattern</label> <input ng-required=true name=topicPattern ng-model=configuration.topicPattern> <div ng-messages=kafkaConfigForm.topicPattern.$error> <div ng-message=required translate>tb.rulenode.topic-pattern-required</div> </div> </md-input-container> <md-input-container class=md-block> <label translate>tb.rulenode.bootstrap-servers</label> <input ng-required=true name=bootstrapServers ng-model=configuration.bootstrapServers> <div ng-messages=kafkaConfigForm.bootstrapServers.$error> <div ng-message=required translate>tb.rulenode.bootstrap-servers-required</div> </div> </md-input-container> <md-input-container class=md-block> <label translate>tb.rulenode.retries</label> <input type=number step=1 name=retries ng-model=configuration.retries min=0> <div ng-messages=kafkaConfigForm.retries.$error> <div ng-message=min translate>tb.rulenode.min-retries-message</div> </div> </md-input-container> <md-input-container class=md-block> <label translate>tb.rulenode.batch-size-bytes</label> <input type=number step=1 name=batchSize ng-model=configuration.batchSize min=0> <div ng-messages=kafkaConfigForm.batchSize.$error> <div ng-message=min translate>tb.rulenode.min-batch-size-bytes-message</div> </div> </md-input-container> <md-input-container class=md-block> <label translate>tb.rulenode.linger-ms</label> <input type=number step=1 name=linger ng-model=configuration.linger min=0> <div ng-messages=kafkaConfigForm.linger.$error> <div ng-message=min translate>tb.rulenode.min-linger-ms-message</div> </div> </md-input-container> <md-input-container class=md-block> <label translate>tb.rulenode.buffer-memory-bytes</label> <input type=number step=1 name=bufferMemory ng-model=configuration.bufferMemory min=0> <div ng-messages=kafkaConfigForm.bufferMemory.$error> <div ng-message=min translate>tb.rulenode.min-buffer-memory-bytes-message</div> </div> </md-input-container> <md-input-container class=md-block> <label translate>tb.rulenode.acks</label> <md-select ng-model=configuration.acks ng-disabled=$root.loading> <md-option ng-repeat="ackValue in ackValues" ng-value=ackValue> {{ ackValue }} </md-option> </md-select> </md-input-container> <md-input-container class=md-block> <label translate>tb.rulenode.key-serializer</label> <input ng-required=true name=keySerializer ng-model=configuration.keySerializer> <div ng-messages=kafkaConfigForm.keySerializer.$error> <div ng-message=required translate>tb.rulenode.key-serializer-required</div> </div> </md-input-container> <md-input-container class=md-block> <label translate>tb.rulenode.value-serializer</label> <input ng-required=true name=valueSerializer ng-model=configuration.valueSerializer> <div ng-messages=kafkaConfigForm.valueSerializer.$error> <div ng-message=required translate>tb.rulenode.value-serializer-required</div> </div> </md-input-container> <label translate class=tb-title>tb.rulenode.other-properties</label> <tb-kv-map-config ng-model=configuration.otherProperties ng-required=false key-text="\'tb.rulenode.key\'" key-required-text="\'tb.rulenode.key-required\'" val-text="\'tb.rulenode.value\'" val-required-text="\'tb.rulenode.value-required\'"> </tb-kv-map-config> </section> '},function(e,t){e.exports=" <section layout=column> <label translate class=\"tb-title no-padding\">tb.rulenode.to-string</label> <tb-js-func ng-model=configuration.jsScript function-name=ToString function-args=\"{{ ['msg', 'metadata', 'msgType'] }}\" no-validate=true> </tb-js-func> <div layout=row> <md-button ng-click=testScript($event) class=\"md-primary md-raised\"> {{ 'tb.rulenode.test-to-string-function' | translate }} </md-button> </div> </section> "},function(e,t){e.exports=' <section class=tb-mqtt-config ng-form name=mqttConfigForm layout=column> <md-input-container class=md-block> <label translate>tb.rulenode.topic-pattern</label> <input ng-required=true name=topicPattern ng-model=configuration.topicPattern> <div ng-messages=mqttConfigForm.topicPattern.$error> <div translate ng-message=required>tb.rulenode.topic-pattern-required</div> </div> <div class=tb-hint translate>tb.rulenode.mqtt-topic-pattern-hint</div> </md-input-container> <div flex layout=column layout-gt-sm=row> <md-input-container flex=60 class=md-block> <label translate>tb.rulenode.host</label> <input ng-required=true name=host ng-model=configuration.host> <div ng-messages=mqttConfigForm.host.$error> <div translate ng-message=required>tb.rulenode.host-required</div> </div> </md-input-container> <md-input-container flex=40 class=md-block> <label translate>tb.rulenode.port</label> <input type=number step=1 min=1 max=65535 ng-required=true name=port ng-model=configuration.port> <div ng-messages=mqttConfigForm.port.$error> <div translate ng-message=required>tb.rulenode.port-required</div> <div translate ng-message=min>tb.rulenode.port-range</div> <div translate ng-message=max>tb.rulenode.port-range</div> </div> </md-input-container> <md-input-container flex=40 class=md-block> <label translate>tb.rulenode.connect-timeout</label> <input type=number step=1 min=1 max=200 ng-required=true name=connectTimeoutSec ng-model=configuration.connectTimeoutSec> <div ng-messages=mqttConfigForm.connectTimeoutSec.$error> <div translate ng-message=required>tb.rulenode.connect-timeout-required</div> <div translate ng-message=min>tb.rulenode.connect-timeout-range</div> <div translate ng-message=max>tb.rulenode.connect-timeout-range</div> </div> </md-input-container> </div> <md-input-container class=md-block> <label translate>tb.rulenode.client-id</label> <input name=clientId ng-model=configuration.clientId> </md-input-container> <md-checkbox ng-disabled="$root.loading || readonly" aria-label="{{ \'tb.rulenode.clean-session\' | translate }}" ng-model=configuration.cleanSession> {{ \'tb.rulenode.clean-session\' | translate }} </md-checkbox> <md-checkbox ng-disabled="$root.loading || readonly" aria-label="{{ \'tb.rulenode.enable-ssl\' | translate }}" ng-model=configuration.ssl> {{ \'tb.rulenode.enable-ssl\' | translate }} </md-checkbox> <md-expansion-panel-group class=tb-credentials-panel-group ng-class="{\'disabled\': $root.loading || readonly}" md-component-id=credentialsPanelGroup> <md-expansion-panel md-component-id=credentialsPanel> <md-expansion-panel-collapsed> <div class=tb-panel-title>{{ \'tb.rulenode.credentials\' | translate }}</div> <div class=tb-panel-prompt>{{ ruleNodeTypes.mqttCredentialTypes[configuration.credentials.type].name | translate }}</div> <span flex></span> <md-expansion-panel-icon></md-expansion-panel-icon> </md-expansion-panel-collapsed> <md-expansion-panel-expanded> <md-expansion-panel-header ng-click="$mdExpansionPanel(\'credentialsPanel\').collapse()"> <div class=tb-panel-title>{{ \'tb.rulenode.credentials\' | translate }}</div> <div class=tb-panel-prompt>{{ ruleNodeTypes.mqttCredentialTypes[configuration.credentials.type].name | translate }}</div> <span flex></span> <md-expansion-panel-icon></md-expansion-panel-icon> </md-expansion-panel-header> <md-expansion-panel-content> <div layout=column> <md-input-container class=md-block> <label translate>tb.rulenode.credentials-type</label> <md-select ng-required=true name=credentialsType ng-model=configuration.credentials.type ng-disabled="$root.loading || readonly" ng-change=credentialsTypeChanged()> <md-option ng-repeat="(credentialsType, credentialsValue) in ruleNodeTypes.mqttCredentialTypes" ng-value=credentialsValue.value> {{credentialsValue.name | translate}} </md-option> </md-select> <div ng-messages=mqttConfigForm.credentialsType.$error> <div translate ng-message=required>tb.rulenode.credentials-type-required</div> </div> </md-input-container> <section flex layout=column ng-if="configuration.credentials.type == ruleNodeTypes.mqttCredentialTypes.basic.value"> <md-input-container class=md-block> <label translate>tb.rulenode.username</label> <input ng-required=true name=mqttUsername ng-model=configuration.credentials.username> <div ng-messages=mqttConfigForm.mqttUsername.$error> <div translate ng-message=required>tb.rulenode.username-required</div> </div> </md-input-container> <md-input-container class=md-block> <label translate>tb.rulenode.password</label> <input type=password ng-required=true name=mqttPassword ng-model=configuration.credentials.password> <div ng-messages=mqttConfigForm.mqttPassword.$error> <div translate ng-message=required>tb.rulenode.password-required</div> </div> </md-input-container> </section> <section flex layout=column ng-if="configuration.credentials.type == ruleNodeTypes.mqttCredentialTypes[\'cert.PEM\'].value" class=dropdown-section> <div class=tb-container ng-class="configuration.credentials.caCertFileName ? \'ng-valid\' : \'ng-invalid\'"> <label class=tb-label translate>tb.rulenode.ca-cert</label> <div flow-init={singleFile:true} flow-file-added="certFileAdded($file, \'caCert\')" class=tb-file-select-container> <div class=tb-file-clear-container> <md-button ng-click="clearCertFile(\'caCert\')" class="tb-file-clear-btn md-icon-button md-primary" aria-label="{{ \'action.remove\' | translate }}"> <md-tooltip md-direction=top> {{ \'action.remove\' | translate }} </md-tooltip> <md-icon aria-label="{{ \'action.remove\' | translate }}" class=material-icons>close</md-icon> </md-button> </div> <div class="alert tb-flow-drop" flow-drop> <label for=caCertSelect translate>tb.rulenode.drop-file</label> <input class=file-input flow-btn id=caCertSelect> </div> </div> </div> <div class=dropdown-messages> <div ng-if=!configuration.credentials.caCertFileName class=tb-error-message translate>tb.rulenode.no-file</div> <div ng-if=configuration.credentials.caCertFileName>{{configuration.credentials.caCertFileName}}</div> </div> <div class=tb-container ng-class="configuration.credentials.certFileName ? \'ng-valid\' : \'ng-invalid\'"> <label class=tb-label translate>tb.rulenode.cert</label> <div flow-init={singleFile:true} flow-file-added="certFileAdded($file, \'Cert\')" class=tb-file-select-container> <div class=tb-file-clear-container> <md-button ng-click="clearCertFile(\'Cert\')" class="tb-file-clear-btn md-icon-button md-primary" aria-label="{{ \'action.remove\' | translate }}"> <md-tooltip md-direction=top> {{ \'action.remove\' | translate }} </md-tooltip> <md-icon aria-label="{{ \'action.remove\' | translate }}" class=material-icons>close</md-icon> </md-button> </div> <div class="alert tb-flow-drop" flow-drop> <label for=CertSelect translate>tb.rulenode.drop-file</label> <input class=file-input flow-btn id=CertSelect> </div> </div> </div> <div class=dropdown-messages> <div ng-if=!configuration.credentials.certFileName class=tb-error-message translate>tb.rulenode.no-file</div> <div ng-if=configuration.credentials.certFileName>{{configuration.credentials.certFileName}}</div> </div> <div class=tb-container ng-class="configuration.credentials.privateKeyFileName ? \'ng-valid\' : \'ng-invalid\'"> <label class=tb-label translate>tb.rulenode.private-key</label> <div flow-init={singleFile:true} flow-file-added="certFileAdded($file, \'privateKey\')" class=tb-file-select-container> <div class=tb-file-clear-container> <md-button ng-click="clearCertFile(\'privateKey\')" class="tb-file-clear-btn md-icon-button md-primary" aria-label="{{ \'action.remove\' | translate }}"> <md-tooltip md-direction=top> {{ \'action.remove\' | translate }} </md-tooltip> <md-icon aria-label="{{ \'action.remove\' | translate }}" class=material-icons>close</md-icon> </md-button> </div> <div class="alert tb-flow-drop" flow-drop> <label for=privateKeySelect translate>tb.rulenode.drop-file</label> <input class=file-input flow-btn id=privateKeySelect> </div> </div> </div> <div class=dropdown-messages> <div ng-if=!configuration.credentials.privateKeyFileName class=tb-error-message translate>tb.rulenode.no-file</div> <div ng-if=configuration.credentials.privateKeyFileName>{{configuration.credentials.privateKeyFileName}}</div> </div> <md-input-container class=md-block> <label translate>tb.rulenode.private-key-password</label> <input type=password name=privateKeyPassword ng-model=configuration.credentials.password> </md-input-container> </section> </div> </md-expansion-panel-content> </md-expansion-panel-expanded> </md-expansion-panel> </md-expansion-panel-group> </section>'},function(e,t){e.exports=' <section ng-form name=rabbitMqConfigForm layout=column> <md-input-container class=md-block> <label translate>tb.rulenode.exchange-name-pattern</label> <input name=exchangeNamePattern ng-model=configuration.exchangeNamePattern> </md-input-container> <md-input-container class=md-block> <label translate>tb.rulenode.routing-key-pattern</label> <input name=routingKeyPattern ng-model=configuration.routingKeyPattern> </md-input-container> <md-input-container class=md-block> <label translate>tb.rulenode.message-properties</label> <md-select ng-model=configuration.messageProperties ng-disabled="$root.loading || readonly"> <md-option ng-repeat="property in messageProperties" ng-value=property> {{ property }} </md-option> </md-select> </md-input-container> <div layout-gt-sm=row> <md-input-container class=md-block flex=100 flex-gt-sm=60> <label translate>tb.rulenode.host</label> <input ng-required=true name=host ng-model=configuration.host> <div ng-messages=rabbitMqConfigForm.host.$error> <div ng-message=required translate>tb.rulenode.host-required</div> </div> </md-input-container> <md-input-container class=md-block flex=100 flex-gt-sm=40> <label translate>tb.rulenode.port</label> <input ng-required=true type=number step=1 name=port ng-model=configuration.port min=0 max=65535> <div ng-messages=rabbitMqConfigForm.port.$error> <div ng-message=required translate>tb.rulenode.port-required</div> <div ng-message=min translate>tb.rulenode.port-range</div> <div ng-message=max translate>tb.rulenode.port-range</div> </div> </md-input-container> </div> <md-input-container class=md-block> <label translate>tb.rulenode.virtual-host</label> <input name=virtualHost ng-model=configuration.virtualHost> </md-input-container> <md-input-container class=md-block> <label translate>tb.rulenode.username</label> <input name=virtualHost ng-model=configuration.username> </md-input-container> <md-input-container class=md-block> <label translate>tb.rulenode.password</label> <input name=virtualHost type=password ng-model=configuration.password> </md-input-container> <md-input-container class=md-block> <md-checkbox ng-disabled="$root.loading || readonly" aria-label="{{ \'tb.rulenode.automatic-recovery\' | translate }}" ng-model=ruleNode.automaticRecoveryEnabled>{{ \'tb.rulenode.automatic-recovery\' | translate }} </md-checkbox> </md-input-container> <md-input-container class=md-block> <label translate>tb.rulenode.connection-timeout-ms</label> <input type=number step=1 name=connectionTimeout ng-model=configuration.connectionTimeout min=0> <div ng-messages=rabbitMqConfigForm.connectionTimeout.$error> <div ng-message=min translate>tb.rulenode.min-connection-timeout-ms-message</div> </div> </md-input-container> <md-input-container class=md-block> <label translate>tb.rulenode.handshake-timeout-ms</label> <input type=number step=1 name=handshakeTimeout ng-model=configuration.handshakeTimeout min=0> <div ng-messages=rabbitMqConfigForm.handshakeTimeout.$error> <div ng-message=min translate>tb.rulenode.min-handshake-timeout-ms-message</div> </div> </md-input-container> <label translate class=tb-title>tb.rulenode.client-properties</label> <tb-kv-map-config ng-model=configuration.clientProperties ng-required=false key-text="\'tb.rulenode.key\'" key-required-text="\'tb.rulenode.key-required\'" val-text="\'tb.rulenode.value\'" val-required-text="\'tb.rulenode.value-required\'"> </tb-kv-map-config> </section> '},function(e,t){e.exports=' <section ng-form name=restApiCallConfigForm layout=column> <md-input-container class=md-block> <label translate>tb.rulenode.endpoint-url-pattern</label> <input ng-required=true name=endpointUrlPattern ng-model=configuration.restEndpointUrlPattern> <div ng-messages=restApiCallConfigForm.endpointUrlPattern.$error> <div ng-message=required translate>tb.rulenode.endpoint-url-pattern-required</div> </div> <div class=tb-hint translate>tb.rulenode.endpoint-url-pattern-hint</div> </md-input-container> <md-input-container class=md-block> <label translate>tb.rulenode.request-method</label> <md-select ng-model=configuration.requestMethod ng-disabled=$root.loading> <md-option ng-repeat="type in ruleNodeTypes.httpRequestType" ng-value=type> {{ type }} </md-option> </md-select> </md-input-container> <label translate class=tb-title>tb.rulenode.headers</label> <div class=tb-hint translate>tb.rulenode.headers-hint</div> <tb-kv-map-config ng-model=configuration.headers ng-required=false key-text="\'tb.rulenode.header\'" key-required-text="\'tb.rulenode.header-required\'" val-text="\'tb.rulenode.value\'" val-required-text="\'tb.rulenode.value-required\'"> </tb-kv-map-config> </section> '},function(e,t){e.exports=" <section ng-form name=rpcReplyConfigForm layout=column> <md-input-container class=md-block> <label translate>tb.rulenode.request-id-metadata-attribute</label> <input name=requestIdMetaDataAttribute ng-model=configuration.requestIdMetaDataAttribute> </md-input-container> </section> "},function(e,t){e.exports=" <section ng-form name=rpcRequestConfigForm layout=column> <md-input-container class=md-block> <label translate>tb.rulenode.timeout-sec</label> <input ng-required=true type=number step=1 name=timeoutInSeconds ng-model=configuration.timeoutInSeconds min=0> <div ng-messages=rpcRequestConfigForm.timeoutInSeconds.$error multiple=multiple md-auto-hide=false> <div ng-message=required translate>tb.rulenode.timeout-required</div> <div ng-message=min translate>tb.rulenode.min-timeout-message</div> </div> </md-input-container> </section> "},function(e,t){e.exports=' <section ng-form name=sendEmailConfigForm layout=column> <md-checkbox ng-disabled="$root.loading || readonly" aria-label="{{ \'tb.rulenode.use-system-smtp-settings\' | translate }}" ng-model=configuration.useSystemSmtpSettings> {{ \'tb.rulenode.use-system-smtp-settings\' | translate }} </md-checkbox> <section layout=column ng-if=!configuration.useSystemSmtpSettings> <md-input-container class=md-block> <label translate>tb.rulenode.smtp-protocol</label> <md-select ng-disabled="$root.loading || readonly" ng-model=configuration.smtpProtocol> <md-option ng-repeat="smtpProtocol in smtpProtocols" value={{smtpProtocol}}> {{smtpProtocol.toUpperCase()}} </md-option> </md-select> </md-input-container> <div layout-gt-sm=row> <md-input-container class=md-block flex=100 flex-gt-sm=60> <label translate>tb.rulenode.smtp-host</label> <input ng-required=true name=smtpHost ng-model=configuration.smtpHost> <div ng-messages=sendEmailConfigForm.smtpHost.$error> <div translate ng-message=required>tb.rulenode.smtp-host-required</div> </div> </md-input-container> <md-input-container class=md-block flex=100 flex-gt-sm=40> <label translate>tb.rulenode.smtp-port</label> <input type=number step=1 min=1 max=65535 ng-required=true name=port ng-model=configuration.smtpPort> <div ng-messages=sendEmailConfigForm.port.$error> <div translate ng-message=required>tb.rulenode.smtp-port-required</div> <div translate ng-message=min>tb.rulenode.smtp-port-range</div> <div translate ng-message=max>tb.rulenode.smtp-port-range</div> </div> </md-input-container> </div> <md-input-container class=md-block> <label translate>tb.rulenode.timeout-msec</label> <input type=number step=1 min=0 ng-required=true name=timeout ng-model=configuration.timeout> <div ng-messages=sendEmailConfigForm.timeout.$error> <div translate ng-message=required>tb.rulenode.timeout-required</div> <div translate ng-message=min>tb.rulenode.min-timeout-msec-message</div> </div> </md-input-container> <md-checkbox ng-disabled="$root.loading || readonly" aria-label="{{ \'tb.rulenode.enable-tls\' | translate }}" ng-model=configuration.enableTls>{{ \'tb.rulenode.enable-tls\' | translate }}</md-checkbox> <md-input-container class=md-block> <label translate>tb.rulenode.username</label> <input name=username placeholder="{{ \'tb.rulenode.enter-username\' | translate }}" ng-model=configuration.username> </md-input-container> <md-input-container class=md-block> <label translate>tb.rulenode.password</label> <input name=password placeholder="{{ \'tb.rulenode.enter-password\' | translate }}" type=password ng-model=configuration.password> </md-input-container> </section> </section> '},function(e,t){e.exports=" <section ng-form name=snsConfigForm layout=column> <md-input-container class=md-block> <label translate>tb.rulenode.topic-arn-pattern</label> <input ng-required=true name=topicArnPattern ng-model=configuration.topicArnPattern> <div ng-messages=snsConfigForm.topicArnPattern.$error> <div ng-message=required translate>tb.rulenode.topic-arn-pattern-required</div> </div> <div class=tb-hint translate>tb.rulenode.topic-arn-pattern-hint</div> </md-input-container> <md-input-container class=md-block> <label translate>tb.rulenode.aws-access-key-id</label> <input ng-required=true name=accessKeyId ng-model=configuration.accessKeyId> <div ng-messages=snsConfigForm.accessKeyId.$error> <div ng-message=required translate>tb.rulenode.aws-access-key-id-required</div> </div> </md-input-container> <md-input-container class=md-block> <label translate>tb.rulenode.aws-secret-access-key</label> <input ng-required=true name=secretAccessKey ng-model=configuration.secretAccessKey> <div ng-messages=snsConfigForm.secretAccessKey.$error> <div ng-message=required translate>tb.rulenode.aws-secret-access-key-required</div> </div> </md-input-container> <md-input-container class=md-block> <label translate>tb.rulenode.aws-region</label> <input ng-required=true name=region ng-model=configuration.region> <div ng-messages=snsConfigForm.region.$error> <div ng-message=required translate>tb.rulenode.aws-region-required</div> </div> </md-input-container> </section> "},function(e,t){e.exports=' <section ng-form name=sqsConfigForm layout=column> <md-input-container class=md-block> <label translate>tb.rulenode.queue-type</label> <md-select ng-model=configuration.queueType ng-disabled="$root.loading || readonly"> <md-option ng-repeat="type in ruleNodeTypes.sqsQueueType" ng-value=type.value> {{ type.name | translate }} </md-option> </md-select> </md-input-container> <md-input-container class=md-block> <label translate>tb.rulenode.queue-url-pattern</label> <input ng-required=true name=queueUrlPattern ng-model=configuration.queueUrlPattern> <div ng-messages=sqsConfigForm.queueUrlPattern.$error> <div ng-message=required translate>tb.rulenode.queue-url-pattern-required</div> </div> <div class=tb-hint translate>tb.rulenode.queue-url-pattern-hint</div> </md-input-container> <md-input-container class=md-block ng-if="configuration.queueType == ruleNodeTypes.sqsQueueType.STANDARD.value"> <label translate>tb.rulenode.delay-seconds</label> <input type=number step=1 name=delaySeconds ng-model=configuration.delaySeconds min=0 max=900> <div ng-messages=sqsConfigForm.delaySeconds.$error> <div ng-message=min translate>tb.rulenode.min-delay-seconds-message</div> <div ng-message=max translate>tb.rulenode.max-delay-seconds-message</div> </div> </md-input-container> <label translate class=tb-title>tb.rulenode.message-attributes</label> <div class=tb-hint translate>tb.rulenode.message-attributes-hint</div> <tb-kv-map-config ng-model=configuration.messageAttributes ng-required=false key-text="\'tb.rulenode.name\'" key-required-text="\'tb.rulenode.name-required\'" val-text="\'tb.rulenode.value\'" val-required-text="\'tb.rulenode.value-required\'"> </tb-kv-map-config> <md-input-container class=md-block> <label translate>tb.rulenode.aws-access-key-id</label> <input ng-required=true name=accessKeyId ng-model=configuration.accessKeyId> <div ng-messages=snsConfigForm.accessKeyId.$error> <div ng-message=required translate>tb.rulenode.aws-access-key-id-required</div> </div> </md-input-container> <md-input-container class=md-block> <label translate>tb.rulenode.aws-secret-access-key</label> <input ng-required=true name=secretAccessKey ng-model=configuration.secretAccessKey> <div ng-messages=snsConfigForm.secretAccessKey.$error> <div ng-message=required translate>tb.rulenode.aws-secret-access-key-required</div> </div> </md-input-container> <md-input-container class=md-block> <label translate>tb.rulenode.aws-region</label> <input ng-required=true name=region ng-model=configuration.region> <div ng-messages=snsConfigForm.region.$error> <div ng-message=required translate>tb.rulenode.aws-region-required</div> </div> </md-input-container> </section> '},function(e,t){e.exports=" <section ng-form name=timeseriesConfigForm layout=column> <md-input-container class=md-block> <label translate>tb.rulenode.default-ttl</label> <input ng-required=true type=number step=1 name=defaultTTL ng-model=configuration.defaultTTL min=0> <div ng-messages=timeseriesConfigForm.defaultTTL.$error multiple=multiple md-auto-hide=false> <div ng-message=required translate>tb.rulenode.default-ttl-required</div> <div ng-message=min translate>tb.rulenode.min-default-ttl-message</div> </div> </md-input-container> </section> "},function(e,t){e.exports=' <section layout=column> <div layout=row> <md-input-container class=md-block style=min-width:100px> <label translate>relation.direction</label> <md-select required ng-model=query.direction> <md-option ng-repeat="direction in types.entitySearchDirection" ng-value=direction> {{ (\'relation.search-direction.\' + direction) | translate}} </md-option> </md-select> </md-input-container> <md-input-container class=md-block> <label translate>tb.rulenode.max-relation-level</label> <input name=maxRelationLevel type=number min=1 step=1 placeholder="{{ \'tb.rulenode.unlimited-level\' | translate }}" ng-model=query.maxLevel aria-label="{{ \'tb.rulenode.max-relation-level\' | translate }}"> </md-input-container> </div> <div class=md-caption style=color:rgba(0,0,0,.57) translate>relation.relation-type</div> <tb-relation-type-autocomplete flex hide-label ng-model=query.relationType tb-required=false> </tb-relation-type-autocomplete> <div class="md-caption tb-required" style=color:rgba(0,0,0,.57) translate>device.device-types</div> <tb-entity-subtype-list tb-required=true entity-type=types.entityType.device ng-model=query.deviceTypes> </tb-entity-subtype-list> </section> '},function(e,t){e.exports=" <section layout=column> <label translate class=\"tb-title tb-required\">tb.rulenode.attr-mapping</label> <md-checkbox aria-label=\"{{ 'tb.rulenode.latest-telemetry' | translate }}\" ng-model=configuration.telemetry>{{ 'tb.rulenode.latest-telemetry' | translate }} </md-checkbox> <tb-kv-map-config ng-model=configuration.attrMapping ng-required=true required-text=\"'tb.rulenode.attr-mapping-required'\" key-text=\"configuration.telemetry ? 'tb.rulenode.source-telemetry' : 'tb.rulenode.source-attribute'\" key-required-text=\"configuration.telemetry ? 'tb.rulenode.source-telemetry-required' : 'tb.rulenode.source-attribute-required'\" val-text=\"'tb.rulenode.target-attribute'\" val-required-text=\"'tb.rulenode.target-attribute-required'\"> </tb-kv-map-config> </section> "; | |
2 | +},function(e,t){e.exports=' <section layout=column> <label translate class="tb-title tb-required">tb.rulenode.device-relations-query</label> <tb-device-relations-query-config style=padding-bottom:15px ng-model=configuration.deviceRelationsQuery> </tb-device-relations-query-config> <label translate class="tb-title no-padding">tb.rulenode.client-attributes</label> <md-chips style=padding-bottom:15px ng-required=false readonly=readonly ng-model=configuration.clientAttributeNames placeholder="{{\'tb.rulenode.client-attributes\' | translate}}" md-separator-keys=separatorKeys> </md-chips> <label translate class="tb-title no-padding">tb.rulenode.shared-attributes</label> <md-chips style=padding-bottom:15px ng-required=false readonly=readonly ng-model=configuration.sharedAttributeNames placeholder="{{\'tb.rulenode.shared-attributes\' | translate}}" md-separator-keys=separatorKeys> </md-chips> <label translate class="tb-title no-padding">tb.rulenode.server-attributes</label> <md-chips style=padding-bottom:15px ng-required=false readonly=readonly ng-model=configuration.serverAttributeNames placeholder="{{\'tb.rulenode.server-attributes\' | translate}}" md-separator-keys=separatorKeys> </md-chips> <label translate class="tb-title no-padding">tb.rulenode.latest-timeseries</label> <md-chips ng-required=false readonly=readonly ng-model=configuration.latestTsKeyNames placeholder="{{\'tb.rulenode.latest-timeseries\' | translate}}" md-separator-keys=separatorKeys> </md-chips> </section> '},function(e,t){e.exports=' <section layout=column> <label translate class="tb-title no-padding">tb.rulenode.client-attributes</label> <md-chips style=padding-bottom:15px ng-required=false readonly=readonly ng-model=configuration.clientAttributeNames placeholder="{{\'tb.rulenode.client-attributes\' | translate}}" md-separator-keys=separatorKeys> </md-chips> <label translate class="tb-title no-padding">tb.rulenode.shared-attributes</label> <md-chips style=padding-bottom:15px ng-required=false readonly=readonly ng-model=configuration.sharedAttributeNames placeholder="{{\'tb.rulenode.shared-attributes\' | translate}}" md-separator-keys=separatorKeys> </md-chips> <label translate class="tb-title no-padding">tb.rulenode.server-attributes</label> <md-chips style=padding-bottom:15px ng-required=false readonly=readonly ng-model=configuration.serverAttributeNames placeholder="{{\'tb.rulenode.server-attributes\' | translate}}" md-separator-keys=separatorKeys> </md-chips> <label translate class="tb-title no-padding">tb.rulenode.latest-timeseries</label> <md-chips ng-required=false readonly=readonly ng-model=configuration.latestTsKeyNames placeholder="{{\'tb.rulenode.latest-timeseries\' | translate}}" md-separator-keys=separatorKeys> </md-chips> </section> '},function(e,t){e.exports=' <section layout=column> <label translate class="tb-title tb-required">tb.rulenode.fields-mapping</label> <tb-kv-map-config ng-model=configuration.fieldsMapping ng-required=true required-text="\'tb.rulenode.fields-mapping-required\'" key-text="\'tb.rulenode.source-field\'" key-required-text="\'tb.rulenode.source-field-required\'" val-text="\'tb.rulenode.target-attribute\'" val-required-text="\'tb.rulenode.target-attribute-required\'"> </tb-kv-map-config> </section> '},function(e,t){e.exports=" <section layout=column> <label translate class=\"tb-title tb-required\">tb.rulenode.relations-query</label> <tb-relations-query-config style=padding-bottom:15px ng-model=configuration.relationsQuery> </tb-relations-query-config> <label translate class=\"tb-title tb-required\">tb.rulenode.attr-mapping</label> <md-checkbox aria-label=\"{{ 'tb.rulenode.latest-telemetry' | translate }}\" ng-model=configuration.telemetry>{{ 'tb.rulenode.latest-telemetry' | translate }} </md-checkbox> <tb-kv-map-config ng-model=configuration.attrMapping ng-required=true required-text=\"'tb.rulenode.attr-mapping-required'\" key-text=\"configuration.telemetry ? 'tb.rulenode.source-telemetry' : 'tb.rulenode.source-attribute'\" key-required-text=\"configuration.telemetry ? 'tb.rulenode.source-telemetry-required' : 'tb.rulenode.source-attribute-required'\" val-text=\"'tb.rulenode.target-attribute'\" val-required-text=\"'tb.rulenode.target-attribute-required'\"> </tb-kv-map-config> </section> "},21,function(e,t){e.exports=" <section ng-form name=checkRelationConfigForm> <md-input-container class=md-block style=min-width:100px> <label translate>relation.direction</label> <md-select required ng-model=configuration.direction> <md-option ng-repeat=\"direction in types.entitySearchDirection\" ng-value=direction> {{ ('relation.search-direction.' + direction) | translate}} </md-option> </md-select> </md-input-container> <div layout=row class=tb-entity-select> <tb-entity-type-select style=min-width:100px the-form=checkRelationConfigForm tb-required=true ng-model=configuration.entityType> </tb-entity-type-select> <tb-entity-autocomplete flex ng-if=configuration.entityType the-form=checkRelationConfigForm tb-required=true entity-type=configuration.entityType ng-model=configuration.entityId> </tb-entity-autocomplete> </div> <tb-relation-type-autocomplete hide-label ng-model=configuration.relationType tb-required=true> </tb-relation-type-autocomplete> </section> "},function(e,t){e.exports=' <section layout=column> <label translate class="tb-title no-padding" ng-class="{\'tb-required\': required}">tb.rulenode.message-types-filter</label> <md-chips id=message_type_chips ng-required=required readonly=readonly ng-model=messageTypes md-autocomplete-snap md-transform-chip=transformMessageTypeChip($chip) md-require-match=false> <md-autocomplete id=message_type md-no-cache=true md-selected-item=selectedMessageType md-search-text=messageTypeSearchText md-items="item in messageTypesSearch(messageTypeSearchText)" md-item-text=item.name md-min-length=0 placeholder="{{\'tb.rulenode.message-type\' | translate }}" md-menu-class=tb-message-type-autocomplete> <span md-highlight-text=messageTypeSearchText md-highlight-flags=^i>{{item}}</span> <md-not-found> <div class=tb-not-found> <div class=tb-no-entries ng-if="!messageTypeSearchText || !messageTypeSearchText.length"> <span translate>tb.rulenode.no-message-types-found</span> </div> <div ng-if="messageTypeSearchText && messageTypeSearchText.length"> <span translate translate-values=\'{ messageType: "{{messageTypeSearchText | truncate:true:6:'...'}}" }\'>tb.rulenode.no-message-type-matching</span> <span> <a translate ng-click="createMessageType($event, \'#message_type_chips\')">tb.rulenode.create-new-message-type</a> </span> </div> </div> </md-not-found> </md-autocomplete> <md-chip-template> <span>{{$chip.name}}</span> </md-chip-template> </md-chips> <div class=tb-error-messages ng-messages=ngModelCtrl.$error role=alert> <div translate ng-message=messageTypes class=tb-error-message>tb.rulenode.message-types-required</div> </div> </section>'},function(e,t){e.exports=" <section layout=column> <label translate class=\"tb-title no-padding\">tb.rulenode.filter</label> <tb-js-func ng-model=configuration.jsScript function-name=Filter function-args=\"{{ ['msg', 'metadata', 'msgType'] }}\" no-validate=true> </tb-js-func> <div layout=row> <md-button ng-click=testScript($event) class=\"md-primary md-raised\"> {{ 'tb.rulenode.test-filter-function' | translate }} </md-button> </div> </section> "},function(e,t){e.exports=" <section layout=column> <label translate class=\"tb-title no-padding\">tb.rulenode.switch</label> <tb-js-func ng-model=configuration.jsScript function-name=Switch function-args=\"{{ ['msg', 'metadata', 'msgType'] }}\" no-validate=true> </tb-js-func> <div layout=row> <md-button ng-click=testScript($event) class=\"md-primary md-raised\"> {{ 'tb.rulenode.test-switch-function' | translate }} </md-button> </div> </section> "},function(e,t){e.exports=' <section class=tb-kv-map-config layout=column> <div class=header flex layout=row> <span class=cell flex translate>{{ keyText }}</span> <span class=cell flex translate>{{ valText }}</span> <span ng-show=!disabled style=width:52px> </span> </div> <div class=body> <div class=row ng-form name=kvForm flex layout=row layout-align="start center" ng-repeat="keyVal in kvList track by $index"> <md-input-container class="cell md-block" flex md-no-float> <input placeholder="{{ keyText | translate }}" ng-required=true name=key ng-model=keyVal.key> <div ng-messages=kvForm.key.$error> <div translate ng-message=required>{{keyRequiredText}}</div> </div> </md-input-container> <md-input-container class="cell md-block" flex md-no-float> <input placeholder="{{ valText | translate }}" ng-required=true name=value ng-model=keyVal.value> <div ng-messages=kvForm.value.$error> <div translate ng-message=required>{{valRequiredText}}</div> </div> </md-input-container> <md-button ng-show=!disabled ng-disabled=loading class="md-icon-button md-primary" ng-click=removeKeyVal($index) aria-label="{{ \'action.remove\' | translate }}"> <md-tooltip md-direction=top> {{ \'tb.key-val.remove-entry\' | translate }} </md-tooltip> <md-icon aria-label="{{ \'action.delete\' | translate }}" class=material-icons> close </md-icon> </md-button> </div> </div> <div class=tb-error-messages ng-messages=ngModelCtrl.$error role=alert> <div translate ng-message=kvMap class=tb-error-message>{{requiredText}}</div> </div> <div> <md-button ng-show=!disabled ng-disabled=loading class="md-primary md-raised" ng-click=addKeyVal() aria-label="{{ \'action.add\' | translate }}"> <md-tooltip md-direction=top> {{ \'tb.key-val.add-entry\' | translate }} </md-tooltip> <md-icon aria-label="{{ \'action.add\' | translate }}" class=material-icons> add </md-icon> {{ \'action.add\' | translate }} </md-button> </div> </section> '},function(e,t){e.exports=" <section layout=column> <div layout=row> <md-input-container class=md-block style=min-width:100px> <label translate>relation.direction</label> <md-select required ng-model=query.direction> <md-option ng-repeat=\"direction in types.entitySearchDirection\" ng-value=direction> {{ ('relation.search-direction.' + direction) | translate}} </md-option> </md-select> </md-input-container> <md-input-container class=md-block> <label translate>tb.rulenode.max-relation-level</label> <input name=maxRelationLevel type=number min=1 step=1 placeholder=\"{{ 'tb.rulenode.unlimited-level' | translate }}\" ng-model=query.maxLevel aria-label=\"{{ 'tb.rulenode.max-relation-level' | translate }}\"> </md-input-container> </div> <div class=md-caption style=padding-bottom:10px;color:rgba(0,0,0,.57) translate>relation.relation-filters</div> <tb-relation-filters ng-model=query.filters> </tb-relation-filters> </section> "},function(e,t){e.exports=' <section layout=column> <md-input-container class=md-block> <label translate>tb.rulenode.originator-source</label> <md-select required ng-model=configuration.originatorSource> <md-option ng-repeat="source in ruleNodeTypes.originatorSource" ng-value=source.value> {{ source.name | translate}} </md-option> </md-select> </md-input-container> <section layout=column ng-if="configuration.originatorSource == ruleNodeTypes.originatorSource.RELATED.value"> <label translate class="tb-title tb-required">tb.rulenode.relations-query</label> <tb-relations-query-config style=padding-bottom:15px ng-model=configuration.relationsQuery> </tb-relations-query-config> </section> </section> '},function(e,t){e.exports=" <section layout=column> <label translate class=\"tb-title no-padding\">tb.rulenode.transform</label> <tb-js-func ng-model=configuration.jsScript function-name=Transform function-args=\"{{ ['msg', 'metadata', 'msgType'] }}\" no-validate=true> </tb-js-func> <div layout=row style=padding-bottom:15px> <md-button ng-click=testScript($event) class=\"md-primary md-raised\"> {{ 'tb.rulenode.test-transformer-function' | translate }} </md-button> </div> </section> "},function(e,t){e.exports=" <section ng-form name=toEmailConfigForm layout=column> <md-input-container class=md-block> <label translate>tb.rulenode.from-template</label> <textarea ng-required=true name=fromTemplate ng-model=configuration.fromTemplate rows=2></textarea> <div ng-messages=toEmailConfigForm.fromTemplate.$error> <div ng-message=required translate>tb.rulenode.from-template-required</div> </div> <div class=tb-hint translate>tb.rulenode.from-template-hint</div> </md-input-container> <md-input-container class=md-block> <label translate>tb.rulenode.to-template</label> <textarea ng-required=true name=toTemplate ng-model=configuration.toTemplate rows=2></textarea> <div ng-messages=toEmailConfigForm.toTemplate.$error> <div ng-message=required translate>tb.rulenode.to-template-required</div> </div> <div class=tb-hint translate>tb.rulenode.mail-address-list-template-hint</div> </md-input-container> <md-input-container class=md-block> <label translate>tb.rulenode.cc-template</label> <textarea name=ccTemplate ng-model=configuration.ccTemplate rows=2></textarea> <div class=tb-hint translate>tb.rulenode.mail-address-list-template-hint</div> </md-input-container> <md-input-container class=md-block> <label translate>tb.rulenode.bcc-template</label> <textarea name=ccTemplate ng-model=configuration.bccTemplate rows=2></textarea> <div class=tb-hint translate>tb.rulenode.mail-address-list-template-hint</div> </md-input-container> <md-input-container class=md-block> <label translate>tb.rulenode.subject-template</label> <textarea ng-required=true name=subjectTemplate ng-model=configuration.subjectTemplate rows=2></textarea> <div ng-messages=toEmailConfigForm.subjectTemplate.$error> <div ng-message=required translate>tb.rulenode.subject-template-required</div> </div> <div class=tb-hint translate>tb.rulenode.subject-template-hint</div> </md-input-container> <md-input-container class=md-block> <label translate>tb.rulenode.body-template</label> <textarea ng-required=true name=bodyTemplate ng-model=configuration.bodyTemplate rows=6></textarea> <div ng-messages=toEmailConfigForm.bodyTemplate.$error> <div ng-message=required translate>tb.rulenode.body-template-required</div> </div> <div class=tb-hint translate>tb.rulenode.body-template-hint</div> </md-input-container> </section> "},function(e,t,n){"use strict";function a(e){return e&&e.__esModule?e:{default:e}}function r(e,t){var n=function(n,a,r,i){var l=o.default;a.html(l),n.types=t,n.$watch("configuration",function(e,t){angular.equals(e,t)||i.$setViewValue(n.configuration)}),i.$render=function(){n.configuration=i.$viewValue},e(a.contents())(n)};return{restrict:"E",require:"^ngModel",scope:{},link:n}}r.$inject=["$compile","types"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=r;var i=n(5),o=a(i)},function(e,t,n){"use strict";function a(e){return e&&e.__esModule?e:{default:e}}function r(e,t,n,a){var r=function(r,i,l,s){var u=o.default;i.html(u),r.types=n,r.$watch("configuration",function(e,t){angular.equals(e,t)||s.$setViewValue(r.configuration)}),s.$render=function(){r.configuration=s.$viewValue},r.testDetailsBuildJs=function(e){var n=angular.copy(r.configuration.alarmDetailsBuildJs);a.testNodeScript(e,n,"json",t.instant("tb.rulenode.details")+"","Details",["msg","metadata","msgType"],r.ruleNodeId).then(function(e){r.configuration.alarmDetailsBuildJs=e,s.$setDirty()})},e(i.contents())(r)};return{restrict:"E",require:"^ngModel",scope:{ruleNodeId:"="},link:r}}r.$inject=["$compile","$translate","types","ruleNodeScriptTest"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=r;var i=n(6),o=a(i)},function(e,t,n){"use strict";function a(e){return e&&e.__esModule?e:{default:e}}function r(e,t,n,a){var r=function(r,i,l,s){var u=o.default;i.html(u),r.types=n,r.$watch("configuration",function(e,t){angular.equals(e,t)||s.$setViewValue(r.configuration)}),s.$render=function(){r.configuration=s.$viewValue},r.testDetailsBuildJs=function(e){var n=angular.copy(r.configuration.alarmDetailsBuildJs);a.testNodeScript(e,n,"json",t.instant("tb.rulenode.details")+"","Details",["msg","metadata","msgType"],r.ruleNodeId).then(function(e){r.configuration.alarmDetailsBuildJs=e,s.$setDirty()})},e(i.contents())(r)};return{restrict:"E",require:"^ngModel",scope:{ruleNodeId:"="},link:r}}r.$inject=["$compile","$translate","types","ruleNodeScriptTest"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=r;var i=n(7),o=a(i)},function(e,t,n){"use strict";function a(e){return e&&e.__esModule?e:{default:e}}function r(e,t,n,a){var r=function(r,i,l,s){var u=o.default;i.html(u),r.types=n,r.originator=null,r.$watch("configuration",function(e,t){angular.equals(e,t)||s.$setViewValue(r.configuration)}),s.$render=function(){r.configuration=s.$viewValue,r.configuration.originatorId&&r.configuration.originatorType?r.originator={id:r.configuration.originatorId,entityType:r.configuration.originatorType}:r.originator=null,r.$watch("originator",function(e,t){angular.equals(e,t)||(r.originator?(s.$viewValue.originatorId=r.originator.id,s.$viewValue.originatorType=r.originator.entityType):(s.$viewValue.originatorId=null,s.$viewValue.originatorType=null))},!0)},r.testScript=function(e){var n=angular.copy(r.configuration.jsScript);a.testNodeScript(e,n,"generate",t.instant("tb.rulenode.generator")+"","Generate",["prevMsg","prevMetadata","prevMsgType"],r.ruleNodeId).then(function(e){r.configuration.jsScript=e,s.$setDirty()})},e(i.contents())(r)};return{restrict:"E",require:"^ngModel",scope:{ruleNodeId:"="},link:r}}r.$inject=["$compile","$translate","types","ruleNodeScriptTest"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=r,n(1);var i=n(8),o=a(i)},function(e,t,n){"use strict";function a(e){return e&&e.__esModule?e:{default:e}}Object.defineProperty(t,"__esModule",{value:!0});var r=n(51),i=a(r),o=n(36),l=a(o),s=n(39),u=a(s),d=n(38),c=a(d),m=n(37),g=a(m),p=n(42),f=a(p),b=n(46),v=a(b),y=n(47),q=a(y),h=n(45),T=a(h),$=n(41),k=a($),w=n(49),C=a(w),_=n(50),x=a(_),E=n(44),M=a(E),S=n(43),N=a(S),V=n(48),P=a(V);t.default=angular.module("thingsboard.ruleChain.config.action",[]).directive("tbActionNodeTimeseriesConfig",i.default).directive("tbActionNodeAttributesConfig",l.default).directive("tbActionNodeGeneratorConfig",u.default).directive("tbActionNodeCreateAlarmConfig",c.default).directive("tbActionNodeClearAlarmConfig",g.default).directive("tbActionNodeLogConfig",f.default).directive("tbActionNodeRpcReplyConfig",v.default).directive("tbActionNodeRpcRequestConfig",q.default).directive("tbActionNodeRestApiCallConfig",T.default).directive("tbActionNodeKafkaConfig",k.default).directive("tbActionNodeSnsConfig",C.default).directive("tbActionNodeSqsConfig",x.default).directive("tbActionNodeRabbitMqConfig",M.default).directive("tbActionNodeMqttConfig",N.default).directive("tbActionNodeSendEmailConfig",P.default).name},function(e,t,n){"use strict";function a(e){return e&&e.__esModule?e:{default:e}}function r(e){var t=function(t,n,a,r){var i=o.default;n.html(i),t.ackValues=["all","-1","0","1"],t.$watch("configuration",function(e,n){angular.equals(e,n)||r.$setViewValue(t.configuration)}),r.$render=function(){t.configuration=r.$viewValue},e(n.contents())(t)};return{restrict:"E",require:"^ngModel",scope:{},link:t}}r.$inject=["$compile"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=r;var i=n(9),o=a(i)},function(e,t,n){"use strict";function a(e){return e&&e.__esModule?e:{default:e}}function r(e,t,n){var a=function(a,r,i,l){var s=o.default;r.html(s),a.$watch("configuration",function(e,t){angular.equals(e,t)||l.$setViewValue(a.configuration)}),l.$render=function(){a.configuration=l.$viewValue},a.testScript=function(e){var r=angular.copy(a.configuration.jsScript);n.testNodeScript(e,r,"string",t.instant("tb.rulenode.to-string")+"","ToString",["msg","metadata","msgType"],a.ruleNodeId).then(function(e){a.configuration.jsScript=e,l.$setDirty()})},e(r.contents())(a)};return{restrict:"E",require:"^ngModel",scope:{ruleNodeId:"="},link:a}}r.$inject=["$compile","$translate","ruleNodeScriptTest"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=r;var i=n(10),o=a(i)},function(e,t,n){"use strict";function a(e){return e&&e.__esModule?e:{default:e}}function r(e,t,n){var a=function(a,r,i,l){var s=o.default;r.html(s),a.$mdExpansionPanel=t,a.ruleNodeTypes=n,a.credentialsTypeChanged=function(){var e=a.configuration.credentials.type;a.configuration.credentials={},a.configuration.credentials.type=e,a.updateValidity()},a.certFileAdded=function(e,t){var n=new FileReader;n.onload=function(n){a.$apply(function(){if(n.target.result){l.$setDirty();var r=n.target.result;r&&r.length>0&&("caCert"==t&&(a.configuration.credentials.caCertFileName=e.name,a.configuration.credentials.caCert=r),"privateKey"==t&&(a.configuration.credentials.privateKeyFileName=e.name,a.configuration.credentials.privateKey=r),"Cert"==t&&(a.configuration.credentials.certFileName=e.name,a.configuration.credentials.cert=r)),a.updateValidity()}})},n.readAsText(e.file)},a.clearCertFile=function(e){l.$setDirty(),"caCert"==e&&(a.configuration.credentials.caCertFileName=null,a.configuration.credentials.caCert=null),"privateKey"==e&&(a.configuration.credentials.privateKeyFileName=null,a.configuration.credentials.privateKey=null),"Cert"==e&&(a.configuration.credentials.certFileName=null,a.configuration.credentials.cert=null),a.updateValidity()},a.updateValidity=function(){var e=!0,t=a.configuration.credentials;t.type==n.mqttCredentialTypes["cert.PEM"].value&&(t.caCert&&t.cert&&t.privateKey||(e=!1)),l.$setValidity("Certs",e)},a.$watch("configuration",function(e,t){angular.equals(e,t)||l.$setViewValue(a.configuration)}),l.$render=function(){a.configuration=l.$viewValue},e(r.contents())(a)};return{restrict:"E",require:"^ngModel",scope:{readonly:"=ngReadonly"},link:a}}r.$inject=["$compile","$mdExpansionPanel","ruleNodeTypes"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=r,n(2);var i=n(11),o=a(i)},function(e,t,n){"use strict";function a(e){return e&&e.__esModule?e:{default:e}}function r(e){var t=function(t,n,a,r){var i=o.default;n.html(i),t.messageProperties=[null,"BASIC","TEXT_PLAIN","MINIMAL_BASIC","MINIMAL_PERSISTENT_BASIC","PERSISTENT_BASIC","PERSISTENT_TEXT_PLAIN"],t.$watch("configuration",function(e,n){angular.equals(e,n)||r.$setViewValue(t.configuration)}),r.$render=function(){t.configuration=r.$viewValue},e(n.contents())(t)};return{restrict:"E",require:"^ngModel",scope:{readonly:"=ngReadonly"},link:t}}r.$inject=["$compile"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=r;var i=n(12),o=a(i)},function(e,t,n){"use strict";function a(e){return e&&e.__esModule?e:{default:e}}function r(e,t){var n=function(n,a,r,i){var l=o.default;a.html(l),n.ruleNodeTypes=t,n.$watch("configuration",function(e,t){angular.equals(e,t)||i.$setViewValue(n.configuration)}),i.$render=function(){n.configuration=i.$viewValue},e(a.contents())(n)};return{restrict:"E",require:"^ngModel",scope:{},link:n}}r.$inject=["$compile","ruleNodeTypes"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=r;var i=n(13),o=a(i)},function(e,t,n){"use strict";function a(e){return e&&e.__esModule?e:{default:e}}function r(e){var t=function(t,n,a,r){var i=o.default;n.html(i),t.$watch("configuration",function(e,n){angular.equals(e,n)||r.$setViewValue(t.configuration)}),r.$render=function(){t.configuration=r.$viewValue},e(n.contents())(t)};return{restrict:"E",require:"^ngModel",scope:{},link:t}}r.$inject=["$compile"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=r;var i=n(14),o=a(i)},function(e,t,n){"use strict";function a(e){return e&&e.__esModule?e:{default:e}}function r(e){var t=function(t,n,a,r){var i=o.default;n.html(i),t.$watch("configuration",function(e,n){angular.equals(e,n)||r.$setViewValue(t.configuration)}),r.$render=function(){t.configuration=r.$viewValue},e(n.contents())(t)};return{restrict:"E",require:"^ngModel",scope:{},link:t}}r.$inject=["$compile"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=r;var i=n(15),o=a(i)},function(e,t,n){"use strict";function a(e){return e&&e.__esModule?e:{default:e}}function r(e){var t=function(t,n,a,r){var i=o.default;n.html(i),t.smtpProtocols=["smtp","smtps"],t.$watch("configuration",function(e,n){angular.equals(e,n)||r.$setViewValue(t.configuration)}),r.$render=function(){t.configuration=r.$viewValue},e(n.contents())(t)};return{restrict:"E",require:"^ngModel",scope:{readonly:"=ngReadonly"},link:t}}r.$inject=["$compile"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=r;var i=n(16),o=a(i)},function(e,t,n){"use strict";function a(e){return e&&e.__esModule?e:{default:e}}function r(e){var t=function(t,n,a,r){var i=o.default;n.html(i),t.$watch("configuration",function(e,n){angular.equals(e,n)||r.$setViewValue(t.configuration)}),r.$render=function(){t.configuration=r.$viewValue},e(n.contents())(t)};return{restrict:"E",require:"^ngModel",scope:{},link:t}}r.$inject=["$compile"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=r;var i=n(17),o=a(i)},function(e,t,n){"use strict";function a(e){return e&&e.__esModule?e:{default:e}}function r(e,t){var n=function(n,a,r,i){var l=o.default;a.html(l),n.ruleNodeTypes=t,n.$watch("configuration",function(e,t){angular.equals(e,t)||i.$setViewValue(n.configuration)}),i.$render=function(){n.configuration=i.$viewValue},e(a.contents())(n)};return{restrict:"E",require:"^ngModel",scope:{readonly:"=ngReadonly"},link:n}}r.$inject=["$compile","ruleNodeTypes"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=r;var i=n(18),o=a(i)},function(e,t,n){"use strict";function a(e){return e&&e.__esModule?e:{default:e}}function r(e){var t=function(t,n,a,r){var i=o.default;n.html(i),t.$watch("configuration",function(e,n){angular.equals(e,n)||r.$setViewValue(t.configuration)}),r.$render=function(){t.configuration=r.$viewValue},e(n.contents())(t)};return{restrict:"E",require:"^ngModel",scope:{},link:t}}r.$inject=["$compile"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=r;var i=n(19),o=a(i)},function(e,t,n){"use strict";function a(e){return e&&e.__esModule?e:{default:e}}function r(e,t){var n=function(n,a,r,i){var l=o.default;a.html(l),n.types=t,n.$watch("query",function(e,t){angular.equals(e,t)||i.$setViewValue(n.query)}),i.$render=function(){n.query=i.$viewValue},e(a.contents())(n)};return{restrict:"E",require:"^ngModel",scope:{},link:n}}r.$inject=["$compile","types"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=r;var i=n(20),o=a(i)},function(e,t){"use strict";function n(e){var t=function(t,n,a,r){n.html("<div></div>"),t.$watch("configuration",function(e,n){angular.equals(e,n)||r.$setViewValue(t.configuration)}),r.$render=function(){t.configuration=r.$viewValue},e(n.contents())(t)};return{restrict:"E",require:"^ngModel",scope:{},link:t}}n.$inject=["$compile"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=n},function(e,t,n){"use strict";function a(e){return e&&e.__esModule?e:{default:e}}function r(e){var t=function(t,n,a,r){var i=o.default;n.html(i),t.$watch("configuration",function(e,n){angular.equals(e,n)||r.$setViewValue(t.configuration)}),r.$render=function(){t.configuration=r.$viewValue},e(n.contents())(t)};return{restrict:"E",require:"^ngModel",scope:{},link:t}}r.$inject=["$compile"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=r;var i=n(21),o=a(i)},function(e,t,n){"use strict";function a(e){return e&&e.__esModule?e:{default:e}}function r(e,t){var n=function(n,a,r,i){var l=o.default;a.html(l);var s=186;n.separatorKeys=[t.KEY_CODE.ENTER,t.KEY_CODE.COMMA,s],n.$watch("configuration",function(e,t){angular.equals(e,t)||i.$setViewValue(n.configuration)}),i.$render=function(){n.configuration=i.$viewValue},e(a.contents())(n)};return{restrict:"E",require:"^ngModel",scope:{},link:n}}r.$inject=["$compile","$mdConstant"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=r;var i=n(22),o=a(i)},function(e,t,n){"use strict";function a(e){return e&&e.__esModule?e:{default:e}}Object.defineProperty(t,"__esModule",{value:!0});var r=n(57),i=a(r),o=n(58),l=a(o),s=n(55),u=a(s),d=n(59),c=a(d),m=n(54),g=a(m),p=n(60),f=a(p);t.default=angular.module("thingsboard.ruleChain.config.enrichment",[]).directive("tbEnrichmentNodeOriginatorAttributesConfig",i.default).directive("tbEnrichmentNodeOriginatorFieldsConfig",l.default).directive("tbEnrichmentNodeDeviceAttributesConfig",u.default).directive("tbEnrichmentNodeRelatedAttributesConfig",c.default).directive("tbEnrichmentNodeCustomerAttributesConfig",g.default).directive("tbEnrichmentNodeTenantAttributesConfig",f.default).name},function(e,t,n){"use strict";function a(e){return e&&e.__esModule?e:{default:e}}function r(e,t){var n=function(n,a,r,i){var l=o.default;a.html(l);var s=186;n.separatorKeys=[t.KEY_CODE.ENTER,t.KEY_CODE.COMMA,s],n.$watch("configuration",function(e,t){angular.equals(e,t)||i.$setViewValue(n.configuration)}),i.$render=function(){n.configuration=i.$viewValue},e(a.contents())(n)};return{restrict:"E",require:"^ngModel",scope:{},link:n}}r.$inject=["$compile","$mdConstant"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=r;var i=n(23),o=a(i)},function(e,t,n){"use strict";function a(e){return e&&e.__esModule?e:{default:e}}function r(e){var t=function(t,n,a,r){var i=o.default;n.html(i),t.$watch("configuration",function(e,n){angular.equals(e,n)||r.$setViewValue(t.configuration)}),r.$render=function(){t.configuration=r.$viewValue},e(n.contents())(t)};return{restrict:"E",require:"^ngModel",scope:{},link:t}}r.$inject=["$compile"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=r;var i=n(24),o=a(i)},function(e,t,n){"use strict";function a(e){return e&&e.__esModule?e:{default:e}}function r(e){var t=function(t,n,a,r){var i=o.default;n.html(i),t.$watch("configuration",function(e,n){angular.equals(e,n)||r.$setViewValue(t.configuration)}),r.$render=function(){t.configuration=r.$viewValue},e(n.contents())(t)};return{restrict:"E",require:"^ngModel",scope:{},link:t}}r.$inject=["$compile"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=r;var i=n(25),o=a(i)},function(e,t,n){"use strict";function a(e){return e&&e.__esModule?e:{default:e}}function r(e){var t=function(t,n,a,r){var i=o.default;n.html(i),t.$watch("configuration",function(e,n){angular.equals(e,n)||r.$setViewValue(t.configuration)}),r.$render=function(){t.configuration=r.$viewValue},e(n.contents())(t)};return{restrict:"E",require:"^ngModel",scope:{},link:t}}r.$inject=["$compile"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=r;var i=n(26),o=a(i)},function(e,t,n){"use strict";function a(e){return e&&e.__esModule?e:{default:e}}function r(e,t){var n=function(n,a,r,i){var l=o.default;a.html(l),n.types=t,n.$watch("configuration",function(e,t){angular.equals(e,t)||i.$setViewValue(n.configuration)}),i.$render=function(){n.configuration=i.$viewValue},e(a.contents())(n)};return{restrict:"E",require:"^ngModel",scope:{},link:n}}r.$inject=["$compile","types"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=r;var i=n(27),o=a(i)},function(e,t,n){"use strict";function a(e){return e&&e.__esModule?e:{default:e}}Object.defineProperty(t,"__esModule",{value:!0});var r=n(64),i=a(r),o=n(63),l=a(o),s=n(65),u=a(s),d=n(61),c=a(d);t.default=angular.module("thingsboard.ruleChain.config.filter",[]).directive("tbFilterNodeScriptConfig",i.default).directive("tbFilterNodeMessageTypeConfig",l.default).directive("tbFilterNodeSwitchConfig",u.default).directive("tbFilterNodeCheckRelationConfig",c.default).name},function(e,t,n){"use strict";function a(e){return e&&e.__esModule?e:{default:e}}function r(e,t,n){var a=function(a,r,i,l){function s(){if(l.$viewValue){for(var e=[],t=0;t<a.messageTypes.length;t++)e.push(a.messageTypes[t].value);l.$viewValue.messageTypes=e,u()}}function u(){if(a.required){var e=!(!l.$viewValue.messageTypes||!l.$viewValue.messageTypes.length);l.$setValidity("messageTypes",e)}else l.$setValidity("messageTypes",!0)}var d=o.default;r.html(d),a.selectedMessageType=null,a.messageTypeSearchText=null,a.ngModelCtrl=l;var c=[];for(var m in n.messageType){var g={name:n.messageType[m].name,value:n.messageType[m].value};c.push(g)}a.transformMessageTypeChip=function(e){ | |
3 | +var n,a=t("filter")(c,{name:e},!0);return n=a&&a.length?angular.copy(a[0]):{name:e,value:e}},a.messageTypesSearch=function(e){var n=e?t("filter")(c,{name:e}):c;return n.map(function(e){return e.name})},a.createMessageType=function(e,t){var n=angular.element(t,r)[0].firstElementChild,a=angular.element(n),i=a.scope().$mdChipsCtrl.getChipBuffer();e.preventDefault(),e.stopPropagation(),a.scope().$mdChipsCtrl.appendChip(i.trim()),a.scope().$mdChipsCtrl.resetChipBuffer()},l.$render=function(){var e=l.$viewValue,t=[];if(e&&e.messageTypes)for(var r=0;r<e.messageTypes.length;r++){var i=e.messageTypes[r];n.messageType[i]?t.push(angular.copy(n.messageType[i])):t.push({name:i,value:i})}a.messageTypes=t,a.$watch("messageTypes",function(e,t){angular.equals(e,t)||s()},!0)},e(r.contents())(a)};return{restrict:"E",require:"^ngModel",scope:{required:"=ngRequired",readonly:"=ngReadonly"},link:a}}r.$inject=["$compile","$filter","ruleNodeTypes"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=r,n(3);var i=n(28),o=a(i)},function(e,t,n){"use strict";function a(e){return e&&e.__esModule?e:{default:e}}function r(e,t,n){var a=function(a,r,i,l){var s=o.default;r.html(s),a.$watch("configuration",function(e,t){angular.equals(e,t)||l.$setViewValue(a.configuration)}),l.$render=function(){a.configuration=l.$viewValue},a.testScript=function(e){var r=angular.copy(a.configuration.jsScript);n.testNodeScript(e,r,"filter",t.instant("tb.rulenode.filter")+"","Filter",["msg","metadata","msgType"],a.ruleNodeId).then(function(e){a.configuration.jsScript=e,l.$setDirty()})},e(r.contents())(a)};return{restrict:"E",require:"^ngModel",scope:{ruleNodeId:"="},link:a}}r.$inject=["$compile","$translate","ruleNodeScriptTest"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=r;var i=n(29),o=a(i)},function(e,t,n){"use strict";function a(e){return e&&e.__esModule?e:{default:e}}function r(e,t,n){var a=function(a,r,i,l){var s=o.default;r.html(s),a.$watch("configuration",function(e,t){angular.equals(e,t)||l.$setViewValue(a.configuration)}),l.$render=function(){a.configuration=l.$viewValue},a.testScript=function(e){var r=angular.copy(a.configuration.jsScript);n.testNodeScript(e,r,"switch",t.instant("tb.rulenode.switch")+"","Switch",["msg","metadata","msgType"],a.ruleNodeId).then(function(e){a.configuration.jsScript=e,l.$setDirty()})},e(r.contents())(a)};return{restrict:"E",require:"^ngModel",scope:{ruleNodeId:"="},link:a}}r.$inject=["$compile","$translate","ruleNodeScriptTest"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=r;var i=n(30),o=a(i)},function(e,t,n){"use strict";function a(e){return e&&e.__esModule?e:{default:e}}function r(e){var t=function(t,n,a,r){function i(e){e>-1&&t.kvList.splice(e,1)}function l(){t.kvList||(t.kvList=[]),t.kvList.push({key:"",value:""})}function s(){var e={};t.kvList.forEach(function(t){t.key&&(e[t.key]=t.value)}),r.$setViewValue(e),u()}function u(){var e=!0;t.required&&!t.kvList.length&&(e=!1),r.$setValidity("kvMap",e)}var d=o.default;n.html(d),t.ngModelCtrl=r,t.removeKeyVal=i,t.addKeyVal=l,t.kvList=[],t.$watch("query",function(e,n){angular.equals(e,n)||r.$setViewValue(t.query)}),r.$render=function(){if(r.$viewValue){var e=r.$viewValue;t.kvList.length=0;for(var n in e)t.kvList.push({key:n,value:e[n]})}t.$watch("kvList",function(e,t){angular.equals(e,t)||s()},!0),u()},e(n.contents())(t)};return{restrict:"E",require:"^ngModel",scope:{required:"=ngRequired",disabled:"=ngDisabled",requiredText:"=",keyText:"=",keyRequiredText:"=",valText:"=",valRequiredText:"="},link:t}}r.$inject=["$compile"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=r;var i=n(31),o=a(i);n(4)},function(e,t,n){"use strict";function a(e){return e&&e.__esModule?e:{default:e}}function r(e,t){var n=function(n,a,r,i){var l=o.default;a.html(l),n.types=t,n.$watch("query",function(e,t){angular.equals(e,t)||i.$setViewValue(n.query)}),i.$render=function(){n.query=i.$viewValue},e(a.contents())(n)};return{restrict:"E",require:"^ngModel",scope:{},link:n}}r.$inject=["$compile","types"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=r;var i=n(32),o=a(i)},function(e,t,n){"use strict";function a(e){return e&&e.__esModule?e:{default:e}}function r(e,t){var n=function(n,a,r,i){var l=o.default;a.html(l),n.ruleNodeTypes=t,n.$watch("configuration",function(e,t){angular.equals(e,t)||i.$setViewValue(n.configuration)}),i.$render=function(){n.configuration=i.$viewValue},e(a.contents())(n)};return{restrict:"E",require:"^ngModel",scope:{},link:n}}r.$inject=["$compile","ruleNodeTypes"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=r;var i=n(33),o=a(i)},function(e,t,n){"use strict";function a(e){return e&&e.__esModule?e:{default:e}}Object.defineProperty(t,"__esModule",{value:!0});var r=n(68),i=a(r),o=n(70),l=a(o),s=n(71),u=a(s);t.default=angular.module("thingsboard.ruleChain.config.transform",[]).directive("tbTransformationNodeChangeOriginatorConfig",i.default).directive("tbTransformationNodeScriptConfig",l.default).directive("tbTransformationNodeToEmailConfig",u.default).name},function(e,t,n){"use strict";function a(e){return e&&e.__esModule?e:{default:e}}function r(e,t,n){var a=function(a,r,i,l){var s=o.default;r.html(s),a.$watch("configuration",function(e,t){angular.equals(e,t)||l.$setViewValue(a.configuration)}),l.$render=function(){a.configuration=l.$viewValue},a.testScript=function(e){var r=angular.copy(a.configuration.jsScript);n.testNodeScript(e,r,"update",t.instant("tb.rulenode.transformer")+"","Transform",["msg","metadata","msgType"],a.ruleNodeId).then(function(e){a.configuration.jsScript=e,l.$setDirty()})},e(r.contents())(a)};return{restrict:"E",require:"^ngModel",scope:{ruleNodeId:"="},link:a}}r.$inject=["$compile","$translate","ruleNodeScriptTest"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=r;var i=n(34),o=a(i)},function(e,t,n){"use strict";function a(e){return e&&e.__esModule?e:{default:e}}function r(e){var t=function(t,n,a,r){var i=o.default;n.html(i),t.$watch("configuration",function(e,n){angular.equals(e,n)||r.$setViewValue(t.configuration)}),r.$render=function(){t.configuration=r.$viewValue},e(n.contents())(t)};return{restrict:"E",require:"^ngModel",scope:{},link:t}}r.$inject=["$compile"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=r;var i=n(35),o=a(i)},function(e,t,n){"use strict";function a(e){return e&&e.__esModule?e:{default:e}}Object.defineProperty(t,"__esModule",{value:!0});var r=n(75),i=a(r),o=n(62),l=a(o),s=n(56),u=a(s),d=n(69),c=a(d),m=n(40),g=a(m),p=n(53),f=a(p),b=n(67),v=a(b),y=n(52),q=a(y),h=n(66),T=a(h),$=n(74),k=a($);t.default=angular.module("thingsboard.ruleChain.config",[i.default,l.default,u.default,c.default,g.default]).directive("tbNodeEmptyConfig",f.default).directive("tbRelationsQueryConfig",v.default).directive("tbDeviceRelationsQueryConfig",q.default).directive("tbKvMapConfig",T.default).config(k.default).name},function(e,t){"use strict";function n(e){var t={tb:{rulenode:{filter:"Filter",switch:"Switch","message-type":"Message type","message-type-required":"Message type is required.","message-types-filter":"Message types filter","no-message-types-found":"No message types found","no-message-type-matching":"'{{messageType}}' not found.","create-new-message-type":"Create a new one!","message-types-required":"Message types are required.","client-attributes":"Client attributes","shared-attributes":"Shared attributes","server-attributes":"Server attributes","latest-timeseries":"Latest timeseries","relations-query":"Relations query","device-relations-query":"Device relations query","max-relation-level":"Max relation level","unlimited-level":"Unlimited level","latest-telemetry":"Latest telemetry","attr-mapping":"Attributes mapping","source-attribute":"Source attribute","source-attribute-required":"Source attribute is required.","source-telemetry":"Source telemetry","source-telemetry-required":"Source telemetry is required.","target-attribute":"Target attribute","target-attribute-required":"Target attribute is required.","attr-mapping-required":"At least one attribute mapping should be specified.","fields-mapping":"Fields mapping","fields-mapping-required":"At least one field mapping should be specified.","source-field":"Source field","source-field-required":"Source field is required.","originator-source":"Originator source","originator-customer":"Customer","originator-tenant":"Tenant","originator-related":"Related","clone-message":"Clone message",transform:"Transform","default-ttl":"Default TTL in seconds","default-ttl-required":"Default TTL is required.","min-default-ttl-message":"Only 0 minimum TTL is allowed.","message-count":"Message count (0 - unlimited)","message-count-required":"Message count is required.","min-message-count-message":"Only 0 minimum message count is allowed.","period-seconds":"Period in seconds","period-seconds-required":"Period is required.","min-period-seconds-message":"Only 1 second minimum period is allowed.",originator:"Originator","message-body":"Message body","message-metadata":"Message metadata",generate:"Generate","test-generator-function":"Test generator function",generator:"Generator","test-filter-function":"Test filter function","test-switch-function":"Test switch function","test-transformer-function":"Test transformer function",transformer:"Transformer","alarm-create-condition":"Alarm create condition","test-condition-function":"Test condition function","alarm-clear-condition":"Alarm clear condition","alarm-details-builder":"Alarm details builder","test-details-function":"Test details function","alarm-type":"Alarm type","alarm-type-required":"Alarm type is required.","alarm-severity":"Alarm severity","alarm-severity-required":"Alarm severity is required",propagate:"Propagate",condition:"Condition",details:"Details","to-string":"To string","test-to-string-function":"Test to string function","from-template":"From Template","from-template-required":"From Template is required","from-template-hint":"From address template, use <code>${metaKeyName}</code> to substitute variables from metadata","to-template":"To Template","to-template-required":"To Template is required","mail-address-list-template-hint":"Comma separated address list, use <code>${metaKeyName}</code> to substitute variables from metadata","cc-template":"Cc Template","bcc-template":"Bcc Template","subject-template":"Subject Template","subject-template-required":"Subject Template is required","subject-template-hint":"Mail subject template, use <code>${metaKeyName}</code> to substitute variables from metadata","body-template":"Body Template","body-template-required":"Body Template is required","body-template-hint":"Mail body template, use <code>${metaKeyName}</code> to substitute variables from metadata","request-id-metadata-attribute":"Request Id Metadata attribute name","timeout-sec":"Timeout in seconds","timeout-required":"Timeout is required","min-timeout-message":"Only 0 minimum timeout value is allowed.","endpoint-url-pattern":"Endpoint URL pattern","endpoint-url-pattern-required":"Endpoint URL pattern is required","endpoint-url-pattern-hint":"HTTP URL address pattern, use <code>${metaKeyName}</code> to substitute variables from metadata","request-method":"Request method",headers:"Headers","headers-hint":"Use <code>${metaKeyName}</code> in header/value fields to substitute variables from metadata",header:"Header","header-required":"Header is required",value:"Value","value-required":"Value is required","topic-pattern":"Topic pattern","topic-pattern-required":"Topic pattern is required","mqtt-topic-pattern-hint":"MQTT topic pattern, use <code>${metaKeyName}</code> to substitute variables from metadata","bootstrap-servers":"Bootstrap servers","bootstrap-servers-required":"Bootstrap servers value is required","other-properties":"Other properties",key:"Key","key-required":"Key is required",retries:"Automatically retry times if fails","min-retries-message":"Only 0 minimum retries is allowed.","batch-size-bytes":"Produces batch size in bytes","min-batch-size-bytes-message":"Only 0 minimum batch size is allowed.","linger-ms":"Time to buffer locally (ms)","min-linger-ms-message":"Only 0 ms minimum value is allowed.","buffer-memory-bytes":"Client buffer max size in bytes","min-buffer-memory-message":"Only 0 minimum buffer size is allowed.",acks:"Number of acknowledgments","key-serializer":"Key serializer","key-serializer-required":"Key serializer is required","value-serializer":"Value serializer","value-serializer-required":"Value serializer is required","topic-arn-pattern":"Topic ARN pattern","topic-arn-pattern-required":"Topic ARN pattern is required","topic-arn-pattern-hint":"Topic ARN pattern, use <code>${metaKeyName}</code> to substitute variables from metadata","aws-access-key-id":"AWS Access Key ID","aws-access-key-id-required":"AWS Access Key ID is required","aws-secret-access-key":"AWS Secret Access Key","aws-secret-access-key-required":"AWS Secret Access Key is required","aws-region":"AWS Region","aws-region-required":"AWS Region is required","exchange-name-pattern":"Exchange name pattern","routing-key-pattern":"Routing key pattern","message-properties":"Message properties",host:"Host","host-required":"Host is required",port:"Port","port-required":"Port is required","port-range":"Port should be in a range from 1 to 65535.","virtual-host":"Virtual host",username:"Username",password:"Password","automatic-recovery":"Automatic recovery","connection-timeout-ms":"Connection timeout (ms)","min-connection-timeout-ms-message":"Only 0 ms minimum value is allowed.","handshake-timeout-ms":"Handshake timeout (ms)","min-handshake-timeout-ms-message":"Only 0 ms minimum value is allowed.","client-properties":"Client properties","queue-url-pattern":"Queue URL pattern","queue-url-pattern-required":"Queue URL pattern is required","queue-url-pattern-hint":"Queue URL pattern, use <code>${metaKeyName}</code> to substitute variables from metadata","delay-seconds":"Delay (seconds)","min-delay-seconds-message":"Only 0 seconds minimum value is allowed.","max-delay-seconds-message":"Only 900 seconds maximum value is allowed.",name:"Name","name-required":"Name is required","queue-type":"Queue type","sqs-queue-standard":"Standard","sqs-queue-fifo":"FIFO","message-attributes":"Message attributes","message-attributes-hint":"Use <code>${metaKeyName}</code> in name/value fields to substitute variables from metadata","connect-timeout":"Connection timeout (sec)","connect-timeout-required":"Connection timeout is required.","connect-timeout-range":"Connection timeout should be in a range from 1 to 200.","client-id":"Client ID","clean-session":"Clean session","enable-ssl":"Enable SSL",credentials:"Credentials","credentials-type":"Credentials type","credentials-type-required":"Credentials type is required.","credentials-anonymous":"Anonymous","credentials-basic":"Basic","credentials-pem":"PEM","username-required":"Username is required.","password-required":"Password is required.","ca-cert":"CA certificate file *","private-key":"Private key file *",cert:"Certificate file *","no-file":"No file selected.","drop-file":"Drop a file or click to select a file to upload.","private-key-password":"Private key password","use-system-smtp-settings":"Use system SMTP settings","smtp-protocol":"Protocol","smtp-host":"SMTP host","smtp-host-required":"SMTP host is required.","smtp-port":"SMTP port","smtp-port-required":"You must supply a smtp port.","smtp-port-range":"SMTP port should be in a range from 1 to 65535.","timeout-msec":"Timeout ms","min-timeout-msec-message":"Only 0 ms minimum value is allowed.","enter-username":"Enter username","enter-password":"Enter password","enable-tls":"Enable TLS"},"key-val":{key:"Key",value:"Value","remove-entry":"Remove entry","add-entry":"Add entry"}}};angular.merge(e.en_US,t)}Object.defineProperty(t,"__esModule",{value:!0}),t.default=n},function(e,t,n){"use strict";function a(e){return e&&e.__esModule?e:{default:e}}function r(e,t){(0,o.default)(t);for(var n in t){var a=t[n];e.translations(n,a)}}r.$inject=["$translateProvider","locales"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=r;var i=n(73),o=a(i)},function(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=angular.module("thingsboard.ruleChain.config.types",[]).constant("ruleNodeTypes",{messageType:{POST_ATTRIBUTES_REQUEST:{name:"Post attributes",value:"POST_ATTRIBUTES_REQUEST"},POST_TELEMETRY_REQUEST:{name:"Post telemetry",value:"POST_TELEMETRY_REQUEST"},TO_SERVER_RPC_REQUEST:{name:"RPC Request from Device",value:"TO_SERVER_RPC_REQUEST"},RPC_CALL_FROM_SERVER_TO_DEVICE:{name:"RPC Request to Device",value:"RPC_CALL_FROM_SERVER_TO_DEVICE"},ACTIVITY_EVENT:{name:"Activity Event",value:"ACTIVITY_EVENT"},INACTIVITY_EVENT:{name:"Inactivity Event",value:"INACTIVITY_EVENT"},CONNECT_EVENT:{name:"Connect Event",value:"CONNECT_EVENT"},DISCONNECT_EVENT:{name:"Disconnect Event",value:"DISCONNECT_EVENT"},ENTITY_CREATED:{name:"Entity Created",value:"ENTITY_CREATED"},ENTITY_UPDATED:{name:"Entity Updated",value:"ENTITY_UPDATED"},ENTITY_DELETED:{name:"Entity Deleted",value:"ENTITY_DELETED"},ENTITY_ASSIGNED:{name:"Entity Assigned",value:"ENTITY_ASSIGNED"},ENTITY_UNASSIGNED:{name:"Entity Unassigned",value:"ENTITY_UNASSIGNED"},ATTRIBUTES_UPDATED:{name:"Attributes Updated",value:"ATTRIBUTES_UPDATED"},ATTRIBUTES_DELETED:{name:"Attributes Deleted",value:"ATTRIBUTES_DELETED"}},originatorSource:{CUSTOMER:{name:"tb.rulenode.originator-customer",value:"CUSTOMER"},TENANT:{name:"tb.rulenode.originator-tenant",value:"TENANT"},RELATED:{name:"tb.rulenode.originator-related",value:"RELATED"}},httpRequestType:["GET","POST","PUT","DELETE"],sqsQueueType:{STANDARD:{name:"tb.rulenode.sqs-queue-standard",value:"STANDARD"},FIFO:{name:"tb.rulenode.sqs-queue-fifo",value:"FIFO"}},mqttCredentialTypes:{anonymous:{value:"anonymous",name:"tb.rulenode.credentials-anonymous"},basic:{value:"basic",name:"tb.rulenode.credentials-basic"},"cert.PEM":{value:"cert.PEM",name:"tb.rulenode.credentials-pem"}}}).name}])); | |
4 | 4 | //# sourceMappingURL=rulenode-core-config.js.map |
\ No newline at end of file | ... | ... |
... | ... | @@ -92,6 +92,7 @@ public class GatewaySessionCtx { |
92 | 92 | device.setType(deviceType); |
93 | 93 | device = deviceService.saveDevice(device); |
94 | 94 | relationService.saveRelationAsync(new EntityRelation(gateway.getId(), device.getId(), "Created")); |
95 | + processor.onDeviceAdded(device); | |
95 | 96 | } |
96 | 97 | GatewayDeviceSessionCtx ctx = new GatewayDeviceSessionCtx(this, device); |
97 | 98 | devices.put(deviceName, ctx); |
... | ... | @@ -154,6 +155,7 @@ public class GatewaySessionCtx { |
154 | 155 | GatewayDeviceSessionCtx deviceSessionCtx = devices.get(deviceName); |
155 | 156 | processor.process(new BasicTransportToDeviceSessionActorMsg(deviceSessionCtx.getDevice(), |
156 | 157 | new BasicAdaptorToSessionActorMsg(deviceSessionCtx, new ToDeviceRpcResponseMsg(requestId, data)))); |
158 | + ack(mqttMsg); | |
157 | 159 | } else { |
158 | 160 | throw new JsonSyntaxException(CAN_T_PARSE_VALUE + json); |
159 | 161 | } | ... | ... |
... | ... | @@ -13,804 +13,1321 @@ |
13 | 13 | * See the License for the specific language governing permissions and |
14 | 14 | * limitations under the License. |
15 | 15 | */ |
16 | - export default function addLocaleSpanish(locales) { | |
16 | +export default function addLocaleSpanish(locales) { | |
17 | 17 | var es_ES = { |
18 | - "access": { | |
19 | - "unauthorized": "No autorizado", | |
20 | - "unauthorized-access": "Acceso no autorizado", | |
21 | - "unauthorized-access-text": "Debes iniciar sesión para tener acceso a este recurso!", | |
22 | - "access-forbidden": "Acceso Prohibido", | |
23 | - "access-forbidden-text": "No tienes derechos para acceder a esta ubicación!<br/>Intenta iniciar sesión con otro usuario si todavía quieres acceder a esta ubicación.", | |
24 | - "refresh-token-expired": "La sesión ha expirado", | |
25 | - "refresh-token-failed": "No se puede actualizar la sesión" | |
18 | + "access": { | |
19 | + "unauthorized": "No autorizado", | |
20 | + "unauthorized-access": "Acceso no autorizado", | |
21 | + "unauthorized-access-text": "Debes iniciar sesión para tener acceso a este recurso!", | |
22 | + "access-forbidden": "Acceso Prohibido", | |
23 | + "access-forbidden-text": "No tienes derechos para acceder a esta ubicación!<br/>Intenta iniciar sesión con otro usuario si todavía quieres acceder a esta ubicación.", | |
24 | + "refresh-token-expired": "La sesión ha expirado", | |
25 | + "refresh-token-failed": "No se puede actualizar la sesión" | |
26 | 26 | }, |
27 | 27 | "action": { |
28 | - "activate": "Activar", | |
29 | - "suspend": "Suspender", | |
30 | - "save": "Guardar", | |
31 | - "saveAs": "Guardar como", | |
32 | - "cancel": "Cancelar", | |
33 | - "ok": "OK", | |
34 | - "delete": "Borrar", | |
35 | - "add": "Agregar", | |
36 | - "yes": "Si", | |
37 | - "no": "No", | |
38 | - "update": "Actualizar", | |
39 | - "remove": "Eliminar", | |
40 | - "search": "Buscar", | |
41 | - "assign": "Asignar", | |
42 | - "unassign": "Cancelar asignación", | |
43 | - "share": "Compartir", | |
44 | - "make-private": "Hacer privado", | |
45 | - "apply": "Aplicar", | |
46 | - "apply-changes": "Aplicar cambios", | |
47 | - "edit-mode": "Modo Edición", | |
48 | - "enter-edit-mode": "Modo Edición", | |
49 | - "decline-changes": "Descartar cambios", | |
50 | - "close": "Cerrar", | |
51 | - "back": "Atrás", | |
52 | - "run": "Correr", | |
53 | - "sign-in": "Regístrate!", | |
54 | - "edit": "Editar", | |
55 | - "view": "Ver", | |
56 | - "create": "Crear", | |
57 | - "drag": "Arrastrar", | |
58 | - "refresh": "Refrescar", | |
59 | - "undo": "Deshacer", | |
60 | - "copy": "Copiar", | |
61 | - "paste": "Pegar", | |
62 | - "import": "Importar", | |
63 | - "export": "Exportar", | |
64 | - "share-via": "Compartir vía {{provider}}" | |
28 | + "activate": "Activar", | |
29 | + "suspend": "Suspender", | |
30 | + "save": "Guardar", | |
31 | + "saveAs": "Guardar como", | |
32 | + "cancel": "Cancelar", | |
33 | + "ok": "OK", | |
34 | + "delete": "Borrar", | |
35 | + "add": "Agregar", | |
36 | + "yes": "Si", | |
37 | + "no": "No", | |
38 | + "update": "Actualizar", | |
39 | + "remove": "Eliminar", | |
40 | + "search": "Buscar", | |
41 | + "assign": "Asignar", | |
42 | + "unassign": "Cancelar asignación", | |
43 | + "share": "Compartir", | |
44 | + "make-private": "Hacer privado", | |
45 | + "apply": "Aplicar", | |
46 | + "apply-changes": "Aplicar cambios", | |
47 | + "edit-mode": "Modo Edición", | |
48 | + "enter-edit-mode": "Modo Edición", | |
49 | + "decline-changes": "Descartar cambios", | |
50 | + "close": "Cerrar", | |
51 | + "back": "Atrás", | |
52 | + "run": "Correr", | |
53 | + "sign-in": "Regístrate!", | |
54 | + "edit": "Editar", | |
55 | + "view": "Ver", | |
56 | + "create": "Crear", | |
57 | + "drag": "Arrastrar", | |
58 | + "refresh": "Refrescar", | |
59 | + "undo": "Deshacer", | |
60 | + "copy": "Copiar", | |
61 | + "paste": "Pegar", | |
62 | + "import": "Importar", | |
63 | + "export": "Exportar", | |
64 | + "share-via": "Compartir vía {{provider}}" | |
65 | 65 | }, |
66 | 66 | "aggregation": { |
67 | - "aggregation": "Agregación", | |
68 | - "function": "Función de Agregación", | |
69 | - "limit": "Valores Max", | |
70 | - "group-interval": "Intervalo de agrupación", | |
71 | - "min": "Min", | |
72 | - "max": "Max", | |
73 | - "avg": "Promedio", | |
74 | - "sum": "Suma", | |
75 | - "count": "Cuenta", | |
76 | - "none": "Ninguno" | |
67 | + "aggregation": "Agregación", | |
68 | + "function": "Función de Agregación", | |
69 | + "limit": "Valores Max", | |
70 | + "group-interval": "Intervalo de agrupación", | |
71 | + "min": "Min", | |
72 | + "max": "Max", | |
73 | + "avg": "Promedio", | |
74 | + "sum": "Suma", | |
75 | + "count": "Cuenta", | |
76 | + "none": "Ninguno" | |
77 | 77 | }, |
78 | 78 | "admin": { |
79 | - "general": "General", | |
80 | - "general-settings": "Ajustes General", | |
81 | - "outgoing-mail": "Mail de Salida", | |
82 | - "outgoing-mail-settings": "Ajustes del Mail de Salida", | |
83 | - "system-settings": "Sistema", | |
84 | - "test-mail-sent": "Mail de prueba enviado correctamente!", | |
85 | - "base-url": "URL Base", | |
86 | - "base-url-required": "URL Base requerida.", | |
87 | - "mail-from": "Mail Desde", | |
88 | - "mail-from-required": "Mail Desde requerido.", | |
89 | - "smtp-protocol": "Protocolo SMTP", | |
90 | - "smtp-host": "Host SMTP", | |
91 | - "smtp-host-required": "Host SMTP requerido.", | |
92 | - "smtp-port": "Puerto SMTP", | |
93 | - "smtp-port-required": "Debe ingresar un Puerto SMTP.", | |
94 | - "smtp-port-invalid": "No parece un Puerto SMTP valido.", | |
95 | - "timeout-msec": "Timeout (ms)", | |
96 | - "timeout-required": "Timeout requerido.", | |
97 | - "timeout-invalid": "No parece un Timeout valido.", | |
98 | - "enable-tls": "Habilitar TLS", | |
99 | - "send-test-mail": "Enviar mail de prueba" | |
79 | + "general": "General", | |
80 | + "general-settings": "Ajustes General", | |
81 | + "outgoing-mail": "Mail de Salida", | |
82 | + "outgoing-mail-settings": "Ajustes del Mail de Salida", | |
83 | + "system-settings": "Sistema", | |
84 | + "test-mail-sent": "Mail de prueba enviado correctamente!", | |
85 | + "base-url": "URL Base", | |
86 | + "base-url-required": "URL Base requerida.", | |
87 | + "mail-from": "Mail Desde", | |
88 | + "mail-from-required": "Mail Desde requerido.", | |
89 | + "smtp-protocol": "Protocolo SMTP", | |
90 | + "smtp-host": "Host SMTP", | |
91 | + "smtp-host-required": "Host SMTP requerido.", | |
92 | + "smtp-port": "Puerto SMTP", | |
93 | + "smtp-port-required": "Debe ingresar un Puerto SMTP.", | |
94 | + "smtp-port-invalid": "No parece un Puerto SMTP valido.", | |
95 | + "timeout-msec": "Timeout (ms)", | |
96 | + "timeout-required": "Timeout requerido.", | |
97 | + "timeout-invalid": "No parece un Timeout valido.", | |
98 | + "enable-tls": "Habilitar TLS", | |
99 | + "send-test-mail": "Enviar mail de prueba" | |
100 | + }, | |
101 | + "alarm": { // TODO | |
102 | + "alarm": "Alarm", | |
103 | + "alarms": "Alarms", | |
104 | + "select-alarm": "Select alarm", | |
105 | + "no-alarms-matching": "No alarms matching '{{entity}}' were found.", | |
106 | + "alarm-required": "Alarm is required", | |
107 | + "alarm-status": "Alarm status", | |
108 | + "search-status": { | |
109 | + "ANY": "Any", | |
110 | + "ACTIVE": "Active", | |
111 | + "CLEARED": "Cleared", | |
112 | + "ACK": "Acknowledged", | |
113 | + "UNACK": "Unacknowledged" | |
114 | + }, | |
115 | + "display-status": { | |
116 | + "ACTIVE_UNACK": "Active Unacknowledged", | |
117 | + "ACTIVE_ACK": "Active Acknowledged", | |
118 | + "CLEARED_UNACK": "Cleared Unacknowledged", | |
119 | + "CLEARED_ACK": "Cleared Acknowledged" | |
120 | + }, | |
121 | + "no-alarms-prompt": "No alarms found", | |
122 | + "created-time": "Created time", | |
123 | + "type": "Type", | |
124 | + "severity": "Severity", | |
125 | + "originator": "Originator", | |
126 | + "originator-type": "Originator type", | |
127 | + "details": "Details", | |
128 | + "status": "Status", | |
129 | + "alarm-details": "Alarm details", | |
130 | + "start-time": "Start time", | |
131 | + "end-time": "End time", | |
132 | + "ack-time": "Acknowledged time", | |
133 | + "clear-time": "Cleared time", | |
134 | + "severity-critical": "Critical", | |
135 | + "severity-major": "Major", | |
136 | + "severity-minor": "Minor", | |
137 | + "severity-warning": "Warning", | |
138 | + "severity-indeterminate": "Indeterminate", | |
139 | + "acknowledge": "Acknowledge", | |
140 | + "clear": "Clear", | |
141 | + "search": "Search alarms", | |
142 | + "selected-alarms": "{ count, select, 1 {1 alarm} other {# alarms} } selected", | |
143 | + "no-data": "No data to display", | |
144 | + "polling-interval": "Alarms polling interval (sec)", | |
145 | + "polling-interval-required": "Alarms polling interval is required.", | |
146 | + "min-polling-interval-message": "At least 1 sec polling interval is allowed.", | |
147 | + "aknowledge-alarms-title": "Acknowledge { count, select, 1 {1 alarm} other {# alarms} }", | |
148 | + "aknowledge-alarms-text": "Are you sure you want to acknowledge { count, select, 1 {1 alarm} other {# alarms} }?", | |
149 | + "clear-alarms-title": "Clear { count, select, 1 {1 alarm} other {# alarms} }", | |
150 | + "clear-alarms-text": "Are you sure you want to clear { count, select, 1 {1 alarm} other {# alarms} }?" | |
151 | + }, | |
152 | + "alias": { // TODO | |
153 | + "add": "Add alias", | |
154 | + "edit": "Edit alias", | |
155 | + "name": "Alias name", | |
156 | + "name-required": "Alias name is required", | |
157 | + "duplicate-alias": "Alias with same name is already exists.", | |
158 | + "filter-type-single-entity": "Single entity", | |
159 | + "filter-type-entity-list": "Entity list", | |
160 | + "filter-type-entity-name": "Entity name", | |
161 | + "filter-type-state-entity": "Entity from dashboard state", | |
162 | + "filter-type-state-entity-description": "Entity taken from dashboard state parameters", | |
163 | + "filter-type-asset-type": "Asset type", | |
164 | + "filter-type-asset-type-description": "Assets of type '{{assetType}}'", | |
165 | + "filter-type-asset-type-and-name-description": "Assets of type '{{assetType}}' and with name starting with '{{prefix}}'", | |
166 | + "filter-type-device-type": "Device type", | |
167 | + "filter-type-device-type-description": "Devices of type '{{deviceType}}'", | |
168 | + "filter-type-device-type-and-name-description": "Devices of type '{{deviceType}}' and with name starting with '{{prefix}}'", | |
169 | + "filter-type-relations-query": "Relations query", | |
170 | + "filter-type-relations-query-description": "{{entities}} that have {{relationType}} relation {{direction}} {{rootEntity}}", | |
171 | + "filter-type-asset-search-query": "Asset search query", | |
172 | + "filter-type-asset-search-query-description": "Assets with types {{assetTypes}} that have {{relationType}} relation {{direction}} {{rootEntity}}", | |
173 | + "filter-type-device-search-query": "Device search query", | |
174 | + "filter-type-device-search-query-description": "Devices with types {{deviceTypes}} that have {{relationType}} relation {{direction}} {{rootEntity}}", | |
175 | + "entity-filter": "Entity filter", | |
176 | + "resolve-multiple": "Resolve as multiple entities", | |
177 | + "filter-type": "Filter type", | |
178 | + "filter-type-required": "Filter type is required.", | |
179 | + "entity-filter-no-entity-matched": "No entities matching specified filter were found.", | |
180 | + "no-entity-filter-specified": "No entity filter specified", | |
181 | + "root-state-entity": "Use dashboard state entity as root", | |
182 | + "root-entity": "Root entity", | |
183 | + "state-entity-parameter-name": "State entity parameter name", | |
184 | + "default-state-entity": "Default state entity", | |
185 | + "default-entity-parameter-name": "By default", | |
186 | + "max-relation-level": "Max relation level", | |
187 | + "unlimited-level": "Unlimited level", | |
188 | + "state-entity": "Dashboard state entity", | |
189 | + "all-entities": "All entities", | |
190 | + "any-relation": "any" | |
191 | + }, | |
192 | + "asset": { // TODO | |
193 | + "asset": "Asset", | |
194 | + "assets": "Assets", | |
195 | + "management": "Asset management", | |
196 | + "view-assets": "View Assets", | |
197 | + "add": "Add Asset", | |
198 | + "assign-to-customer": "Assign to customer", | |
199 | + "assign-asset-to-customer": "Assign Asset(s) To Customer", | |
200 | + "assign-asset-to-customer-text": "Please select the assets to assign to the customer", | |
201 | + "no-assets-text": "No assets found", | |
202 | + "assign-to-customer-text": "Please select the customer to assign the asset(s)", | |
203 | + "public": "Public", | |
204 | + "assignedToCustomer": "Assigned to customer", | |
205 | + "make-public": "Make asset public", | |
206 | + "make-private": "Make asset private", | |
207 | + "unassign-from-customer": "Unassign from customer", | |
208 | + "delete": "Delete asset", | |
209 | + "asset-public": "Asset is public", | |
210 | + "asset-type": "Asset type", | |
211 | + "asset-type-required": "Asset type is required.", | |
212 | + "select-asset-type": "Select asset type", | |
213 | + "enter-asset-type": "Enter asset type", | |
214 | + "any-asset": "Any asset", | |
215 | + "no-asset-types-matching": "No asset types matching '{{entitySubtype}}' were found.", | |
216 | + "asset-type-list-empty": "No asset types selected.", | |
217 | + "asset-types": "Asset types", | |
218 | + "name": "Name", | |
219 | + "name-required": "Name is required.", | |
220 | + "description": "Description", | |
221 | + "type": "Type", | |
222 | + "type-required": "Type is required.", | |
223 | + "details": "Details", | |
224 | + "events": "Events", | |
225 | + "add-asset-text": "Add new asset", | |
226 | + "asset-details": "Asset details", | |
227 | + "assign-assets": "Assign assets", | |
228 | + "assign-assets-text": "Assign { count, select, 1 {1 asset} other {# assets} } to customer", | |
229 | + "delete-assets": "Delete assets", | |
230 | + "unassign-assets": "Unassign assets", | |
231 | + "unassign-assets-action-title": "Unassign { count, select, 1 {1 asset} other {# assets} } from customer", | |
232 | + "assign-new-asset": "Assign new asset", | |
233 | + "delete-asset-title": "Are you sure you want to delete the asset '{{assetName}}'?", | |
234 | + "delete-asset-text": "Be careful, after the confirmation the asset and all related data will become unrecoverable.", | |
235 | + "delete-assets-title": "Are you sure you want to delete { count, select, 1 {1 asset} other {# assets} }?", | |
236 | + "delete-assets-action-title": "Delete { count, select, 1 {1 asset} other {# assets} }", | |
237 | + "delete-assets-text": "Be careful, after the confirmation all selected assets will be removed and all related data will become unrecoverable.", | |
238 | + "make-public-asset-title": "Are you sure you want to make the asset '{{assetName}}' public?", | |
239 | + "make-public-asset-text": "After the confirmation the asset and all its data will be made public and accessible by others.", | |
240 | + "make-private-asset-title": "Are you sure you want to make the asset '{{assetName}}' private?", | |
241 | + "make-private-asset-text": "After the confirmation the asset and all its data will be made private and won't be accessible by others.", | |
242 | + "unassign-asset-title": "Are you sure you want to unassign the asset '{{assetName}}'?", | |
243 | + "unassign-asset-text": "After the confirmation the asset will be unassigned and won't be accessible by the customer.", | |
244 | + "unassign-asset": "Unassign asset", | |
245 | + "unassign-assets-title": "Are you sure you want to unassign { count, select, 1 {1 asset} other {# assets} }?", | |
246 | + "unassign-assets-text": "After the confirmation all selected assets will be unassigned and won't be accessible by the customer.", | |
247 | + "copyId": "Copy asset Id", | |
248 | + "idCopiedMessage": "Asset Id has been copied to clipboard", | |
249 | + "select-asset": "Select asset", | |
250 | + "no-assets-matching": "No assets matching '{{entity}}' were found.", | |
251 | + "asset-required": "Asset is required", | |
252 | + "name-starts-with": "Asset name starts with" | |
100 | 253 | }, |
101 | 254 | "attribute": { |
102 | - "attributes": "Atributos", | |
103 | - "latest-telemetry": "Última telemetría", | |
104 | - "attributes-scope": "Alcance de los atributos del dispositivo", | |
105 | - "scope-latest-telemetry": "Última telemetría", | |
106 | - "scope-client": "Atributos del Cliente", | |
107 | - "scope-server": "Atributos del Servidor", | |
108 | - "scope-shared": "Atributos Compartidos", | |
109 | - "add": "Agregar atributo", | |
110 | - "key": "Clave", | |
111 | - "key-required": "Clave del atributo requerida.", | |
112 | - "value": "Valor", | |
113 | - "value-required": "Valor del atributo requerido.", | |
114 | - "delete-attributes-title": "¿Estás seguro que quieres eliminar { count, select, 1 {1 atributo} other {# atributos} }?", | |
115 | - "delete-attributes-text": "Ten cuidado, luego de confirmar el atributo será eliminado, y la información relacionada será irrecuperable.", | |
116 | - "delete-attributes": "Borrar atributo", | |
117 | - "enter-attribute-value": "Ingresar valor del atributo", | |
118 | - "show-on-widget": "Mostrar en Widget", | |
119 | - "widget-mode": "Widget", | |
120 | - "next-widget": "Widget siguiente", | |
121 | - "prev-widget": "Widget anterior", | |
122 | - "add-to-dashboard": "Agregar al Panel", | |
123 | - "add-widget-to-dashboard": "Agregar widget al Panel", | |
124 | - "selected-attributes": "{ count, select, 1 {1 atributo} other {# atributos} } seleccionados", | |
125 | - "selected-telemetry": "{ count, select, 1 {1 unidad de telemetría } other {# unidades de telemetría} } seleccionadas." | |
255 | + "attributes": "Atributos", | |
256 | + "latest-telemetry": "Última telemetría", | |
257 | + "attributes-scope": "Alcance de los atributos del dispositivo", | |
258 | + "scope-latest-telemetry": "Última telemetría", | |
259 | + "scope-client": "Atributos del Cliente", | |
260 | + "scope-server": "Atributos del Servidor", | |
261 | + "scope-shared": "Atributos Compartidos", | |
262 | + "add": "Agregar atributo", | |
263 | + "key": "Clave", | |
264 | + "key-required": "Clave del atributo requerida.", | |
265 | + "value": "Valor", | |
266 | + "value-required": "Valor del atributo requerido.", | |
267 | + "delete-attributes-title": "¿Estás seguro que quieres eliminar { count, select, 1 {1 atributo} other {# atributos} }?", | |
268 | + "delete-attributes-text": "Ten cuidado, luego de confirmar el atributo será eliminado, y la información relacionada será irrecuperable.", | |
269 | + "delete-attributes": "Borrar atributo", | |
270 | + "enter-attribute-value": "Ingresar valor del atributo", | |
271 | + "show-on-widget": "Mostrar en Widget", | |
272 | + "widget-mode": "Widget", | |
273 | + "next-widget": "Widget siguiente", | |
274 | + "prev-widget": "Widget anterior", | |
275 | + "add-to-dashboard": "Agregar al Panel", | |
276 | + "add-widget-to-dashboard": "Agregar widget al Panel", | |
277 | + "selected-attributes": "{ count, select, 1 {1 atributo} other {# atributos} } seleccionados", | |
278 | + "selected-telemetry": "{ count, select, 1 {1 unidad de telemetría } other {# unidades de telemetría} } seleccionadas." | |
279 | + }, | |
280 | + "audit-log": { // TODO | |
281 | + "audit": "Audit", | |
282 | + "audit-logs": "Audit Logs", | |
283 | + "timestamp": "Timestamp", | |
284 | + "entity-type": "Entity Type", | |
285 | + "entity-name": "Entity Name", | |
286 | + "user": "User", | |
287 | + "type": "Type", | |
288 | + "status": "Status", | |
289 | + "details": "Details", | |
290 | + "type-added": "Added", | |
291 | + "type-deleted": "Deleted", | |
292 | + "type-updated": "Updated", | |
293 | + "type-attributes-updated": "Attributes updated", | |
294 | + "type-attributes-deleted": "Attributes deleted", | |
295 | + "type-rpc-call": "RPC call", | |
296 | + "type-credentials-updated": "Credentials updated", | |
297 | + "type-assigned-to-customer": "Assigned to Customer", | |
298 | + "type-unassigned-from-customer": "Unassigned from Customer", | |
299 | + "type-activated": "Activated", | |
300 | + "type-suspended": "Suspended", | |
301 | + "type-credentials-read": "Credentials read", | |
302 | + "type-attributes-read": "Attributes read", | |
303 | + "status-success": "Success", | |
304 | + "status-failure": "Failure", | |
305 | + "audit-log-details": "Audit log details", | |
306 | + "no-audit-logs-prompt": "No logs found", | |
307 | + "action-data": "Action data", | |
308 | + "failure-details": "Failure details", | |
309 | + "search": "Search audit logs", | |
310 | + "clear-search": "Clear search" | |
126 | 311 | }, |
127 | 312 | "confirm-on-exit": { |
128 | - "message": "Tienes cambios sin guardar. ¿Estás seguro que quieres abandonar la página?", | |
129 | - "html-message": "Tienes cambios sin guardar.<br/>¿Estás seguro que quieres abandonar la página?", | |
130 | - "title": "Cambios sin guardar" | |
313 | + "message": "Tienes cambios sin guardar. ¿Estás seguro que quieres abandonar la página?", | |
314 | + "html-message": "Tienes cambios sin guardar.<br/>¿Estás seguro que quieres abandonar la página?", | |
315 | + "title": "Cambios sin guardar" | |
131 | 316 | }, |
132 | 317 | "contact": { |
133 | - "country": "País", | |
134 | - "city": "Ciudad", | |
135 | - "state": "Estado/Provincia", | |
136 | - "postal-code": "Código Postal", | |
137 | - "postal-code-invalid": "Solo se permiten dígitos.", | |
138 | - "address": "Dirección", | |
139 | - "address2": "Dirección 2", | |
140 | - "phone": "Teléfono", | |
141 | - "email": "Email", | |
142 | - "no-address": "Sin Dirección" | |
318 | + "country": "País", | |
319 | + "city": "Ciudad", | |
320 | + "state": "Estado/Provincia", | |
321 | + "postal-code": "Código Postal", | |
322 | + "postal-code-invalid": "Solo se permiten dígitos.", | |
323 | + "address": "Dirección", | |
324 | + "address2": "Dirección 2", | |
325 | + "phone": "Teléfono", | |
326 | + "email": "Email", | |
327 | + "no-address": "Sin Dirección" | |
143 | 328 | }, |
144 | 329 | "common": { |
145 | - "username": "Usuario", | |
146 | - "password": "Contraseña", | |
147 | - "enter-username": "Ingresa el nombre de usuario.", | |
148 | - "enter-password": "Ingresa la contraseña", | |
149 | - "enter-search": "Ingresa búsqueda" | |
330 | + "username": "Usuario", | |
331 | + "password": "Contraseña", | |
332 | + "enter-username": "Ingresa el nombre de usuario.", | |
333 | + "enter-password": "Ingresa la contraseña", | |
334 | + "enter-search": "Ingresa búsqueda" | |
335 | + }, | |
336 | + "content-type": { // TODO | |
337 | + "json": "Json", | |
338 | + "text": "Text", | |
339 | + "binary": "Binary (Base64)" | |
150 | 340 | }, |
151 | 341 | "customer": { |
152 | - "customers": "Clientes", | |
153 | - "management": "Gestión de Clientes", | |
154 | - "dashboard": "Panel del Cliente", | |
155 | - "dashboards": "Paneles del Cliente", | |
156 | - "devices": "Panel del Cliente", | |
157 | - "public-dashboards": "Paneles Públicos", | |
158 | - "public-devices": "Dispositivos Públicos", | |
159 | - "add": "Agregar cliente", | |
160 | - "delete": "Borrar cliente", | |
161 | - "manage-customer-users": "Gestionar usuarios del cliente", | |
162 | - "manage-customer-devices": "Gestionar dispositivos del cliente", | |
163 | - "manage-customer-dashboards": "Gestionar paneles del cliente", | |
164 | - "manage-public-devices": "Gestionar dispositivos públicos", | |
165 | - "manage-public-dashboards": "Gestionar paneles públicos", | |
166 | - "add-customer-text": "Agregar nuevo cliente", | |
167 | - "no-customers-text": "No se encontrar clientes", | |
168 | - "customer-details": "Detalles del cliente", | |
169 | - "delete-customer-title": "¿Estás seguro que quieres eliminar el cliente '{{customerTitle}}'?", | |
170 | - "delete-customer-text": "Ten cuidado, luego de confirmar el cliente será eliminado y toda la información relacionada será irrecuperable.", | |
171 | - "delete-customers-title": "¿Estás seguro que quieres eliminar { count, select, 1 {1 cliente} other {# clientes} }?", | |
172 | - "delete-customers-action-title": "Borrar { count, select, 1 {1 cliente} other {# clientes} }", | |
173 | - "delete-customers-text": "Ten cuidado, luego de confirmar todos los clientes seleccionados serán eliminados y su información relacionada será irrecuperable.", | |
174 | - "manage-users": "Gestionar usuarios", | |
175 | - "manage-devices": "Gestionar dispositivos", | |
176 | - "manage-dashboards": "Gestionar paneles", | |
177 | - "title": "Título", | |
178 | - "title-required": "Título requerido.", | |
179 | - "description": "Descripción" | |
342 | + "customers": "Clientes", | |
343 | + "management": "Gestión de Clientes", | |
344 | + "dashboard": "Panel del Cliente", | |
345 | + "dashboards": "Paneles del Cliente", | |
346 | + "devices": "Panel del Cliente", | |
347 | + "public-dashboards": "Paneles Públicos", | |
348 | + "public-devices": "Dispositivos Públicos", | |
349 | + "add": "Agregar cliente", | |
350 | + "delete": "Borrar cliente", | |
351 | + "manage-customer-users": "Gestionar usuarios del cliente", | |
352 | + "manage-customer-devices": "Gestionar dispositivos del cliente", | |
353 | + "manage-customer-dashboards": "Gestionar paneles del cliente", | |
354 | + "manage-public-devices": "Gestionar dispositivos públicos", | |
355 | + "manage-public-dashboards": "Gestionar paneles públicos", | |
356 | + "add-customer-text": "Agregar nuevo cliente", | |
357 | + "no-customers-text": "No se encontrar clientes", | |
358 | + "customer-details": "Detalles del cliente", | |
359 | + "delete-customer-title": "¿Estás seguro que quieres eliminar el cliente '{{customerTitle}}'?", | |
360 | + "delete-customer-text": "Ten cuidado, luego de confirmar el cliente será eliminado y toda la información relacionada será irrecuperable.", | |
361 | + "delete-customers-title": "¿Estás seguro que quieres eliminar { count, select, 1 {1 cliente} other {# clientes} }?", | |
362 | + "delete-customers-action-title": "Borrar { count, select, 1 {1 cliente} other {# clientes} }", | |
363 | + "delete-customers-text": "Ten cuidado, luego de confirmar todos los clientes seleccionados serán eliminados y su información relacionada será irrecuperable.", | |
364 | + "manage-users": "Gestionar usuarios", | |
365 | + "manage-devices": "Gestionar dispositivos", | |
366 | + "manage-dashboards": "Gestionar paneles", | |
367 | + "title": "Título", | |
368 | + "title-required": "Título requerido.", | |
369 | + "description": "Descripción" | |
180 | 370 | }, |
181 | 371 | "datetime": { |
182 | - "date-from": "Fecha desde", | |
183 | - "time-from": "Tiempo desde", | |
184 | - "date-to": "Fecha hasta", | |
185 | - "time-to": "Tiempo hasta" | |
372 | + "date-from": "Fecha desde", | |
373 | + "time-from": "Tiempo desde", | |
374 | + "date-to": "Fecha hasta", | |
375 | + "time-to": "Tiempo hasta" | |
186 | 376 | }, |
187 | 377 | "dashboard": { |
188 | - "dashboard": "Panel", | |
189 | - "dashboards": "Paneles", | |
190 | - "management": "Gestión de Paneles", | |
191 | - "view-dashboards": "Ver paneles", | |
192 | - "add": "Agregar Panel", | |
193 | - "assign-dashboard-to-customer": "Asignar panel(es) a cliente", | |
194 | - "assign-dashboard-to-customer-text": "Por favor, seleccione algún panel para asignar al Cliente.", | |
195 | - "assign-to-customer-text": "Por favor, seleccione algún cliente para asignar al(los) panel(es).", | |
196 | - "assign-to-customer": "Asignar a cliente", | |
197 | - "unassign-from-customer": "Desasignar del cliente", | |
198 | - "make-public": "Hacer panel público", | |
199 | - "make-private": "Hacer panel privado", | |
200 | - "no-dashboards-text": "Ningún panel encontrado", | |
201 | - "no-widgets": "Ningún widget configurado", | |
202 | - "add-widget": "Agregar nuevo widget", | |
203 | - "title": "Titulo", | |
204 | - "select-widget-title": "Seleccionar widget", | |
205 | - "select-widget-subtitle": "Lista de tipos de widgets", | |
206 | - "delete": "Eliminar panel", | |
207 | - "title-required": "Título requerido.", | |
208 | - "description": "Descripción", | |
209 | - "details": "Detalles", | |
210 | - "dashboard-details": "Detalles del panel", | |
211 | - "add-dashboard-text": "Agregar nuevo panel", | |
212 | - "assign-dashboards": "Asignar paneles", | |
213 | - "assign-new-dashboard": "Asignar nuevo panel", | |
214 | - "assign-dashboards-text": "Asignar { count, select, 1 {1 panel} other {# paneles} } al cliente", | |
215 | - "delete-dashboards": "Eliminar paneles", | |
216 | - "unassign-dashboards": "Desasignar paneles", | |
217 | - "unassign-dashboards-action-title": "Desasignar { count, select, 1 {1 paneles} other {# paneles} } del cliente", | |
218 | - "delete-dashboard-title": "¿Estás seguro que quieres eliminar el panel '{{dashboardTitle}}'?", | |
219 | - "delete-dashboard-text": "Ten cuidado, el panel seleccionado será eliminado y la información relacionada sera irrecuperable.", | |
220 | - "delete-dashboards-title": "¿Estás seguro que quieres eliminar { count, select, 1 {1 panel} other {# paneles} }?", | |
221 | - "delete-dashboards-action-title": "Eliminar { count, select, 1 {1 panel} other {# paneles} }", | |
222 | - "delete-dashboards-text": "Ten cuidado, los paneles seleccionados serán eliminados y la información relacionada será irrecuperable.", | |
223 | - "unassign-dashboard-title": "¿Estás seguro que quieres desasignar el panel '{{dashboardTitle}}'?", | |
224 | - "unassign-dashboard-text": "Luego de confirmar, el panel será desasignado y no podrá ser accesible por el cliente.", | |
225 | - "unassign-dashboard": "Desasignar panel", | |
226 | - "unassign-dashboards-title": "¿Estás seguro que quieres desasignar { count, select, 1 {1 panel} other {# paneles} }?", | |
227 | - "unassign-dashboards-text": "Luego de confirmar, los paneles seleccionados serán desasignados y no podrán ser accesibles por el cliente.", | |
228 | - "public-dashboard-title": "El panel ahora es público", | |
229 | - "public-dashboard-text": "Tu panel <b>{{dashboardTitle}}</b> es ahora público y podrá ser accedido desde: <a href='{{publicLink}}' target='_blank'>aquí</a>:", | |
230 | - "public-dashboard-notice": "<b>Nota:</b> No olvides hacer públicos los dispositivos relacionados para acceder a sus datos.", | |
231 | - "make-private-dashboard-title": "¿Estás seguro que quieres hacer el panel '{{dashboardTitle}}' privado?", | |
232 | - "make-private-dashboard-text": "Luego de confirmar, el panel será privado y no podrá ser accesible por otros.", | |
233 | - "make-private-dashboard": "Hacer panel privado", | |
234 | - "socialshare-text": "'{{dashboardTitle}}' powered by ThingsBoard", | |
235 | - "socialshare-title": "'{{dashboardTitle}}' powered by ThingsBoard", | |
236 | - "select-dashboard": "Seleccionar panel", | |
237 | - "no-dashboards-matching": "Panel '{{entity}}' no encontrado.", | |
238 | - "dashboard-required": "Panel requerido.", | |
239 | - "select-existing": "Seleccionar paneles existentes", | |
240 | - "create-new": "Crear nuevo panel", | |
241 | - "new-dashboard-title": "Nuevo título", | |
242 | - "open-dashboard": "Abrir panel", | |
243 | - "set-background": "Definir fondo", | |
244 | - "background-color": "Color de fondo", | |
245 | - "background-image": "Imagen de fondo", | |
246 | - "background-size-mode": "Modo tamaño de fondo", | |
247 | - "no-image": "No se ha seleccionado ningúna imagen", | |
248 | - "drop-image": "Suelte una imagen o haga clic para seleccionar un archivo para cargar.", | |
249 | - "settings": "Ajustes", | |
250 | - "columns-count": "Número de columnas", | |
251 | - "columns-count-required": "Número de columnas requerido.", | |
252 | - "min-columns-count-message": "Solo se permite un número mínimo de 10 columnas.", | |
253 | - "max-columns-count-message": "Solo se permite un número máximo de 1000 columnas.", | |
254 | - "widgets-margins": "Margen entre widgets", | |
255 | - "horizontal-margin": "Margen horizontal", | |
256 | - "horizontal-margin-required": "Margen horizontal requerido.", | |
257 | - "min-horizontal-margin-message": "Solo se permite margen horizontal mínimo de 0.", | |
258 | - "max-horizontal-margin-message": "Solo se permite margen horizontal máximo de 50.", | |
259 | - "vertical-margin": "Margen vertical", | |
260 | - "vertical-margin-required": "Margen vertical requerido.", | |
261 | - "min-vertical-margin-message": "Solo se permite margen vertical mínimo de 0.", | |
262 | - "max-vertical-margin-message": "Solo se permite margen vertical máximo de 50.", | |
263 | - "display-title": "Mostrar título del panel", | |
264 | - "title-color": "Color del título", | |
265 | - "display-device-selection": "Mostrar selección de dispositivo", | |
266 | - "display-dashboard-timewindow": "Mostrar ventana de tiempo", | |
267 | - "display-dashboard-export": "Mostrar exportar", | |
268 | - "import": "Importar panel", | |
269 | - "export": "Exportar panel", | |
270 | - "export-failed-error": "Imposible exportar panel: {{error}}", | |
271 | - "create-new-dashboard": "Crear nuevo panel", | |
272 | - "dashboard-file": "Archivo del panel", | |
273 | - "invalid-dashboard-file-error": "Imposible importar panel: Estructura de datos inválida.", | |
274 | - "dashboard-import-missing-aliases-title": "Configurar alias utilizados por el panel importado", | |
275 | - "create-new-widget": "Crear nuevo widget", | |
276 | - "import-widget": "Importar widget", | |
277 | - "widget-file": "Archivo de widget", | |
278 | - "invalid-widget-file-error": "Imposible importar widget: Estructura de datos inválida.", | |
279 | - "widget-import-missing-aliases-title": "Configurar alias utilizados por el widget", | |
280 | - "open-toolbar": "Abrir toolbar del panel", | |
281 | - "close-toolbar": "Cerrar toolbar", | |
282 | - "configuration-error": "Error de configuración", | |
283 | - "alias-resolution-error-title": "Error de configuración de alias del panel", | |
284 | - "invalid-aliases-config": "No se puede encontrar ningún dispositivo que coincida con algunos de los alias de filtro.<br/>" + | |
285 | - "Póngase en contacto con su administrador para resolver este problema.", | |
286 | - "select-devices": "Seleccionar dispositivos", | |
287 | - "assignedToCustomer": "Asignado al cliente", | |
288 | - "public": "Público", | |
289 | - "public-link": "Link público", | |
290 | - "copy-public-link": "Copiar link público", | |
291 | - "public-link-copied-message": "El link público del panel se ha copiado al portapapeles" | |
378 | + "dashboard": "Panel", | |
379 | + "dashboards": "Paneles", | |
380 | + "management": "Gestión de Paneles", | |
381 | + "view-dashboards": "Ver paneles", | |
382 | + "add": "Agregar Panel", | |
383 | + "assign-dashboard-to-customer": "Asignar panel(es) a cliente", | |
384 | + "assign-dashboard-to-customer-text": "Por favor, seleccione algún panel para asignar al Cliente.", | |
385 | + "assign-to-customer-text": "Por favor, seleccione algún cliente para asignar al(los) panel(es).", | |
386 | + "assign-to-customer": "Asignar a cliente", | |
387 | + "unassign-from-customer": "Desasignar del cliente", | |
388 | + "make-public": "Hacer panel público", | |
389 | + "make-private": "Hacer panel privado", | |
390 | + "no-dashboards-text": "Ningún panel encontrado", | |
391 | + "no-widgets": "Ningún widget configurado", | |
392 | + "add-widget": "Agregar nuevo widget", | |
393 | + "title": "Titulo", | |
394 | + "select-widget-title": "Seleccionar widget", | |
395 | + "select-widget-subtitle": "Lista de tipos de widgets", | |
396 | + "delete": "Eliminar panel", | |
397 | + "title-required": "Título requerido.", | |
398 | + "description": "Descripción", | |
399 | + "details": "Detalles", | |
400 | + "dashboard-details": "Detalles del panel", | |
401 | + "add-dashboard-text": "Agregar nuevo panel", | |
402 | + "assign-dashboards": "Asignar paneles", | |
403 | + "assign-new-dashboard": "Asignar nuevo panel", | |
404 | + "assign-dashboards-text": "Asignar { count, select, 1 {1 panel} other {# paneles} } al cliente", | |
405 | + "delete-dashboards": "Eliminar paneles", | |
406 | + "unassign-dashboards": "Desasignar paneles", | |
407 | + "unassign-dashboards-action-title": "Desasignar { count, select, 1 {1 paneles} other {# paneles} } del cliente", | |
408 | + "delete-dashboard-title": "¿Estás seguro que quieres eliminar el panel '{{dashboardTitle}}'?", | |
409 | + "delete-dashboard-text": "Ten cuidado, el panel seleccionado será eliminado y la información relacionada sera irrecuperable.", | |
410 | + "delete-dashboards-title": "¿Estás seguro que quieres eliminar { count, select, 1 {1 panel} other {# paneles} }?", | |
411 | + "delete-dashboards-action-title": "Eliminar { count, select, 1 {1 panel} other {# paneles} }", | |
412 | + "delete-dashboards-text": "Ten cuidado, los paneles seleccionados serán eliminados y la información relacionada será irrecuperable.", | |
413 | + "unassign-dashboard-title": "¿Estás seguro que quieres desasignar el panel '{{dashboardTitle}}'?", | |
414 | + "unassign-dashboard-text": "Luego de confirmar, el panel será desasignado y no podrá ser accesible por el cliente.", | |
415 | + "unassign-dashboard": "Desasignar panel", | |
416 | + "unassign-dashboards-title": "¿Estás seguro que quieres desasignar { count, select, 1 {1 panel} other {# paneles} }?", | |
417 | + "unassign-dashboards-text": "Luego de confirmar, los paneles seleccionados serán desasignados y no podrán ser accesibles por el cliente.", | |
418 | + "public-dashboard-title": "El panel ahora es público", | |
419 | + "public-dashboard-text": "Tu panel <b>{{dashboardTitle}}</b> es ahora público y podrá ser accedido desde: <a href='{{publicLink}}' target='_blank'>aquí</a>:", | |
420 | + "public-dashboard-notice": "<b>Nota:</b> No olvides hacer públicos los dispositivos relacionados para acceder a sus datos.", | |
421 | + "make-private-dashboard-title": "¿Estás seguro que quieres hacer el panel '{{dashboardTitle}}' privado?", | |
422 | + "make-private-dashboard-text": "Luego de confirmar, el panel será privado y no podrá ser accesible por otros.", | |
423 | + "make-private-dashboard": "Hacer panel privado", | |
424 | + "socialshare-text": "'{{dashboardTitle}}' powered by ThingsBoard", | |
425 | + "socialshare-title": "'{{dashboardTitle}}' powered by ThingsBoard", | |
426 | + "select-dashboard": "Seleccionar panel", | |
427 | + "no-dashboards-matching": "Panel '{{entity}}' no encontrado.", | |
428 | + "dashboard-required": "Panel requerido.", | |
429 | + "select-existing": "Seleccionar paneles existentes", | |
430 | + "create-new": "Crear nuevo panel", | |
431 | + "new-dashboard-title": "Nuevo título", | |
432 | + "open-dashboard": "Abrir panel", | |
433 | + "set-background": "Definir fondo", | |
434 | + "background-color": "Color de fondo", | |
435 | + "background-image": "Imagen de fondo", | |
436 | + "background-size-mode": "Modo tamaño de fondo", | |
437 | + "no-image": "No se ha seleccionado ningúna imagen", | |
438 | + "drop-image": "Suelte una imagen o haga clic para seleccionar un archivo para cargar.", | |
439 | + "settings": "Ajustes", | |
440 | + "columns-count": "Número de columnas", | |
441 | + "columns-count-required": "Número de columnas requerido.", | |
442 | + "min-columns-count-message": "Solo se permite un número mínimo de 10 columnas.", | |
443 | + "max-columns-count-message": "Solo se permite un número máximo de 1000 columnas.", | |
444 | + "widgets-margins": "Margen entre widgets", | |
445 | + "horizontal-margin": "Margen horizontal", | |
446 | + "horizontal-margin-required": "Margen horizontal requerido.", | |
447 | + "min-horizontal-margin-message": "Solo se permite margen horizontal mínimo de 0.", | |
448 | + "max-horizontal-margin-message": "Solo se permite margen horizontal máximo de 50.", | |
449 | + "vertical-margin": "Margen vertical", | |
450 | + "vertical-margin-required": "Margen vertical requerido.", | |
451 | + "min-vertical-margin-message": "Solo se permite margen vertical mínimo de 0.", | |
452 | + "max-vertical-margin-message": "Solo se permite margen vertical máximo de 50.", | |
453 | + "display-title": "Mostrar título del panel", | |
454 | + "title-color": "Color del título", | |
455 | + "display-device-selection": "Mostrar selección de dispositivo", | |
456 | + "display-dashboard-timewindow": "Mostrar ventana de tiempo", | |
457 | + "display-dashboard-export": "Mostrar exportar", | |
458 | + "import": "Importar panel", | |
459 | + "export": "Exportar panel", | |
460 | + "export-failed-error": "Imposible exportar panel: {{error}}", | |
461 | + "create-new-dashboard": "Crear nuevo panel", | |
462 | + "dashboard-file": "Archivo del panel", | |
463 | + "invalid-dashboard-file-error": "Imposible importar panel: Estructura de datos inválida.", | |
464 | + "dashboard-import-missing-aliases-title": "Configurar alias utilizados por el panel importado", | |
465 | + "create-new-widget": "Crear nuevo widget", | |
466 | + "import-widget": "Importar widget", | |
467 | + "widget-file": "Archivo de widget", | |
468 | + "invalid-widget-file-error": "Imposible importar widget: Estructura de datos inválida.", | |
469 | + "widget-import-missing-aliases-title": "Configurar alias utilizados por el widget", | |
470 | + "open-toolbar": "Abrir toolbar del panel", | |
471 | + "close-toolbar": "Cerrar toolbar", | |
472 | + "configuration-error": "Error de configuración", | |
473 | + "alias-resolution-error-title": "Error de configuración de alias del panel", | |
474 | + "invalid-aliases-config": "No se puede encontrar ningún dispositivo que coincida con algunos de los alias de filtro.<br/>" + | |
475 | + "Póngase en contacto con su administrador para resolver este problema.", | |
476 | + "select-devices": "Seleccionar dispositivos", | |
477 | + "assignedToCustomer": "Asignado al cliente", | |
478 | + "public": "Público", | |
479 | + "public-link": "Link público", | |
480 | + "copy-public-link": "Copiar link público", | |
481 | + "public-link-copied-message": "El link público del panel se ha copiado al portapapeles" | |
292 | 482 | }, |
293 | 483 | "datakey": { |
294 | - "settings": "Ajustes", | |
295 | - "advanced": "Avanzado", | |
296 | - "label": "Etiqueta", | |
297 | - "color": "Color", | |
298 | - "data-generation-func": "Función de generación de datos", | |
299 | - "use-data-post-processing-func": "Usar funcíon de post-procesamiendo de datos", | |
300 | - "configuration": "Ajustes de clave de datos", | |
301 | - "timeseries": "Serie de tiempos", | |
302 | - "attributes": "Atributos", | |
303 | - "timeseries-required": "Series de tiempo del dispositivo requerido.", | |
304 | - "timeseries-or-attributes-required": "Series de tiempo/Atributos requeridos.", | |
305 | - "function-types": "Tipos de funciones", | |
306 | - "function-types-required": "Tipos de funciones requerido." | |
484 | + "settings": "Ajustes", | |
485 | + "advanced": "Avanzado", | |
486 | + "label": "Etiqueta", | |
487 | + "color": "Color", | |
488 | + "data-generation-func": "Función de generación de datos", | |
489 | + "use-data-post-processing-func": "Usar funcíon de post-procesamiendo de datos", | |
490 | + "configuration": "Ajustes de clave de datos", | |
491 | + "timeseries": "Serie de tiempos", | |
492 | + "attributes": "Atributos", | |
493 | + "timeseries-required": "Series de tiempo del dispositivo requerido.", | |
494 | + "timeseries-or-attributes-required": "Series de tiempo/Atributos requeridos.", | |
495 | + "function-types": "Tipos de funciones", | |
496 | + "function-types-required": "Tipos de funciones requerido." | |
307 | 497 | }, |
308 | 498 | "datasource": { |
309 | - "type": "Típo de fuente de datos", | |
310 | - "add-datasource-prompt": "Por favor, agrega una fuente de datos" | |
499 | + "type": "Típo de fuente de datos", | |
500 | + "add-datasource-prompt": "Por favor, agrega una fuente de datos" | |
311 | 501 | }, |
312 | 502 | "details": { |
313 | - "edit-mode": "Modo Edición", | |
314 | - "toggle-edit-mode": "Ir a Modo Edición" | |
503 | + "edit-mode": "Modo Edición", | |
504 | + "toggle-edit-mode": "Ir a Modo Edición" | |
315 | 505 | }, |
316 | 506 | "device": { |
317 | - "device": "Dispositivo", | |
318 | - "device-required": "Dispositivo requerido.", | |
319 | - "devices": "Dispositivos", | |
320 | - "management": "Gestión de Dispositivos", | |
321 | - "view-devices": "Ver dispositivos", | |
322 | - "device-alias": "Alias de dispositivo", | |
323 | - "aliases": "Alias de dispositivos", | |
324 | - "no-alias-matching": "'{{alias}}' no encontrado.", | |
325 | - "no-aliases-found": "Ningún alias encontrado.", | |
326 | - "no-key-matching": "'{{key}}' no encontrado.", | |
327 | - "no-keys-found": "Ninguna clave encontrada.", | |
328 | - "create-new-alias": "Crear nuevo alias!", | |
329 | - "create-new-key": "Crear nueva clave!", | |
330 | - "duplicate-alias-error": "Alias duplicado '{{alias}}'.<br> El alias de los dispositivos deben ser únicos dentro del panel.", | |
331 | - "configure-alias": "Configurar alias '{{alias}}'", | |
332 | - "no-devices-matching": "No se encontró dispositivo '{{entity}}'", | |
333 | - "alias": "Alias", | |
334 | - "alias-required": "Alias de dispositivo requerido.", | |
335 | - "remove-alias": "Eliminar alias", | |
336 | - "add-alias": "Agregar alias", | |
337 | - "name-starts-with": "Nombre empieza con", | |
338 | - "device-list": "Lista de dispositivos", | |
339 | - "use-device-name-filter": "Usar filtro", | |
340 | - "device-list-empty": "Ningún dispositivo seleccionado.", | |
341 | - "device-name-filter-required": "Nombre de filtro requerido.", | |
342 | - "device-name-filter-no-device-matched": "Ningún dispositivo encontrado que comience con '{{device}}'.", | |
343 | - "add": "Agregar dispositivo", | |
344 | - "assign-to-customer": "Asignar a cliente", | |
345 | - "assign-device-to-customer": "Asignar dispositivo(s) a Cliente", | |
346 | - "assign-device-to-customer-text": "Por favor, seleccione los dispositivos que serán asignados al cliente", | |
347 | - "make-public": "Hacer dispositivo público", | |
348 | - "make-private": "Hacer dispositivo privado", | |
349 | - "no-devices-text": "Ningún dispositivo encontrado", | |
350 | - "assign-to-customer-text": "Por favor, seleccione el cliente para asignar el(los) dispositivo(s)", | |
351 | - "device-details": "Detalles del dispositivo", | |
352 | - "add-device-text": "Agregar nuevo dispositivo", | |
353 | - "credentials": "Credenciales", | |
354 | - "manage-credentials": "Gestionar credenciales", | |
355 | - "delete": "Eliminar dispositivo", | |
356 | - "assign-devices": "Asignar dispositivo", | |
357 | - "assign-devices-text": "Asignar { count, select, 1 {1 dispositivo} other {# dispositivos} } al cliente", | |
358 | - "delete-devices": "Eliminar dispositivo", | |
359 | - "unassign-from-customer": "Desasignar del cliente", | |
360 | - "unassign-devices": "Desasignar dispositivos", | |
361 | - "unassign-devices-action-title": "Desasignar { count, select, 1 {1 dispositivo} other {# dispositivos} } del cliente", | |
362 | - "assign-new-device": "Asignar nuevo dispositivo", | |
363 | - "make-public-device-title": "¿Estás seguro que quieres hacer el dispositivo '{{deviceName}}' público?", | |
364 | - "make-public-device-text": "Luego de confirmar, el dispositivo y la información relacionada serán públicos y podrá ser accesible por otros.", | |
365 | - "make-private-device-title": "¿Estás seguro que quieres hacer el dispositivo '{{deviceName}}' privado?", | |
366 | - "make-private-device-text": "Luego de confirmar, el dispositivo y la información relacionada serán privados y no podrá ser accesible por otros.", | |
367 | - "view-credentials": "Ver credenciales", | |
368 | - "delete-device-title": "¿Estás seguro que quieres eliminar el dispositivo '{{deviceName}}'?", | |
369 | - "delete-device-text": "Ten cuidado, luego de confirmar los dispositivos serán eliminados y la información relacionada será irrecuperable.", | |
370 | - "delete-devices-title": "¿Estás seguro que quieres eliminar { count, select, 1 {1 dispositivo} other {# dispositivos} }?", | |
371 | - "delete-devices-action-title": "Eliminar { count, select, 1 {1 dispositivo} other {# dispositivos} }", | |
372 | - "delete-devices-text": "Ten cuidado, luego de confirmar los dispositivos seleccionados serán eliminados y la información relacionada será irrecuperable.", | |
373 | - "unassign-device-title": "¿Estás seguro que quieres desasignar el dispositivo '{{deviceName}}'?", | |
374 | - "unassign-device-text": "Luego de confirmar el dispositivo será desasignado y no podrá ser accesible por el cliente.", | |
375 | - "unassign-device": "Desasignar dispositivo", | |
376 | - "unassign-devices-title": "¿Estás seguro que quieres desasignar { count, select, 1 {1 dispositivo} other {# dispositivos} }?", | |
377 | - "unassign-devices-text": "Luego de confirmar los dispositivos seleccionados serán desasignados y no podrán ser accedidos por el cliente.", | |
378 | - "device-credentials": "Credenciales del dispositivo", | |
379 | - "credentials-type": "Tipo de credencial", | |
380 | - "access-token": "Access token", | |
381 | - "access-token-required": "Access token requerido.", | |
382 | - "access-token-invalid": "Access token debe tener entre 1 a 20 caracteres.", | |
383 | - "rsa-key": "Clave pública RSA", | |
384 | - "rsa-key-required": "Clave pública RSA requerida.", | |
385 | - "secret": "Secreta", | |
386 | - "secret-required": "Secreta requerida.", | |
387 | - "name": "Nombre", | |
388 | - "name-required": "Nombre requerido.", | |
389 | - "description": "Descripción", | |
390 | - "events": "Eventos", | |
391 | - "details": "Detalles", | |
392 | - "copyId": "Copiar ID", | |
393 | - "copyAccessToken": "Copiar access token", | |
394 | - "idCopiedMessage": "Id del dispositivo copiado al portapapeles", | |
395 | - "accessTokenCopiedMessage": "Access token del dispositivo copiado al portapapeles", | |
396 | - "assignedToCustomer": "Asignado al cliente", | |
397 | - "unable-delete-device-alias-title": "Imposible eliminar alias del dispositivo", | |
398 | - "unable-delete-device-alias-text": "Alias '{{deviceAlias}}' no puede ser eliminado. Esta siendo usado por el(los) widget(s):<br/>{{widgetsList}}", | |
399 | - "is-gateway": "Es gateway", | |
400 | - "public": "Público", | |
401 | - "device-public": "Dispositivo público" | |
507 | + "device": "Dispositivo", | |
508 | + "device-required": "Dispositivo requerido.", | |
509 | + "devices": "Dispositivos", | |
510 | + "management": "Gestión de Dispositivos", | |
511 | + "view-devices": "Ver dispositivos", | |
512 | + "device-alias": "Alias de dispositivo", | |
513 | + "aliases": "Alias de dispositivos", | |
514 | + "no-alias-matching": "'{{alias}}' no encontrado.", | |
515 | + "no-aliases-found": "Ningún alias encontrado.", | |
516 | + "no-key-matching": "'{{key}}' no encontrado.", | |
517 | + "no-keys-found": "Ninguna clave encontrada.", | |
518 | + "create-new-alias": "Crear nuevo alias!", | |
519 | + "create-new-key": "Crear nueva clave!", | |
520 | + "duplicate-alias-error": "Alias duplicado '{{alias}}'.<br> El alias de los dispositivos deben ser únicos dentro del panel.", | |
521 | + "configure-alias": "Configurar alias '{{alias}}'", | |
522 | + "no-devices-matching": "No se encontró dispositivo '{{entity}}'", | |
523 | + "alias": "Alias", | |
524 | + "alias-required": "Alias de dispositivo requerido.", | |
525 | + "remove-alias": "Eliminar alias", | |
526 | + "add-alias": "Agregar alias", | |
527 | + "name-starts-with": "Nombre empieza con", | |
528 | + "device-list": "Lista de dispositivos", | |
529 | + "use-device-name-filter": "Usar filtro", | |
530 | + "device-list-empty": "Ningún dispositivo seleccionado.", | |
531 | + "device-name-filter-required": "Nombre de filtro requerido.", | |
532 | + "device-name-filter-no-device-matched": "Ningún dispositivo encontrado que comience con '{{device}}'.", | |
533 | + "add": "Agregar dispositivo", | |
534 | + "assign-to-customer": "Asignar a cliente", | |
535 | + "assign-device-to-customer": "Asignar dispositivo(s) a Cliente", | |
536 | + "assign-device-to-customer-text": "Por favor, seleccione los dispositivos que serán asignados al cliente", | |
537 | + "make-public": "Hacer dispositivo público", | |
538 | + "make-private": "Hacer dispositivo privado", | |
539 | + "no-devices-text": "Ningún dispositivo encontrado", | |
540 | + "assign-to-customer-text": "Por favor, seleccione el cliente para asignar el(los) dispositivo(s)", | |
541 | + "device-details": "Detalles del dispositivo", | |
542 | + "add-device-text": "Agregar nuevo dispositivo", | |
543 | + "credentials": "Credenciales", | |
544 | + "manage-credentials": "Gestionar credenciales", | |
545 | + "delete": "Eliminar dispositivo", | |
546 | + "assign-devices": "Asignar dispositivo", | |
547 | + "assign-devices-text": "Asignar { count, select, 1 {1 dispositivo} other {# dispositivos} } al cliente", | |
548 | + "delete-devices": "Eliminar dispositivo", | |
549 | + "unassign-from-customer": "Desasignar del cliente", | |
550 | + "unassign-devices": "Desasignar dispositivos", | |
551 | + "unassign-devices-action-title": "Desasignar { count, select, 1 {1 dispositivo} other {# dispositivos} } del cliente", | |
552 | + "assign-new-device": "Asignar nuevo dispositivo", | |
553 | + "make-public-device-title": "¿Estás seguro que quieres hacer el dispositivo '{{deviceName}}' público?", | |
554 | + "make-public-device-text": "Luego de confirmar, el dispositivo y la información relacionada serán públicos y podrá ser accesible por otros.", | |
555 | + "make-private-device-title": "¿Estás seguro que quieres hacer el dispositivo '{{deviceName}}' privado?", | |
556 | + "make-private-device-text": "Luego de confirmar, el dispositivo y la información relacionada serán privados y no podrá ser accesible por otros.", | |
557 | + "view-credentials": "Ver credenciales", | |
558 | + "delete-device-title": "¿Estás seguro que quieres eliminar el dispositivo '{{deviceName}}'?", | |
559 | + "delete-device-text": "Ten cuidado, luego de confirmar los dispositivos serán eliminados y la información relacionada será irrecuperable.", | |
560 | + "delete-devices-title": "¿Estás seguro que quieres eliminar { count, select, 1 {1 dispositivo} other {# dispositivos} }?", | |
561 | + "delete-devices-action-title": "Eliminar { count, select, 1 {1 dispositivo} other {# dispositivos} }", | |
562 | + "delete-devices-text": "Ten cuidado, luego de confirmar los dispositivos seleccionados serán eliminados y la información relacionada será irrecuperable.", | |
563 | + "unassign-device-title": "¿Estás seguro que quieres desasignar el dispositivo '{{deviceName}}'?", | |
564 | + "unassign-device-text": "Luego de confirmar el dispositivo será desasignado y no podrá ser accesible por el cliente.", | |
565 | + "unassign-device": "Desasignar dispositivo", | |
566 | + "unassign-devices-title": "¿Estás seguro que quieres desasignar { count, select, 1 {1 dispositivo} other {# dispositivos} }?", | |
567 | + "unassign-devices-text": "Luego de confirmar los dispositivos seleccionados serán desasignados y no podrán ser accedidos por el cliente.", | |
568 | + "device-credentials": "Credenciales del dispositivo", | |
569 | + "credentials-type": "Tipo de credencial", | |
570 | + "access-token": "Access token", | |
571 | + "access-token-required": "Access token requerido.", | |
572 | + "access-token-invalid": "Access token debe tener entre 1 a 20 caracteres.", | |
573 | + "rsa-key": "Clave pública RSA", | |
574 | + "rsa-key-required": "Clave pública RSA requerida.", | |
575 | + "secret": "Secreta", | |
576 | + "secret-required": "Secreta requerida.", | |
577 | + "name": "Nombre", | |
578 | + "name-required": "Nombre requerido.", | |
579 | + "description": "Descripción", | |
580 | + "events": "Eventos", | |
581 | + "details": "Detalles", | |
582 | + "copyId": "Copiar ID", | |
583 | + "copyAccessToken": "Copiar access token", | |
584 | + "idCopiedMessage": "Id del dispositivo copiado al portapapeles", | |
585 | + "accessTokenCopiedMessage": "Access token del dispositivo copiado al portapapeles", | |
586 | + "assignedToCustomer": "Asignado al cliente", | |
587 | + "unable-delete-device-alias-title": "Imposible eliminar alias del dispositivo", | |
588 | + "unable-delete-device-alias-text": "Alias '{{deviceAlias}}' no puede ser eliminado. Esta siendo usado por el(los) widget(s):<br/>{{widgetsList}}", | |
589 | + "is-gateway": "Es gateway", | |
590 | + "public": "Público", | |
591 | + "device-public": "Dispositivo público" | |
402 | 592 | }, |
403 | 593 | "dialog": { |
404 | - "close": "Cerrar cuadro de diálogo" | |
594 | + "close": "Cerrar cuadro de diálogo" | |
405 | 595 | }, |
406 | 596 | "error": { |
407 | - "unable-to-connect": "Imposible conectar con el servidor! Por favor, revise su conexión a internet.", | |
408 | - "unhandled-error-code": "Código de error no manejado: {{errorCode}}", | |
409 | - "unknown-error": "Error desconocido" | |
597 | + "unable-to-connect": "Imposible conectar con el servidor! Por favor, revise su conexión a internet.", | |
598 | + "unhandled-error-code": "Código de error no manejado: {{errorCode}}", | |
599 | + "unknown-error": "Error desconocido" | |
600 | + }, | |
601 | + "entity": { // TODO | |
602 | + "entity": "Entity", | |
603 | + "entities": "Entities", | |
604 | + "aliases": "Entity aliases", | |
605 | + "entity-alias": "Entity alias", | |
606 | + "unable-delete-entity-alias-title": "Unable to delete entity alias", | |
607 | + "unable-delete-entity-alias-text": "Entity alias '{{entityAlias}}' can't be deleted as it used by the following widget(s):<br/>{{widgetsList}}", | |
608 | + "duplicate-alias-error": "Duplicate alias found '{{alias}}'.<br>Entity aliases must be unique whithin the dashboard.", | |
609 | + "missing-entity-filter-error": "Filter is missing for alias '{{alias}}'.", | |
610 | + "configure-alias": "Configure '{{alias}}' alias", | |
611 | + "alias": "Alias", | |
612 | + "alias-required": "Entity alias is required.", | |
613 | + "remove-alias": "Remove entity alias", | |
614 | + "add-alias": "Add entity alias", | |
615 | + "entity-list": "Entity list", | |
616 | + "entity-type": "Entity type", | |
617 | + "entity-types": "Entity types", | |
618 | + "entity-type-list": "Entity type list", | |
619 | + "any-entity": "Any entity", | |
620 | + "enter-entity-type": "Enter entity type", | |
621 | + "no-entities-matching": "No entities matching '{{entity}}' were found.", | |
622 | + "no-entity-types-matching": "No entity types matching '{{entityType}}' were found.", | |
623 | + "name-starts-with": "Name starts with", | |
624 | + "use-entity-name-filter": "Use filter", | |
625 | + "entity-list-empty": "No entities selected.", | |
626 | + "entity-type-list-empty": "No entity types selected.", | |
627 | + "entity-name-filter-required": "Entity name filter is required.", | |
628 | + "entity-name-filter-no-entity-matched": "No entities starting with '{{entity}}' were found.", | |
629 | + "all-subtypes": "All", | |
630 | + "select-entities": "Select entities", | |
631 | + "no-aliases-found": "No aliases found.", | |
632 | + "no-alias-matching": "'{{alias}}' not found.", | |
633 | + "create-new-alias": "Create a new one!", | |
634 | + "key": "Key", | |
635 | + "key-name": "Key name", | |
636 | + "no-keys-found": "No keys found.", | |
637 | + "no-key-matching": "'{{key}}' not found.", | |
638 | + "create-new-key": "Create a new one!", | |
639 | + "type": "Type", | |
640 | + "type-required": "Entity type is required.", | |
641 | + "type-device": "Device", | |
642 | + "type-devices": "Devices", | |
643 | + "list-of-devices": "{ count, select, 1 {One device} other {List of # devices} }", | |
644 | + "device-name-starts-with": "Devices whose names start with '{{prefix}}'", | |
645 | + "type-asset": "Asset", | |
646 | + "type-assets": "Assets", | |
647 | + "list-of-assets": "{ count, select, 1 {One asset} other {List of # assets} }", | |
648 | + "asset-name-starts-with": "Assets whose names start with '{{prefix}}'", | |
649 | + "type-rule": "Rule", | |
650 | + "type-rules": "Rules", | |
651 | + "list-of-rules": "{ count, select, 1 {One rule} other {List of # rules} }", | |
652 | + "rule-name-starts-with": "Rules whose names start with '{{prefix}}'", | |
653 | + "type-plugin": "Plugin", | |
654 | + "type-plugins": "Plugins", | |
655 | + "list-of-plugins": "{ count, select, 1 {One plugin} other {List of # plugins} }", | |
656 | + "plugin-name-starts-with": "Plugins whose names start with '{{prefix}}'", | |
657 | + "type-tenant": "Tenant", | |
658 | + "type-tenants": "Tenants", | |
659 | + "list-of-tenants": "{ count, select, 1 {One tenant} other {List of # tenants} }", | |
660 | + "tenant-name-starts-with": "Tenants whose names start with '{{prefix}}'", | |
661 | + "type-customer": "Customer", | |
662 | + "type-customers": "Customers", | |
663 | + "list-of-customers": "{ count, select, 1 {One customer} other {List of # customers} }", | |
664 | + "customer-name-starts-with": "Customers whose names start with '{{prefix}}'", | |
665 | + "type-user": "User", | |
666 | + "type-users": "Users", | |
667 | + "list-of-users": "{ count, select, 1 {One user} other {List of # users} }", | |
668 | + "user-name-starts-with": "Users whose names start with '{{prefix}}'", | |
669 | + "type-dashboard": "Dashboard", | |
670 | + "type-dashboards": "Dashboards", | |
671 | + "list-of-dashboards": "{ count, select, 1 {One dashboard} other {List of # dashboards} }", | |
672 | + "dashboard-name-starts-with": "Dashboards whose names start with '{{prefix}}'", | |
673 | + "type-alarm": "Alarm", | |
674 | + "type-alarms": "Alarms", | |
675 | + "list-of-alarms": "{ count, select, 1 {One alarms} other {List of # alarms} }", | |
676 | + "alarm-name-starts-with": "Alarms whose names start with '{{prefix}}'", | |
677 | + "type-rulechain": "Rule chain", | |
678 | + "type-rulechains": "Rule chains", | |
679 | + "list-of-rulechains": "{ count, select, 1 {One rule chain} other {List of # rule chains} }", | |
680 | + "rulechain-name-starts-with": "Rule chains whose names start with '{{prefix}}'", | |
681 | + "type-current-customer": "Current Customer", | |
682 | + "search": "Search entities", | |
683 | + "selected-entities": "{ count, select, 1 {1 entity} other {# entities} } selected", | |
684 | + "entity-name": "Entity name", | |
685 | + "details": "Entity details", | |
686 | + "no-entities-prompt": "No entities found", | |
687 | + "no-data": "No data to display" | |
410 | 688 | }, |
411 | 689 | "event": { |
412 | - "event-type": "Tipo de evento", | |
413 | - "type-error": "Error", | |
414 | - "type-lc-event": "Ciclo de vida", | |
415 | - "type-stats": "Estadísticas", | |
416 | - "no-events-prompt": "Ningún evento encontrado.", | |
417 | - "error": "Error", | |
418 | - "alarm": "Alarma", | |
419 | - "event-time": "Hora del evento", | |
420 | - "server": "Servidor", | |
421 | - "body": "Cuerpo", | |
422 | - "method": "Método", | |
423 | - "event": "Evento", | |
424 | - "status": "Status", | |
425 | - "success": "Éxito", | |
426 | - "failed": "Fallo", | |
427 | - "messages-processed": "Mensajes procesados", | |
428 | - "errors-occurred": "Ocurrieron errores" | |
690 | + "event-type": "Tipo de evento", | |
691 | + "type-error": "Error", | |
692 | + "type-lc-event": "Ciclo de vida", | |
693 | + "type-stats": "Estadísticas", | |
694 | + "no-events-prompt": "Ningún evento encontrado.", | |
695 | + "error": "Error", | |
696 | + "alarm": "Alarma", | |
697 | + "event-time": "Hora del evento", | |
698 | + "server": "Servidor", | |
699 | + "body": "Cuerpo", | |
700 | + "method": "Método", | |
701 | + "event": "Evento", | |
702 | + "status": "Status", | |
703 | + "success": "Éxito", | |
704 | + "failed": "Fallo", | |
705 | + "messages-processed": "Mensajes procesados", | |
706 | + "errors-occurred": "Ocurrieron errores" | |
707 | + }, | |
708 | + "extension": { // TODO | |
709 | + "extensions": "Extensions", | |
710 | + "selected-extensions": "{ count, select, 1 {1 extension} other {# extensions} } selected", | |
711 | + "type": "Type", | |
712 | + "key": "Key", | |
713 | + "value": "Value", | |
714 | + "id": "Id", | |
715 | + "extension-id": "Extension id", | |
716 | + "extension-type": "Extension type", | |
717 | + "transformer-json": "JSON *", | |
718 | + "unique-id-required": "Current extension id already exists.", | |
719 | + "delete": "Delete extension", | |
720 | + "add": "Add extension", | |
721 | + "edit": "Edit extension", | |
722 | + "delete-extension-title": "Are you sure you want to delete the extension '{{extensionId}}'?", | |
723 | + "delete-extension-text": "Be careful, after the confirmation the extension and all related data will become unrecoverable.", | |
724 | + "delete-extensions-title": "Are you sure you want to delete { count, select, 1 {1 extension} other {# extensions} }?", | |
725 | + "delete-extensions-text": "Be careful, after the confirmation all selected extensions will be removed.", | |
726 | + "converters": "Converters", | |
727 | + "converter-id": "Converter id", | |
728 | + "configuration": "Configuration", | |
729 | + "converter-configurations": "Converter configurations", | |
730 | + "token": "Security token", | |
731 | + "add-converter": "Add converter", | |
732 | + "add-config": "Add converter configuration", | |
733 | + "device-name-expression": "Device name expression", | |
734 | + "device-type-expression": "Device type expression", | |
735 | + "custom": "Custom", | |
736 | + "to-double": "To Double", | |
737 | + "transformer": "Transformer", | |
738 | + "json-required": "Transformer json is required.", | |
739 | + "json-parse": "Unable to parse transformer json.", | |
740 | + "attributes": "Attributes", | |
741 | + "add-attribute": "Add attribute", | |
742 | + "add-map": "Add mapping element", | |
743 | + "timeseries": "Timeseries", | |
744 | + "add-timeseries": "Add timeseries", | |
745 | + "field-required": "Field is required", | |
746 | + "brokers": "Brokers", | |
747 | + "add-broker": "Add broker", | |
748 | + "host": "Host", | |
749 | + "port": "Port", | |
750 | + "port-range": "Port should be in a range from 1 to 65535.", | |
751 | + "ssl": "Ssl", | |
752 | + "credentials": "Credentials", | |
753 | + "username": "Username", | |
754 | + "password": "Password", | |
755 | + "retry-interval": "Retry interval in milliseconds", | |
756 | + "anonymous": "Anonymous", | |
757 | + "basic": "Basic", | |
758 | + "pem": "PEM", | |
759 | + "ca-cert": "CA certificate file *", | |
760 | + "private-key": "Private key file *", | |
761 | + "cert": "Certificate file *", | |
762 | + "no-file": "No file selected.", | |
763 | + "drop-file": "Drop a file or click to select a file to upload.", | |
764 | + "mapping": "Mapping", | |
765 | + "topic-filter": "Topic filter", | |
766 | + "converter-type": "Converter type", | |
767 | + "converter-json": "Json", | |
768 | + "json-name-expression": "Device name json expression", | |
769 | + "topic-name-expression": "Device name topic expression", | |
770 | + "json-type-expression": "Device type json expression", | |
771 | + "topic-type-expression": "Device type topic expression", | |
772 | + "attribute-key-expression": "Attribute key expression", | |
773 | + "attr-json-key-expression": "Attribute key json expression", | |
774 | + "attr-topic-key-expression": "Attribute key topic expression", | |
775 | + "request-id-expression": "Request id expression", | |
776 | + "request-id-json-expression": "Request id json expression", | |
777 | + "request-id-topic-expression": "Request id topic expression", | |
778 | + "response-topic-expression": "Response topic expression", | |
779 | + "value-expression": "Value expression", | |
780 | + "topic": "Topic", | |
781 | + "timeout": "Timeout in milliseconds", | |
782 | + "converter-json-required": "Converter json is required.", | |
783 | + "converter-json-parse": "Unable to parse converter json.", | |
784 | + "filter-expression": "Filter expression", | |
785 | + "connect-requests": "Connect requests", | |
786 | + "add-connect-request": "Add connect request", | |
787 | + "disconnect-requests": "Disconnect requests", | |
788 | + "add-disconnect-request": "Add disconnect request", | |
789 | + "attribute-requests": "Attribute requests", | |
790 | + "add-attribute-request": "Add attribute request", | |
791 | + "attribute-updates": "Attribute updates", | |
792 | + "add-attribute-update": "Add attribute update", | |
793 | + "server-side-rpc": "Server side RPC", | |
794 | + "add-server-side-rpc-request": "Add server-side RPC request", | |
795 | + "device-name-filter": "Device name filter", | |
796 | + "attribute-filter": "Attribute filter", | |
797 | + "method-filter": "Method filter", | |
798 | + "request-topic-expression": "Request topic expression", | |
799 | + "response-timeout": "Response timeout in milliseconds", | |
800 | + "topic-expression": "Topic expression", | |
801 | + "client-scope": "Client scope", | |
802 | + "add-device": "Add device", | |
803 | + "opc-server": "Servers", | |
804 | + "opc-add-server": "Add server", | |
805 | + "opc-add-server-prompt": "Please add server", | |
806 | + "opc-application-name": "Application name", | |
807 | + "opc-application-uri": "Application uri", | |
808 | + "opc-scan-period-in-seconds": "Scan period in seconds", | |
809 | + "opc-security": "Security", | |
810 | + "opc-identity": "Identity", | |
811 | + "opc-keystore": "Keystore", | |
812 | + "opc-type": "Type", | |
813 | + "opc-keystore-type": "Type", | |
814 | + "opc-keystore-location": "Location *", | |
815 | + "opc-keystore-password": "Password", | |
816 | + "opc-keystore-alias": "Alias", | |
817 | + "opc-keystore-key-password": "Key password", | |
818 | + "opc-device-node-pattern": "Device node pattern", | |
819 | + "opc-device-name-pattern": "Device name pattern", | |
820 | + "modbus-server": "Servers/slaves", | |
821 | + "modbus-add-server": "Add server/slave", | |
822 | + "modbus-add-server-prompt": "Please add server/slave", | |
823 | + "modbus-transport": "Transport", | |
824 | + "modbus-port-name": "Serial port name", | |
825 | + "modbus-encoding": "Encoding", | |
826 | + "modbus-parity": "Parity", | |
827 | + "modbus-baudrate": "Baud rate", | |
828 | + "modbus-databits": "Data bits", | |
829 | + "modbus-stopbits": "Stop bits", | |
830 | + "modbus-databits-range": "Data bits should be in a range from 7 to 8.", | |
831 | + "modbus-stopbits-range": "Stop bits should be in a range from 1 to 2.", | |
832 | + "modbus-unit-id": "Unit ID", | |
833 | + "modbus-unit-id-range": "Unit ID should be in a range from 1 to 247.", | |
834 | + "modbus-device-name": "Device name", | |
835 | + "modbus-poll-period": "Poll period (ms)", | |
836 | + "modbus-attributes-poll-period": "Attributes poll period (ms)", | |
837 | + "modbus-timeseries-poll-period": "Timeseries poll period (ms)", | |
838 | + "modbus-poll-period-range": "Poll period should be positive value.", | |
839 | + "modbus-tag": "Tag", | |
840 | + "modbus-function": "Function", | |
841 | + "modbus-register-address": "Register address", | |
842 | + "modbus-register-address-range": "Register address should be in a range from 0 to 65535.", | |
843 | + "modbus-register-bit-index": "Bit index", | |
844 | + "modbus-register-bit-index-range": "Bit index should be in a range from 0 to 15.", | |
845 | + "modbus-register-count": "Register count", | |
846 | + "modbus-register-count-range": "Register count should be a positive value.", | |
847 | + "modbus-byte-order": "Byte order", | |
848 | + | |
849 | + "sync": { | |
850 | + "status": "Status", | |
851 | + "sync": "Sync", | |
852 | + "not-sync": "Not sync", | |
853 | + "last-sync-time": "Last sync time", | |
854 | + "not-available": "Not available" | |
855 | + }, | |
856 | + | |
857 | + "export-extensions-configuration": "Export extensions configuration", | |
858 | + "import-extensions-configuration": "Import extensions configuration", | |
859 | + "import-extensions": "Import extensions", | |
860 | + "import-extension": "Import extension", | |
861 | + "export-extension": "Export extension", | |
862 | + "file": "Extensions file", | |
863 | + "invalid-file-error": "Invalid extension file" | |
429 | 864 | }, |
430 | 865 | "fullscreen": { |
431 | - "expand": "Expandir a Pantalla Completa", | |
432 | - "exit": "Salir de Pantalla Completa", | |
433 | - "toggle": "Cambiar el modo de Pantalla Completa", | |
434 | - "fullscreen": "Pantalla Completa" | |
866 | + "expand": "Expandir a Pantalla Completa", | |
867 | + "exit": "Salir de Pantalla Completa", | |
868 | + "toggle": "Cambiar el modo de Pantalla Completa", | |
869 | + "fullscreen": "Pantalla Completa" | |
435 | 870 | }, |
436 | 871 | "function": { |
437 | - "function": "Función" | |
872 | + "function": "Función" | |
438 | 873 | }, |
439 | 874 | "grid": { |
440 | - "delete-item-title": "¿Estás seguro que quieres eliminar este item?", | |
441 | - "delete-item-text": "Ten cuidado, luego de confirmar el item será eliminado y la información relacionada será irrecuperable.", | |
442 | - "delete-items-title": "¿Estás seguro que quieres eliminar { count, select, 1 {1 item} other {# items} }?", | |
443 | - "delete-items-action-title": "Eliminar { count, select, 1 {1 item} other {# items} }", | |
444 | - "delete-items-text": "Ten cuidado, luego de confirmar los items seleccionados serán eliminados y la información relacionada será irrecuperable.", | |
445 | - "add-item-text": "Agregar nuevo item", | |
446 | - "no-items-text": "Ningún item encontrado", | |
447 | - "item-details": "Detalles del item", | |
448 | - "delete-item": "Borrar Item", | |
449 | - "delete-items": "Borrar Items", | |
450 | - "scroll-to-top": "Ir hacia arriba" | |
875 | + "delete-item-title": "¿Estás seguro que quieres eliminar este item?", | |
876 | + "delete-item-text": "Ten cuidado, luego de confirmar el item será eliminado y la información relacionada será irrecuperable.", | |
877 | + "delete-items-title": "¿Estás seguro que quieres eliminar { count, select, 1 {1 item} other {# items} }?", | |
878 | + "delete-items-action-title": "Eliminar { count, select, 1 {1 item} other {# items} }", | |
879 | + "delete-items-text": "Ten cuidado, luego de confirmar los items seleccionados serán eliminados y la información relacionada será irrecuperable.", | |
880 | + "add-item-text": "Agregar nuevo item", | |
881 | + "no-items-text": "Ningún item encontrado", | |
882 | + "item-details": "Detalles del item", | |
883 | + "delete-item": "Borrar Item", | |
884 | + "delete-items": "Borrar Items", | |
885 | + "scroll-to-top": "Ir hacia arriba" | |
451 | 886 | }, |
452 | 887 | "help": { |
453 | - "goto-help-page": "Ir a Página de Ayuda" | |
888 | + "goto-help-page": "Ir a Página de Ayuda" | |
454 | 889 | }, |
455 | 890 | "home": { |
456 | - "home": "Principal", | |
457 | - "profile": "Perfil", | |
458 | - "logout": "Salir", | |
459 | - "menu": "Menu", | |
460 | - "avatar": "Avatar", | |
461 | - "open-user-menu": "Abrir menú de usuario" | |
891 | + "home": "Principal", | |
892 | + "profile": "Perfil", | |
893 | + "logout": "Salir", | |
894 | + "menu": "Menu", | |
895 | + "avatar": "Avatar", | |
896 | + "open-user-menu": "Abrir menú de usuario" | |
462 | 897 | }, |
463 | 898 | "import": { |
464 | - "no-file": "Ningún archivo seleccionado", | |
465 | - "drop-file": "Arrastra un archivo JSON o clickea para seleccionar uno." | |
899 | + "no-file": "Ningún archivo seleccionado", | |
900 | + "drop-file": "Arrastra un archivo JSON o clickea para seleccionar uno." | |
466 | 901 | }, |
467 | 902 | "item": { |
468 | - "selected": "Seleccionado" | |
903 | + "selected": "Seleccionado" | |
469 | 904 | }, |
470 | 905 | "js-func": { |
471 | - "no-return-error": "La función debe retornar un valor!", | |
472 | - "return-type-mismatch": "La función debe retornar un valor de tipo: '{{type}}'!" | |
906 | + "no-return-error": "La función debe retornar un valor!", | |
907 | + "return-type-mismatch": "La función debe retornar un valor de tipo: '{{type}}'!" | |
908 | + }, | |
909 | + "key-val": { // TODO | |
910 | + "key": "Key", | |
911 | + "value": "Value", | |
912 | + "remove-entry": "Remove entry", | |
913 | + "add-entry": "Add entry", | |
914 | + "no-data": "No entries" | |
915 | + }, | |
916 | + "layout": { // TODO | |
917 | + "layout": "Layout", | |
918 | + "manage": "Manage layouts", | |
919 | + "settings": "Layout settings", | |
920 | + "color": "Color", | |
921 | + "main": "Main", | |
922 | + "right": "Right", | |
923 | + "select": "Select target layout" | |
473 | 924 | }, |
474 | 925 | "legend": { |
475 | - "position": "Posición de leyenda", | |
476 | - "show-max": "Mostrar máximo", | |
477 | - "show-min": "Mostrar mínimo", | |
478 | - "show-avg": "Mostrar promedio", | |
479 | - "show-total": "Mostrar total", | |
480 | - "settings": "Ajustes de leyenda.", | |
481 | - "min": "min", | |
482 | - "max": "max", | |
483 | - "avg": "prom", | |
484 | - "total": "total" | |
926 | + "position": "Posición de leyenda", | |
927 | + "show-max": "Mostrar máximo", | |
928 | + "show-min": "Mostrar mínimo", | |
929 | + "show-avg": "Mostrar promedio", | |
930 | + "show-total": "Mostrar total", | |
931 | + "settings": "Ajustes de leyenda.", | |
932 | + "min": "min", | |
933 | + "max": "max", | |
934 | + "avg": "prom", | |
935 | + "total": "total" | |
485 | 936 | }, |
486 | 937 | "login": { |
487 | - "login": "Ingresar", | |
488 | - "request-password-reset": "Pedir restablecer contraseña", | |
489 | - "reset-password": "Restablecer contraseña", | |
490 | - "create-password": "Crear contraseña", | |
491 | - "passwords-mismatch-error": "Las contraseñas deben ser las mismas!", | |
492 | - "password-again": "Reingresa la contraseña", | |
493 | - "sign-in": "Iniciar sesión", | |
494 | - "username": "Usuario (email)", | |
495 | - "remember-me": "Recordar", | |
496 | - "forgot-password": "¿Olvidaste tu contraseña?", | |
497 | - "password-reset": "Restablecer Contraseña", | |
498 | - "new-password": "Nueva contraseña", | |
499 | - "new-password-again": "Repita la nueva contraseña", | |
500 | - "password-link-sent-message": "Se ha enviado el enlace de restablecimiento de contraseña con éxito!", | |
501 | - "email": "Email" | |
502 | - }, | |
503 | - "plugin": { | |
504 | - "plugins": "Plugins", | |
505 | - "delete": "Eliminar plugin", | |
506 | - "activate": "Activar plugin", | |
507 | - "suspend": "Suspender plugin", | |
508 | - "active": "Activo", | |
509 | - "suspended": "Suspendido", | |
510 | - "name": "Nombre", | |
511 | - "name-required": "Nombre requerido.", | |
512 | - "description": "Descripción", | |
513 | - "add": "Agregar Plugin", | |
514 | - "delete-plugin-title": "¿Estás seguro que quieres eliminar el plugin '{{pluginName}}'?", | |
515 | - "delete-plugin-text": "Ten cuidado, luego de confirmar el plugin será eliminado y la información relacionada será irrecuperable.", | |
516 | - "delete-plugins-title": "¿Estás seguro que quieres eliminar { count, select, 1 {1 plugin} other {# plugins} }?", | |
517 | - "delete-plugins-action-title": "Eliminar { count, select, 1 {1 plugin} other {# plugins} }", | |
518 | - "delete-plugins-text": "Ten cuidado, luego de confirmar todos los plugins seleccionados serán eliminados y la información relacionada será irrecuperable.", | |
519 | - "add-plugin-text": "Agregar nuevo plugin", | |
520 | - "no-plugins-text": "Ningún plugin encontrado", | |
521 | - "plugin-details": "Detalles", | |
522 | - "api-token": "API token", | |
523 | - "api-token-required": "API token requerido.", | |
524 | - "type": "Tipo del plugin", | |
525 | - "type-required": "Tipo requerido.", | |
526 | - "configuration": "Ajustes del plugin", | |
527 | - "system": "Sistema", | |
528 | - "select-plugin": "plugin", | |
529 | - "plugin": "Plugin", | |
530 | - "no-plugins-matching": "No se encontraron plugins: '{{entity}}'", | |
531 | - "plugin-required": "Plugin requerido.", | |
532 | - "plugin-require-match": "Por favor, elija un plugin existente.", | |
533 | - "events": "Eventos", | |
534 | - "details": "Detalles", | |
535 | - "import": "Importar plugin", | |
536 | - "export": "Exportar plugin", | |
537 | - "export-failed-error": "Imposible exportar plugin: {{error}}", | |
538 | - "create-new-plugin": "Crear nuevo plugin", | |
539 | - "plugin-file": "Archivo", | |
540 | - "invalid-plugin-file-error": "Imposible de importar plugin: Estructura de datos inválida." | |
938 | + "login": "Ingresar", | |
939 | + "request-password-reset": "Pedir restablecer contraseña", | |
940 | + "reset-password": "Restablecer contraseña", | |
941 | + "create-password": "Crear contraseña", | |
942 | + "passwords-mismatch-error": "Las contraseñas deben ser las mismas!", | |
943 | + "password-again": "Reingresa la contraseña", | |
944 | + "sign-in": "Iniciar sesión", | |
945 | + "username": "Usuario (email)", | |
946 | + "remember-me": "Recordar", | |
947 | + "forgot-password": "¿Olvidaste tu contraseña?", | |
948 | + "password-reset": "Restablecer Contraseña", | |
949 | + "new-password": "Nueva contraseña", | |
950 | + "new-password-again": "Repita la nueva contraseña", | |
951 | + "password-link-sent-message": "Se ha enviado el enlace de restablecimiento de contraseña con éxito!", | |
952 | + "email": "Email" | |
541 | 953 | }, |
542 | 954 | "position": { |
543 | - "top": "Arriba", | |
544 | - "bottom": "Abajo", | |
545 | - "left": "Izquierda", | |
546 | - "right": "Derecha" | |
955 | + "top": "Arriba", | |
956 | + "bottom": "Abajo", | |
957 | + "left": "Izquierda", | |
958 | + "right": "Derecha" | |
547 | 959 | }, |
548 | 960 | "profile": { |
549 | - "profile": "Perfil", | |
550 | - "change-password": "Cambiar contraseña", | |
551 | - "current-password": "Contraseña actual" | |
552 | - }, | |
553 | - "rule": { | |
554 | - "rules": "Reglas", | |
555 | - "delete": "Eliminar regla", | |
556 | - "activate": "Activar regla", | |
557 | - "suspend": "Suspender regla", | |
558 | - "active": "Activada", | |
559 | - "suspended": "Suspendida", | |
560 | - "name": "Nombre", | |
561 | - "name-required": "Nombre requerido.", | |
562 | - "description": "Descripción", | |
563 | - "add": "Agregar Regla", | |
564 | - "delete-rule-title": "¿Estás seguro que quieres eliminar la regla '{{ruleName}}'?", | |
565 | - "delete-rule-text": "Ten cuidado, luego de confirmar la regla será eliminada y la información relacionada será irrecuperable.", | |
566 | - "delete-rules-title": "¿Estás seguro que quieres eliminar { count, select, 1 {1 regla} other {# reglas} }?", | |
567 | - "delete-rules-action-title": "Eliminar { count, select, 1 {1 regla} other {# reglas} }", | |
568 | - "delete-rules-text": "Ten cuidado, luego de confirmar todas las reglas seleccionadas serán borradas y la información relacionada será irrecuperable.", | |
569 | - "add-rule-text": "Agregar nueva regla", | |
570 | - "no-rules-text": "Ninguna regla encontrada", | |
571 | - "rule-details": "Detalles", | |
572 | - "filters": "Filtros", | |
573 | - "filter": "Filtro", | |
574 | - "add-filter-prompt": "Por favor, ingresa un filtro", | |
575 | - "remove-filter": "Eliminar filtro", | |
576 | - "add-filter": "Agregar filtro", | |
577 | - "filter-name": "Nombre", | |
578 | - "filter-type": "Tipo", | |
579 | - "edit-filter": "Editar filtro", | |
580 | - "view-filter": "Ver filtro", | |
581 | - "component-name": "Nombre", | |
582 | - "component-name-required": "Nombre requerido.", | |
583 | - "component-type": "Tipo", | |
584 | - "component-type-required": "Tipo requerido.", | |
585 | - "processor": "Procesador", | |
586 | - "no-processor-configured": "Ningún procesador encontrado", | |
587 | - "create-processor": "Crear procesador", | |
588 | - "processor-name": "Nombre", | |
589 | - "processor-type": "Tipo", | |
590 | - "plugin-action": "Acción del Plugin", | |
591 | - "action-name": "Nombre", | |
592 | - "action-type": "Tipo", | |
593 | - "create-action-prompt": "Por favor, crea una acción.", | |
594 | - "create-action": "Crear acción", | |
595 | - "details": "Detalles", | |
596 | - "events": "Eventos", | |
597 | - "system": "Sistema", | |
598 | - "import": "Importar regla", | |
599 | - "export": "Exportar regla", | |
600 | - "export-failed-error": "Imposible de exportar regla: {{error}}", | |
601 | - "create-new-rule": "Crear nueva regla", | |
602 | - "rule-file": "Archivo", | |
603 | - "invalid-rule-file-error": "Imposible de importar regla: Estructura de datos inválida." | |
604 | - }, | |
605 | - "rule-plugin": { | |
606 | - "management": "Gestión de Reglas y Plugins" | |
961 | + "profile": "Perfil", | |
962 | + "change-password": "Cambiar contraseña", | |
963 | + "current-password": "Contraseña actual" | |
964 | + }, | |
965 | + "relation": { // TODO | |
966 | + "relations": "Relations", | |
967 | + "direction": "Direction", | |
968 | + "search-direction": { | |
969 | + "FROM": "From", | |
970 | + "TO": "To" | |
971 | + }, | |
972 | + "direction-type": { | |
973 | + "FROM": "from", | |
974 | + "TO": "to" | |
975 | + }, | |
976 | + "from-relations": "Outbound relations", | |
977 | + "to-relations": "Inbound relations", | |
978 | + "selected-relations": "{ count, select, 1 {1 relation} other {# relations} } selected", | |
979 | + "type": "Type", | |
980 | + "to-entity-type": "To entity type", | |
981 | + "to-entity-name": "To entity name", | |
982 | + "from-entity-type": "From entity type", | |
983 | + "from-entity-name": "From entity name", | |
984 | + "to-entity": "To entity", | |
985 | + "from-entity": "From entity", | |
986 | + "delete": "Delete relation", | |
987 | + "relation-type": "Relation type", | |
988 | + "relation-type-required": "Relation type is required.", | |
989 | + "any-relation-type": "Any type", | |
990 | + "add": "Add relation", | |
991 | + "edit": "Edit relation", | |
992 | + "delete-to-relation-title": "Are you sure you want to delete relation to the entity '{{entityName}}'?", | |
993 | + "delete-to-relation-text": "Be careful, after the confirmation the entity '{{entityName}}' will be unrelated from the current entity.", | |
994 | + "delete-to-relations-title": "Are you sure you want to delete { count, select, 1 {1 relation} other {# relations} }?", | |
995 | + "delete-to-relations-text": "Be careful, after the confirmation all selected relations will be removed and corresponding entities will be unrelated from the current entity.", | |
996 | + "delete-from-relation-title": "Are you sure you want to delete relation from the entity '{{entityName}}'?", | |
997 | + "delete-from-relation-text": "Be careful, after the confirmation current entity will be unrelated from the entity '{{entityName}}'.", | |
998 | + "delete-from-relations-title": "Are you sure you want to delete { count, select, 1 {1 relation} other {# relations} }?", | |
999 | + "delete-from-relations-text": "Be careful, after the confirmation all selected relations will be removed and current entity will be unrelated from the corresponding entities.", | |
1000 | + "remove-relation-filter": "Remove relation filter", | |
1001 | + "add-relation-filter": "Add relation filter", | |
1002 | + "any-relation": "Any relation", | |
1003 | + "relation-filters": "Relation filters", | |
1004 | + "additional-info": "Additional info (JSON)", | |
1005 | + "invalid-additional-info": "Unable to parse additional info json." | |
1006 | + }, | |
1007 | + "rulechain": { // TODO | |
1008 | + "rulechain": "Rule chain", | |
1009 | + "rulechains": "Rule chains", | |
1010 | + "root": "Root", | |
1011 | + "delete": "Delete rule chain", | |
1012 | + "name": "Name", | |
1013 | + "name-required": "Name is required.", | |
1014 | + "description": "Description", | |
1015 | + "add": "Add Rule Chain", | |
1016 | + "set-root": "Make rule chain root", | |
1017 | + "set-root-rulechain-title": "Are you sure you want to make the rule chain '{{ruleChainName}}' root?", | |
1018 | + "set-root-rulechain-text": "After the confirmation the rule chain will become root and will handle all incoming transport messages.", | |
1019 | + "delete-rulechain-title": "Are you sure you want to delete the rule chain '{{ruleChainName}}'?", | |
1020 | + "delete-rulechain-text": "Be careful, after the confirmation the rule chain and all related data will become unrecoverable.", | |
1021 | + "delete-rulechains-title": "Are you sure you want to delete { count, select, 1 {1 rule chain} other {# rule chains} }?", | |
1022 | + "delete-rulechains-action-title": "Delete { count, select, 1 {1 rule chain} other {# rule chains} }", | |
1023 | + "delete-rulechains-text": "Be careful, after the confirmation all selected rule chains will be removed and all related data will become unrecoverable.", | |
1024 | + "add-rulechain-text": "Add new rule chain", | |
1025 | + "no-rulechains-text": "No rule chains found", | |
1026 | + "rulechain-details": "Rule chain details", | |
1027 | + "details": "Details", | |
1028 | + "events": "Events", | |
1029 | + "system": "System", | |
1030 | + "import": "Import rule chain", | |
1031 | + "export": "Export rule chain", | |
1032 | + "export-failed-error": "Unable to export rule chain: {{error}}", | |
1033 | + "create-new-rulechain": "Create new rule chain", | |
1034 | + "rulechain-file": "Rule chain file", | |
1035 | + "invalid-rulechain-file-error": "Unable to import rule chain: Invalid rule chain data structure.", | |
1036 | + "copyId": "Copy rule chain Id", | |
1037 | + "idCopiedMessage": "Rule chain Id has been copied to clipboard", | |
1038 | + "select-rulechain": "Select rule chain", | |
1039 | + "no-rulechains-matching": "No rule chains matching '{{entity}}' were found.", | |
1040 | + "rulechain-required": "Rule chain is required", | |
1041 | + "management": "Rules management", | |
1042 | + "debug-mode": "Debug mode" | |
1043 | + }, | |
1044 | + "rulenode": { // TODO | |
1045 | + "details": "Details", | |
1046 | + "events": "Events", | |
1047 | + "search": "Search nodes", | |
1048 | + "open-node-library": "Open node library", | |
1049 | + "add": "Add rule node", | |
1050 | + "name": "Name", | |
1051 | + "name-required": "Name is required.", | |
1052 | + "type": "Type", | |
1053 | + "description": "Description", | |
1054 | + "delete": "Delete rule node", | |
1055 | + "select-all-objects": "Select all nodes and connections", | |
1056 | + "deselect-all-objects": "Deselect all nodes and connections", | |
1057 | + "delete-selected-objects": "Delete selected nodes and connections", | |
1058 | + "delete-selected": "Delete selected", | |
1059 | + "select-all": "Select all", | |
1060 | + "copy-selected": "Copy selected", | |
1061 | + "deselect-all": "Deselect all", | |
1062 | + "rulenode-details": "Rule node details", | |
1063 | + "debug-mode": "Debug mode", | |
1064 | + "configuration": "Configuration", | |
1065 | + "link": "Link", | |
1066 | + "link-details": "Rule node link details", | |
1067 | + "add-link": "Add link", | |
1068 | + "link-label": "Link label", | |
1069 | + "link-label-required": "Link label is required.", | |
1070 | + "custom-link-label": "Custom link label", | |
1071 | + "custom-link-label-required": "Custom link label is required.", | |
1072 | + "type-filter": "Filter", | |
1073 | + "type-filter-details": "Filter incoming messages with configured conditions", | |
1074 | + "type-enrichment": "Enrichment", | |
1075 | + "type-enrichment-details": "Add additional information into Message Metadata", | |
1076 | + "type-transformation": "Transformation", | |
1077 | + "type-transformation-details": "Change Message payload and Metadata", | |
1078 | + "type-action": "Action", | |
1079 | + "type-action-details": "Perform special action", | |
1080 | + "type-external": "External", | |
1081 | + "type-external-details": "Interacts with external system", | |
1082 | + "type-rule-chain": "Rule Chain", | |
1083 | + "type-rule-chain-details": "Forwards incoming messages to specified Rule Chain", | |
1084 | + "type-input": "Input", | |
1085 | + "type-input-details": "Logical input of Rule Chain, forwards incoming messages to next related Rule Node", | |
1086 | + "directive-is-not-loaded": "Defined configuration directive '{{directiveName}}' is not available.", | |
1087 | + "ui-resources-load-error": "Failed to load configuration ui resources.", | |
1088 | + "invalid-target-rulechain": "Unable to resolve target rule chain!", | |
1089 | + "test-script-function": "Test script function", | |
1090 | + "message": "Message", | |
1091 | + "message-type": "Message type", | |
1092 | + "message-type-required": "Message type is required", | |
1093 | + "metadata": "Metadata", | |
1094 | + "metadata-required": "Metadata entries can't be empty.", | |
1095 | + "output": "Output", | |
1096 | + "test": "Test", | |
1097 | + "help": "Help" | |
607 | 1098 | }, |
608 | 1099 | "tenant": { |
609 | - "tenants": "Tenants", | |
610 | - "management": "Gestión de Tenant", | |
611 | - "add": "Agregar Tenant", | |
612 | - "admins": "Admins", | |
613 | - "manage-tenant-admins": "Gestionar administradores tenant", | |
614 | - "delete": "Eliminar tenant", | |
615 | - "add-tenant-text": "Agregar nuevo tenant", | |
616 | - "no-tenants-text": "Ningún tenant encontrado", | |
617 | - "tenant-details": "Detalles del Tenant", | |
618 | - "delete-tenant-title": "¿Estás seguro que quieres eliminar el tenant '{{tenantTitle}}'?", | |
619 | - "delete-tenant-text": "Ten cuidado, luego de confirmar el tenant será eliminado y la información relacionada será irrecuperable.", | |
620 | - "delete-tenants-title": "¿Estás seguro que quieres eliminar { count, select, 1 {1 tenant} other {# tenants} }?", | |
621 | - "delete-tenants-action-title": "Eliminar { count, select, 1 {1 tenant} other {# tenants} }", | |
622 | - "delete-tenants-text": "Ten cuidado, luego de confirmar los tenants seleccionados serán eliminados y la información relacionada será irrecuperable.", | |
623 | - "title": "Título", | |
624 | - "title-required": "Título requerido.", | |
625 | - "description": "Descripción" | |
1100 | + "tenants": "Tenants", | |
1101 | + "management": "Gestión de Tenant", | |
1102 | + "add": "Agregar Tenant", | |
1103 | + "admins": "Admins", | |
1104 | + "manage-tenant-admins": "Gestionar administradores tenant", | |
1105 | + "delete": "Eliminar tenant", | |
1106 | + "add-tenant-text": "Agregar nuevo tenant", | |
1107 | + "no-tenants-text": "Ningún tenant encontrado", | |
1108 | + "tenant-details": "Detalles del Tenant", | |
1109 | + "delete-tenant-title": "¿Estás seguro que quieres eliminar el tenant '{{tenantTitle}}'?", | |
1110 | + "delete-tenant-text": "Ten cuidado, luego de confirmar el tenant será eliminado y la información relacionada será irrecuperable.", | |
1111 | + "delete-tenants-title": "¿Estás seguro que quieres eliminar { count, select, 1 {1 tenant} other {# tenants} }?", | |
1112 | + "delete-tenants-action-title": "Eliminar { count, select, 1 {1 tenant} other {# tenants} }", | |
1113 | + "delete-tenants-text": "Ten cuidado, luego de confirmar los tenants seleccionados serán eliminados y la información relacionada será irrecuperable.", | |
1114 | + "title": "Título", | |
1115 | + "title-required": "Título requerido.", | |
1116 | + "description": "Descripción" | |
626 | 1117 | }, |
627 | 1118 | "timeinterval": { |
628 | - "seconds-interval": "{ seconds, select, 1 {1 segundo} other {# segundos} }", | |
629 | - "minutes-interval": "{ minutes, select, 1 {1 minuto} other {# minutos} }", | |
630 | - "hours-interval": "{ hours, select, 1 {1 hora} other {# horas} }", | |
631 | - "days-interval": "{ days, select, 1 {1 día} other {# días} }", | |
632 | - "days": "Días", | |
633 | - "hours": "Horas", | |
634 | - "minutes": "Minutos", | |
635 | - "seconds": "Segundos", | |
636 | - "advanced": "Avanzado" | |
1119 | + "seconds-interval": "{ seconds, select, 1 {1 segundo} other {# segundos} }", | |
1120 | + "minutes-interval": "{ minutes, select, 1 {1 minuto} other {# minutos} }", | |
1121 | + "hours-interval": "{ hours, select, 1 {1 hora} other {# horas} }", | |
1122 | + "days-interval": "{ days, select, 1 {1 día} other {# días} }", | |
1123 | + "days": "Días", | |
1124 | + "hours": "Horas", | |
1125 | + "minutes": "Minutos", | |
1126 | + "seconds": "Segundos", | |
1127 | + "advanced": "Avanzado" | |
637 | 1128 | }, |
638 | 1129 | "timewindow": { |
639 | - "days": "{ days, select, 1 { día } other {# días } }", | |
640 | - "hours": "{ hours, select, 0 { horas } 1 {1 hora } other {# horas } }", | |
641 | - "minutes": "{ minutes, select, 0 { minutos } 1 {1 minuto } other {# minutos } }", | |
642 | - "seconds": "{ seconds, select, 0 { segundos } 1 {1 segundo } other {# segundos } }", | |
643 | - "realtime": "Tiempo-real", | |
644 | - "history": "Histórico", | |
645 | - "last-prefix": "último", | |
646 | - "period": "desde {{ startTime }} hasta {{ endTime }}", | |
647 | - "edit": "Editar ventana de tiempo", | |
648 | - "date-range": "Rango de fechas", | |
649 | - "last": "Últimos", | |
650 | - "time-period": "Período de tiempo" | |
1130 | + "days": "{ days, select, 1 { día } other {# días } }", | |
1131 | + "hours": "{ hours, select, 0 { horas } 1 {1 hora } other {# horas } }", | |
1132 | + "minutes": "{ minutes, select, 0 { minutos } 1 {1 minuto } other {# minutos } }", | |
1133 | + "seconds": "{ seconds, select, 0 { segundos } 1 {1 segundo } other {# segundos } }", | |
1134 | + "realtime": "Tiempo-real", | |
1135 | + "history": "Histórico", | |
1136 | + "last-prefix": "último", | |
1137 | + "period": "desde {{ startTime }} hasta {{ endTime }}", | |
1138 | + "edit": "Editar ventana de tiempo", | |
1139 | + "date-range": "Rango de fechas", | |
1140 | + "last": "Últimos", | |
1141 | + "time-period": "Período de tiempo" | |
651 | 1142 | }, |
652 | 1143 | "user": { |
653 | - "users": "Usuarios", | |
654 | - "customer-users": "Usuarios del Cliente", | |
655 | - "tenant-admins": "Tenant Admins", | |
656 | - "sys-admin": "Administrador del Sistema", | |
657 | - "tenant-admin": "Administrador Tenant", | |
658 | - "customer": "Cliente", | |
659 | - "anonymous": "Anónimo", | |
660 | - "add": "Agregar usuario", | |
661 | - "delete": "Eliminar usuario", | |
662 | - "add-user-text": "Agregar nuevo usuario", | |
663 | - "no-users-text": "Ningún usuario encontrado", | |
664 | - "user-details": "Detalles del usuario", | |
665 | - "delete-user-title": "¿Estás seguro que quieres eliminar el usuario '{{userEmail}}'?", | |
666 | - "delete-user-text": "Ten cuidado, luego de confirmar el usuario seleccionado será eliminado y la información relacionada será irrecuperable.", | |
667 | - "delete-users-title": "¿Estás seguro que quieres eliminar { count, select, 1 {1 usuario} other {# usuarios} }?", | |
668 | - "delete-users-action-title": "Borrar { count, select, 1 {1 usuario} other {# usuarios} }", | |
669 | - "delete-users-text": "Ten cuidado, luego de confirmar los usuarios seleccionados serán eliminados y la información relacionada será irrecuperable.", | |
670 | - "activation-email-sent-message": "Mail de activación enviado con éxito!", | |
671 | - "resend-activation": "Reenviar activación", | |
672 | - "email": "Email", | |
673 | - "email-required": "Email requerido.", | |
674 | - "first-name": "Nombre", | |
675 | - "last-name": "Apellido", | |
676 | - "description": "Descripción", | |
677 | - "default-dashboard": "Panel por defecto", | |
678 | - "always-fullscreen": "Siempre en pantalla completa" | |
1144 | + "users": "Usuarios", | |
1145 | + "customer-users": "Usuarios del Cliente", | |
1146 | + "tenant-admins": "Tenant Admins", | |
1147 | + "sys-admin": "Administrador del Sistema", | |
1148 | + "tenant-admin": "Administrador Tenant", | |
1149 | + "customer": "Cliente", | |
1150 | + "anonymous": "Anónimo", | |
1151 | + "add": "Agregar usuario", | |
1152 | + "delete": "Eliminar usuario", | |
1153 | + "add-user-text": "Agregar nuevo usuario", | |
1154 | + "no-users-text": "Ningún usuario encontrado", | |
1155 | + "user-details": "Detalles del usuario", | |
1156 | + "delete-user-title": "¿Estás seguro que quieres eliminar el usuario '{{userEmail}}'?", | |
1157 | + "delete-user-text": "Ten cuidado, luego de confirmar el usuario seleccionado será eliminado y la información relacionada será irrecuperable.", | |
1158 | + "delete-users-title": "¿Estás seguro que quieres eliminar { count, select, 1 {1 usuario} other {# usuarios} }?", | |
1159 | + "delete-users-action-title": "Borrar { count, select, 1 {1 usuario} other {# usuarios} }", | |
1160 | + "delete-users-text": "Ten cuidado, luego de confirmar los usuarios seleccionados serán eliminados y la información relacionada será irrecuperable.", | |
1161 | + "activation-email-sent-message": "Mail de activación enviado con éxito!", | |
1162 | + "resend-activation": "Reenviar activación", | |
1163 | + "email": "Email", | |
1164 | + "email-required": "Email requerido.", | |
1165 | + "first-name": "Nombre", | |
1166 | + "last-name": "Apellido", | |
1167 | + "description": "Descripción", | |
1168 | + "default-dashboard": "Panel por defecto", | |
1169 | + "always-fullscreen": "Siempre en pantalla completa" | |
679 | 1170 | }, |
680 | 1171 | "value": { |
681 | - "type": "Tipo de valor", | |
682 | - "string": "Cadena de texto", | |
683 | - "string-value": "Valor de cadena de texto", | |
684 | - "integer": "Nro entero", | |
685 | - "integer-value": "Valor de nro entero", | |
686 | - "invalid-integer-value": "Valor inválido", | |
687 | - "double": "Nro decimal", | |
688 | - "double-value": "Valor nro decimal", | |
689 | - "boolean": "Booleano", | |
690 | - "boolean-value": "Valor booleano", | |
691 | - "false": "Falso", | |
692 | - "true": "Verdadero" | |
1172 | + "type": "Tipo de valor", | |
1173 | + "string": "Cadena de texto", | |
1174 | + "string-value": "Valor de cadena de texto", | |
1175 | + "integer": "Nro entero", | |
1176 | + "integer-value": "Valor de nro entero", | |
1177 | + "invalid-integer-value": "Valor inválido", | |
1178 | + "double": "Nro decimal", | |
1179 | + "double-value": "Valor nro decimal", | |
1180 | + "boolean": "Booleano", | |
1181 | + "boolean-value": "Valor booleano", | |
1182 | + "false": "Falso", | |
1183 | + "true": "Verdadero" | |
693 | 1184 | }, |
694 | 1185 | "widget": { |
695 | - "widget-library": "Bibloteca de Widgets", | |
696 | - "widget-bundle": "Paquetes de Widgets", | |
697 | - "select-widgets-bundle": "Seleccionar paquete de widgets", | |
698 | - "management": "Gestión de Widgets", | |
699 | - "editor": "Editor de widgets", | |
700 | - "widget-type-not-found": "Problema al cargar la configuración del widget.<br>Probablemente asociado\n El tipo de widget fue eliminado.", | |
701 | - "widget-type-load-error": "Widget no pudo ser cargado debido a estos errores:", | |
702 | - "remove": "Eliminar widget", | |
703 | - "edit": "Editar widget", | |
704 | - "remove-widget-title": "¿Estás seguro que quieres eliminar el widget '{{widgetTitle}}'?", | |
705 | - "remove-widget-text": "Luego de confirmar el widget será eliminado y toda la información relacionada será irrecuperable..", | |
706 | - "timeseries": "Series de tiempo", | |
707 | - "latest-values": "Últimos valores", | |
708 | - "rpc": "Widget de control", | |
709 | - "static": "Widget estático", | |
710 | - "select-widget-type": "Seleccionar tipo de widget", | |
711 | - "missing-widget-title-error": "El titulo del widget debe ser especificado!", | |
712 | - "widget-saved": "Widget guardado", | |
713 | - "unable-to-save-widget-error": "Imposible guardar widget! Tiene errores!", | |
714 | - "save": "Guardar widget", | |
715 | - "saveAs": "Guardar widget como", | |
716 | - "save-widget-type-as": "Guardar tipo de widget como", | |
717 | - "save-widget-type-as-text": "Por favor, ingrese un nuevo titulo y/o seleccione un paquete de destino.", | |
718 | - "toggle-fullscreen": "Cambiar a pantalla completa", | |
719 | - "run": "Correr widget", | |
720 | - "title": "Titulo", | |
721 | - "title-required": "Titulo requerido.", | |
722 | - "type": "Tipo", | |
723 | - "resources": "Recursos", | |
724 | - "resource-url": "JavaScript/CSS URL", | |
725 | - "remove-resource": "Eliminar recurso", | |
726 | - "add-resource": "Agregar recurso", | |
727 | - "html": "HTML", | |
728 | - "tidy": "Tidy", | |
729 | - "css": "CSS", | |
730 | - "settings-schema": "Esquema de configuración", | |
731 | - "datakey-settings-schema": "Esquema de configuración de clave de datos", | |
732 | - "javascript": "Javascript", | |
733 | - "remove-widget-type-title": "¿Estás seguro que quieres eliminar el tipo del widget '{{widgetName}}'?", | |
734 | - "remove-widget-type-text": "Luego de confirmar el tipo será eliminado y la información relacionada será irrecuperable.", | |
735 | - "remove-widget-type": "Eliminar tipo de widget.", | |
736 | - "add-widget-type": "Agregar nuevo tipo de widget", | |
737 | - "widget-type-load-failed-error": "Error al cargar el tipo de widget!", | |
738 | - "widget-template-load-failed-error": "Error al cargar el template del widget!", | |
739 | - "add": "Agregar Widget", | |
740 | - "undo": "Deshacer cambios", | |
741 | - "export": "Exportar widget" | |
1186 | + "widget-library": "Bibloteca de Widgets", | |
1187 | + "widget-bundle": "Paquetes de Widgets", | |
1188 | + "select-widgets-bundle": "Seleccionar paquete de widgets", | |
1189 | + "management": "Gestión de Widgets", | |
1190 | + "editor": "Editor de widgets", | |
1191 | + "widget-type-not-found": "Problema al cargar la configuración del widget.<br>Probablemente asociado\n El tipo de widget fue eliminado.", | |
1192 | + "widget-type-load-error": "Widget no pudo ser cargado debido a estos errores:", | |
1193 | + "remove": "Eliminar widget", | |
1194 | + "edit": "Editar widget", | |
1195 | + "remove-widget-title": "¿Estás seguro que quieres eliminar el widget '{{widgetTitle}}'?", | |
1196 | + "remove-widget-text": "Luego de confirmar el widget será eliminado y toda la información relacionada será irrecuperable..", | |
1197 | + "timeseries": "Series de tiempo", | |
1198 | + "latest-values": "Últimos valores", | |
1199 | + "rpc": "Widget de control", | |
1200 | + "static": "Widget estático", | |
1201 | + "select-widget-type": "Seleccionar tipo de widget", | |
1202 | + "missing-widget-title-error": "El titulo del widget debe ser especificado!", | |
1203 | + "widget-saved": "Widget guardado", | |
1204 | + "unable-to-save-widget-error": "Imposible guardar widget! Tiene errores!", | |
1205 | + "save": "Guardar widget", | |
1206 | + "saveAs": "Guardar widget como", | |
1207 | + "save-widget-type-as": "Guardar tipo de widget como", | |
1208 | + "save-widget-type-as-text": "Por favor, ingrese un nuevo titulo y/o seleccione un paquete de destino.", | |
1209 | + "toggle-fullscreen": "Cambiar a pantalla completa", | |
1210 | + "run": "Correr widget", | |
1211 | + "title": "Titulo", | |
1212 | + "title-required": "Titulo requerido.", | |
1213 | + "type": "Tipo", | |
1214 | + "resources": "Recursos", | |
1215 | + "resource-url": "JavaScript/CSS URL", | |
1216 | + "remove-resource": "Eliminar recurso", | |
1217 | + "add-resource": "Agregar recurso", | |
1218 | + "html": "HTML", | |
1219 | + "tidy": "Tidy", | |
1220 | + "css": "CSS", | |
1221 | + "settings-schema": "Esquema de configuración", | |
1222 | + "datakey-settings-schema": "Esquema de configuración de clave de datos", | |
1223 | + "javascript": "Javascript", | |
1224 | + "remove-widget-type-title": "¿Estás seguro que quieres eliminar el tipo del widget '{{widgetName}}'?", | |
1225 | + "remove-widget-type-text": "Luego de confirmar el tipo será eliminado y la información relacionada será irrecuperable.", | |
1226 | + "remove-widget-type": "Eliminar tipo de widget.", | |
1227 | + "add-widget-type": "Agregar nuevo tipo de widget", | |
1228 | + "widget-type-load-failed-error": "Error al cargar el tipo de widget!", | |
1229 | + "widget-template-load-failed-error": "Error al cargar el template del widget!", | |
1230 | + "add": "Agregar Widget", | |
1231 | + "undo": "Deshacer cambios", | |
1232 | + "export": "Exportar widget" | |
1233 | + }, | |
1234 | + "widget-action": { // TODO | |
1235 | + "header-button": "Widget header button", | |
1236 | + "open-dashboard-state": "Navigate to new dashboard state", | |
1237 | + "update-dashboard-state": "Update current dashboard state", | |
1238 | + "open-dashboard": "Navigate to other dashboard", | |
1239 | + "custom": "Custom action", | |
1240 | + "target-dashboard-state": "Target dashboard state", | |
1241 | + "target-dashboard-state-required": "Target dashboard state is required", | |
1242 | + "set-entity-from-widget": "Set entity from widget", | |
1243 | + "target-dashboard": "Target dashboard", | |
1244 | + "open-right-layout": "Open right dashboard layout (mobile view)" | |
742 | 1245 | }, |
743 | 1246 | "widgets-bundle": { |
744 | - "current": "Paquete actual", | |
745 | - "widgets-bundles": "Paquete de Widgets", | |
746 | - "add": "Agregar paquete de widgets", | |
747 | - "delete": "Eliminar paquete de widgets", | |
748 | - "title": "Título", | |
749 | - "title-required": "Título requerido.", | |
750 | - "add-widgets-bundle-text": "Agregar nuevo paquete de widgets", | |
751 | - "no-widgets-bundles-text": "Ningún paquete de widgets encontrado", | |
752 | - "empty": "Paquete de widgets vacío.", | |
753 | - "details": "Detalles", | |
754 | - "widgets-bundle-details": "Detalles del paquete de Widgets", | |
755 | - "delete-widgets-bundle-title": "¿Estás seguro que desea eliminar el paquete de widgets '{{widgetsBundleTitle}}'?", | |
756 | - "delete-widgets-bundle-text": "Ten cuidado, luego de confirmar todos los paquetes seleccionados serán eliminados y su información relacionada será irrecuperable.", | |
757 | - "delete-widgets-bundles-title": "¿Estás seguro que deseas eliminar { count, select, 1 {1 paquete de widgets} other {# paquetes de widgets} }?", | |
758 | - "delete-widgets-bundles-action-title": "Eliminar { count, select, 1 {1 paquete de widgets} other {# paquetes de widgets} }", | |
759 | - "delete-widgets-bundles-text": "Ten cuidado, luego de confirmar todos los paquetes seleccionados serán eliminados y la información relacionada será irrecuperable.", | |
760 | - "no-widgets-bundles-matching": "Ningún paquete '{{widgetsBundle}}' encontrado.", | |
761 | - "widgets-bundle-required": "Paquete de widget requerido.", | |
762 | - "system": "Sistema", | |
763 | - "import": "Importar paquete de widgets", | |
764 | - "export": "Exportar paquete de widgets", | |
765 | - "export-failed-error": "Imposible exportar paquete de widgets: {{error}}", | |
766 | - "create-new-widgets-bundle": "Crear nuevo paquete de widgets", | |
767 | - "widgets-bundle-file": "Archivo de paquete de widgets", | |
768 | - "invalid-widgets-bundle-file-error": "Imposible importar paquete de widgets: Estructura de datos inválida." | |
1247 | + "current": "Paquete actual", | |
1248 | + "widgets-bundles": "Paquete de Widgets", | |
1249 | + "add": "Agregar paquete de widgets", | |
1250 | + "delete": "Eliminar paquete de widgets", | |
1251 | + "title": "Título", | |
1252 | + "title-required": "Título requerido.", | |
1253 | + "add-widgets-bundle-text": "Agregar nuevo paquete de widgets", | |
1254 | + "no-widgets-bundles-text": "Ningún paquete de widgets encontrado", | |
1255 | + "empty": "Paquete de widgets vacío.", | |
1256 | + "details": "Detalles", | |
1257 | + "widgets-bundle-details": "Detalles del paquete de Widgets", | |
1258 | + "delete-widgets-bundle-title": "¿Estás seguro que desea eliminar el paquete de widgets '{{widgetsBundleTitle}}'?", | |
1259 | + "delete-widgets-bundle-text": "Ten cuidado, luego de confirmar todos los paquetes seleccionados serán eliminados y su información relacionada será irrecuperable.", | |
1260 | + "delete-widgets-bundles-title": "¿Estás seguro que deseas eliminar { count, select, 1 {1 paquete de widgets} other {# paquetes de widgets} }?", | |
1261 | + "delete-widgets-bundles-action-title": "Eliminar { count, select, 1 {1 paquete de widgets} other {# paquetes de widgets} }", | |
1262 | + "delete-widgets-bundles-text": "Ten cuidado, luego de confirmar todos los paquetes seleccionados serán eliminados y la información relacionada será irrecuperable.", | |
1263 | + "no-widgets-bundles-matching": "Ningún paquete '{{widgetsBundle}}' encontrado.", | |
1264 | + "widgets-bundle-required": "Paquete de widget requerido.", | |
1265 | + "system": "Sistema", | |
1266 | + "import": "Importar paquete de widgets", | |
1267 | + "export": "Exportar paquete de widgets", | |
1268 | + "export-failed-error": "Imposible exportar paquete de widgets: {{error}}", | |
1269 | + "create-new-widgets-bundle": "Crear nuevo paquete de widgets", | |
1270 | + "widgets-bundle-file": "Archivo de paquete de widgets", | |
1271 | + "invalid-widgets-bundle-file-error": "Imposible importar paquete de widgets: Estructura de datos inválida." | |
769 | 1272 | }, |
770 | 1273 | "widget-config": { |
771 | - "data": "Datos", | |
772 | - "settings": "Ajustes", | |
773 | - "advanced": "Avanzado", | |
774 | - "title": "Titulo", | |
775 | - "general-settings": "Ajustes generales", | |
776 | - "display-title": "Mostrar titulo", | |
777 | - "drop-shadow": "Sombra", | |
778 | - "enable-fullscreen": "Habilitar pantalla completa", | |
779 | - "background-color": "Color de fondo", | |
780 | - "text-color": "Color del texto", | |
781 | - "padding": "Relleno", | |
782 | - "title-style": "Estilo de título", | |
783 | - "mobile-mode-settings": "Ajustes mobile.", | |
784 | - "order": "Orden", | |
785 | - "height": "Altura", | |
786 | - "units": "Caracter especial a mostrar en el siguiente valor", | |
787 | - "decimals": "Números de dígitos después de la coma", | |
788 | - "timewindow": "Ventana de tiempo", | |
789 | - "use-dashboard-timewindow": "Usar ventana de tiempo del Panel", | |
790 | - "display-legend": "Mostrar leyenda", | |
791 | - "datasources": "Set de datos", | |
792 | - "datasource-type": "Tipo", | |
793 | - "datasource-parameters": "Parámetros", | |
794 | - "remove-datasource": "Eliminar set de datos", | |
795 | - "add-datasource": "Agregar set de datos", | |
796 | - "target-device": "Dispositivo destino" | |
1274 | + "data": "Datos", | |
1275 | + "settings": "Ajustes", | |
1276 | + "advanced": "Avanzado", | |
1277 | + "title": "Titulo", | |
1278 | + "general-settings": "Ajustes generales", | |
1279 | + "display-title": "Mostrar titulo", | |
1280 | + "drop-shadow": "Sombra", | |
1281 | + "enable-fullscreen": "Habilitar pantalla completa", | |
1282 | + "background-color": "Color de fondo", | |
1283 | + "text-color": "Color del texto", | |
1284 | + "padding": "Relleno", | |
1285 | + "title-style": "Estilo de título", | |
1286 | + "mobile-mode-settings": "Ajustes mobile.", | |
1287 | + "order": "Orden", | |
1288 | + "height": "Altura", | |
1289 | + "units": "Caracter especial a mostrar en el siguiente valor", | |
1290 | + "decimals": "Números de dígitos después de la coma", | |
1291 | + "timewindow": "Ventana de tiempo", | |
1292 | + "use-dashboard-timewindow": "Usar ventana de tiempo del Panel", | |
1293 | + "display-legend": "Mostrar leyenda", | |
1294 | + "datasources": "Set de datos", | |
1295 | + "datasource-type": "Tipo", | |
1296 | + "datasource-parameters": "Parámetros", | |
1297 | + "remove-datasource": "Eliminar set de datos", | |
1298 | + "add-datasource": "Agregar set de datos", | |
1299 | + "target-device": "Dispositivo destino" | |
797 | 1300 | }, |
798 | 1301 | "widget-type": { |
799 | - "import": "Importar tipo de widget", | |
800 | - "export": "Exportar tipo de widget", | |
801 | - "export-failed-error": "Imposible exportar tipo de widget: {{error}}", | |
802 | - "create-new-widget-type": "Crear nuevo tipo de widget", | |
803 | - "widget-type-file": "Tipo de archivo del widget", | |
804 | - "invalid-widget-type-file-error": "Imposible de importar tipo de widget: Estructura de datos inválida." | |
1302 | + "import": "Importar tipo de widget", | |
1303 | + "export": "Exportar tipo de widget", | |
1304 | + "export-failed-error": "Imposible exportar tipo de widget: {{error}}", | |
1305 | + "create-new-widget-type": "Crear nuevo tipo de widget", | |
1306 | + "widget-type-file": "Tipo de archivo del widget", | |
1307 | + "invalid-widget-type-file-error": "Imposible de importar tipo de widget: Estructura de datos inválida." | |
1308 | + }, | |
1309 | + "icon": { // TODO | |
1310 | + "icon": "Icon", | |
1311 | + "select-icon": "Select icon", | |
1312 | + "material-icons": "Material icons", | |
1313 | + "show-all": "Show all icons" | |
1314 | + }, | |
1315 | + "custom": { // TODO | |
1316 | + "widget-action": { | |
1317 | + "action-cell-button": "Action cell button", | |
1318 | + "row-click": "On row click", | |
1319 | + "marker-click": "On marker click", | |
1320 | + "tooltip-tag-action": "Tooltip tag action" | |
1321 | + } | |
805 | 1322 | }, |
806 | 1323 | "language": { |
807 | - "language": "Lenguaje", | |
808 | - "en_US": "Inglés", | |
809 | - "ko_KR": "Coreano", | |
810 | - "zh_CN": "Chino", | |
811 | - "ru_RU": "Ruso", | |
812 | - "es_ES": "Español" | |
1324 | + "language": "Lenguaje", | |
1325 | + "en_US": "Inglés", | |
1326 | + "ko_KR": "Coreano", | |
1327 | + "zh_CN": "Chino", | |
1328 | + "ru_RU": "Ruso", | |
1329 | + "es_ES": "Español" | |
813 | 1330 | } |
814 | - }; | |
815 | - angular.extend(locales, {'es_ES': es_ES}); | |
1331 | + }; | |
1332 | + angular.extend(locales, { 'es_ES': es_ES }); | |
816 | 1333 | } |
\ No newline at end of file | ... | ... |
... | ... | @@ -38,8 +38,11 @@ export default function addLocaleKorean(locales) { |
38 | 38 | "update": "업데이트", |
39 | 39 | "remove": "제거", |
40 | 40 | "search": "검색", |
41 | + "clear-search": "Clear search", // TODO | |
41 | 42 | "assign": "할당", |
42 | 43 | "unassign": "비할당", |
44 | + "share": "Share", // TODO | |
45 | + "make-private": "Make private", // TODO | |
43 | 46 | "apply": "적용", |
44 | 47 | "apply-changes": "변경사항 적용", |
45 | 48 | "edit-mode": "수정 모드", |
... | ... | @@ -57,8 +60,11 @@ export default function addLocaleKorean(locales) { |
57 | 60 | "undo": "취소", |
58 | 61 | "copy": "복사", |
59 | 62 | "paste": "붙여넣기", |
63 | + "copy-reference": "Copy reference", // TODO | |
64 | + "paste-reference": "Paste reference", // TODO | |
60 | 65 | "import": "가져오기", |
61 | - "export": "내보내기" | |
66 | + "export": "내보내기", | |
67 | + "share-via": "Share via {{provider}}" // TODO | |
62 | 68 | }, |
63 | 69 | "aggregation": { |
64 | 70 | "aggregation": "집합", |
... | ... | @@ -95,6 +101,160 @@ export default function addLocaleKorean(locales) { |
95 | 101 | "enable-tls": "TLS 사용", |
96 | 102 | "send-test-mail": "테스트 메일 보내기" |
97 | 103 | }, |
104 | + | |
105 | + "alarm": { // TODO | |
106 | + "alarm": "Alarm", | |
107 | + "alarms": "Alarms", | |
108 | + "select-alarm": "Select alarm", | |
109 | + "no-alarms-matching": "No alarms matching '{{entity}}' were found.", | |
110 | + "alarm-required": "Alarm is required", | |
111 | + "alarm-status": "Alarm status", | |
112 | + "search-status": { | |
113 | + "ANY": "Any", | |
114 | + "ACTIVE": "Active", | |
115 | + "CLEARED": "Cleared", | |
116 | + "ACK": "Acknowledged", | |
117 | + "UNACK": "Unacknowledged" | |
118 | + }, | |
119 | + "display-status": { | |
120 | + "ACTIVE_UNACK": "Active Unacknowledged", | |
121 | + "ACTIVE_ACK": "Active Acknowledged", | |
122 | + "CLEARED_UNACK": "Cleared Unacknowledged", | |
123 | + "CLEARED_ACK": "Cleared Acknowledged" | |
124 | + }, | |
125 | + "no-alarms-prompt": "No alarms found", | |
126 | + "created-time": "Created time", | |
127 | + "type": "Type", | |
128 | + "severity": "Severity", | |
129 | + "originator": "Originator", | |
130 | + "originator-type": "Originator type", | |
131 | + "details": "Details", | |
132 | + "status": "Status", | |
133 | + "alarm-details": "Alarm details", | |
134 | + "start-time": "Start time", | |
135 | + "end-time": "End time", | |
136 | + "ack-time": "Acknowledged time", | |
137 | + "clear-time": "Cleared time", | |
138 | + "severity-critical": "Critical", | |
139 | + "severity-major": "Major", | |
140 | + "severity-minor": "Minor", | |
141 | + "severity-warning": "Warning", | |
142 | + "severity-indeterminate": "Indeterminate", | |
143 | + "acknowledge": "Acknowledge", | |
144 | + "clear": "Clear", | |
145 | + "search": "Search alarms", | |
146 | + "selected-alarms": "{ count, select, 1 {1 alarm} other {# alarms} } selected", | |
147 | + "no-data": "No data to display", | |
148 | + "polling-interval": "Alarms polling interval (sec)", | |
149 | + "polling-interval-required": "Alarms polling interval is required.", | |
150 | + "min-polling-interval-message": "At least 1 sec polling interval is allowed.", | |
151 | + "aknowledge-alarms-title": "Acknowledge { count, select, 1 {1 alarm} other {# alarms} }", | |
152 | + "aknowledge-alarms-text": "Are you sure you want to acknowledge { count, select, 1 {1 alarm} other {# alarms} }?", | |
153 | + "clear-alarms-title": "Clear { count, select, 1 {1 alarm} other {# alarms} }", | |
154 | + "clear-alarms-text": "Are you sure you want to clear { count, select, 1 {1 alarm} other {# alarms} }?" | |
155 | + }, | |
156 | + "alias": { // TODO | |
157 | + "add": "Add alias", | |
158 | + "edit": "Edit alias", | |
159 | + "name": "Alias name", | |
160 | + "name-required": "Alias name is required", | |
161 | + "duplicate-alias": "Alias with same name is already exists.", | |
162 | + "filter-type-single-entity": "Single entity", | |
163 | + "filter-type-entity-list": "Entity list", | |
164 | + "filter-type-entity-name": "Entity name", | |
165 | + "filter-type-state-entity": "Entity from dashboard state", | |
166 | + "filter-type-state-entity-description": "Entity taken from dashboard state parameters", | |
167 | + "filter-type-asset-type": "Asset type", | |
168 | + "filter-type-asset-type-description": "Assets of type '{{assetType}}'", | |
169 | + "filter-type-asset-type-and-name-description": "Assets of type '{{assetType}}' and with name starting with '{{prefix}}'", | |
170 | + "filter-type-device-type": "Device type", | |
171 | + "filter-type-device-type-description": "Devices of type '{{deviceType}}'", | |
172 | + "filter-type-device-type-and-name-description": "Devices of type '{{deviceType}}' and with name starting with '{{prefix}}'", | |
173 | + "filter-type-relations-query": "Relations query", | |
174 | + "filter-type-relations-query-description": "{{entities}} that have {{relationType}} relation {{direction}} {{rootEntity}}", | |
175 | + "filter-type-asset-search-query": "Asset search query", | |
176 | + "filter-type-asset-search-query-description": "Assets with types {{assetTypes}} that have {{relationType}} relation {{direction}} {{rootEntity}}", | |
177 | + "filter-type-device-search-query": "Device search query", | |
178 | + "filter-type-device-search-query-description": "Devices with types {{deviceTypes}} that have {{relationType}} relation {{direction}} {{rootEntity}}", | |
179 | + "entity-filter": "Entity filter", | |
180 | + "resolve-multiple": "Resolve as multiple entities", | |
181 | + "filter-type": "Filter type", | |
182 | + "filter-type-required": "Filter type is required.", | |
183 | + "entity-filter-no-entity-matched": "No entities matching specified filter were found.", | |
184 | + "no-entity-filter-specified": "No entity filter specified", | |
185 | + "root-state-entity": "Use dashboard state entity as root", | |
186 | + "root-entity": "Root entity", | |
187 | + "state-entity-parameter-name": "State entity parameter name", | |
188 | + "default-state-entity": "Default state entity", | |
189 | + "default-entity-parameter-name": "By default", | |
190 | + "max-relation-level": "Max relation level", | |
191 | + "unlimited-level": "Unlimited level", | |
192 | + "state-entity": "Dashboard state entity", | |
193 | + "all-entities": "All entities", | |
194 | + "any-relation": "any" | |
195 | + }, | |
196 | + "asset": { // TODO | |
197 | + "asset": "Asset", | |
198 | + "assets": "Assets", | |
199 | + "management": "Asset management", | |
200 | + "view-assets": "View Assets", | |
201 | + "add": "Add Asset", | |
202 | + "assign-to-customer": "Assign to customer", | |
203 | + "assign-asset-to-customer": "Assign Asset(s) To Customer", | |
204 | + "assign-asset-to-customer-text": "Please select the assets to assign to the customer", | |
205 | + "no-assets-text": "No assets found", | |
206 | + "assign-to-customer-text": "Please select the customer to assign the asset(s)", | |
207 | + "public": "Public", | |
208 | + "assignedToCustomer": "Assigned to customer", | |
209 | + "make-public": "Make asset public", | |
210 | + "make-private": "Make asset private", | |
211 | + "unassign-from-customer": "Unassign from customer", | |
212 | + "delete": "Delete asset", | |
213 | + "asset-public": "Asset is public", | |
214 | + "asset-type": "Asset type", | |
215 | + "asset-type-required": "Asset type is required.", | |
216 | + "select-asset-type": "Select asset type", | |
217 | + "enter-asset-type": "Enter asset type", | |
218 | + "any-asset": "Any asset", | |
219 | + "no-asset-types-matching": "No asset types matching '{{entitySubtype}}' were found.", | |
220 | + "asset-type-list-empty": "No asset types selected.", | |
221 | + "asset-types": "Asset types", | |
222 | + "name": "Name", | |
223 | + "name-required": "Name is required.", | |
224 | + "description": "Description", | |
225 | + "type": "Type", | |
226 | + "type-required": "Type is required.", | |
227 | + "details": "Details", | |
228 | + "events": "Events", | |
229 | + "add-asset-text": "Add new asset", | |
230 | + "asset-details": "Asset details", | |
231 | + "assign-assets": "Assign assets", | |
232 | + "assign-assets-text": "Assign { count, select, 1 {1 asset} other {# assets} } to customer", | |
233 | + "delete-assets": "Delete assets", | |
234 | + "unassign-assets": "Unassign assets", | |
235 | + "unassign-assets-action-title": "Unassign { count, select, 1 {1 asset} other {# assets} } from customer", | |
236 | + "assign-new-asset": "Assign new asset", | |
237 | + "delete-asset-title": "Are you sure you want to delete the asset '{{assetName}}'?", | |
238 | + "delete-asset-text": "Be careful, after the confirmation the asset and all related data will become unrecoverable.", | |
239 | + "delete-assets-title": "Are you sure you want to delete { count, select, 1 {1 asset} other {# assets} }?", | |
240 | + "delete-assets-action-title": "Delete { count, select, 1 {1 asset} other {# assets} }", | |
241 | + "delete-assets-text": "Be careful, after the confirmation all selected assets will be removed and all related data will become unrecoverable.", | |
242 | + "make-public-asset-title": "Are you sure you want to make the asset '{{assetName}}' public?", | |
243 | + "make-public-asset-text": "After the confirmation the asset and all its data will be made public and accessible by others.", | |
244 | + "make-private-asset-title": "Are you sure you want to make the asset '{{assetName}}' private?", | |
245 | + "make-private-asset-text": "After the confirmation the asset and all its data will be made private and won't be accessible by others.", | |
246 | + "unassign-asset-title": "Are you sure you want to unassign the asset '{{assetName}}'?", | |
247 | + "unassign-asset-text": "After the confirmation the asset will be unassigned and won't be accessible by the customer.", | |
248 | + "unassign-asset": "Unassign asset", | |
249 | + "unassign-assets-title": "Are you sure you want to unassign { count, select, 1 {1 asset} other {# assets} }?", | |
250 | + "unassign-assets-text": "After the confirmation all selected assets will be unassigned and won't be accessible by the customer.", | |
251 | + "copyId": "Copy asset Id", | |
252 | + "idCopiedMessage": "Asset Id has been copied to clipboard", | |
253 | + "select-asset": "Select asset", | |
254 | + "no-assets-matching": "No assets matching '{{entity}}' were found.", | |
255 | + "asset-required": "Asset is required", | |
256 | + "name-starts-with": "Asset name starts with" | |
257 | + }, | |
98 | 258 | "attribute": { |
99 | 259 | "attributes": "속성", |
100 | 260 | "latest-telemetry": "최근 데이터", |
... | ... | @@ -104,9 +264,9 @@ export default function addLocaleKorean(locales) { |
104 | 264 | "scope-server": "서버 속성", |
105 | 265 | "scope-shared": "공유 속성", |
106 | 266 | "add": "속성 추가", |
107 | - "key": "Key", | |
267 | + "key": "Key", // TODO | |
108 | 268 | "key-required": "속성 key를 입력하세요.", |
109 | - "value": "Value", | |
269 | + "value": "Value", // TODO | |
110 | 270 | "value-required": "속성 value를 입력하세요.", |
111 | 271 | "delete-attributes-title": "{ count, select, 1 {속성} other {여러 속성들을} } 삭제하시겠습니까??", |
112 | 272 | "delete-attributes-text": "모든 선택된 속성들이 제거 될 것이므로 주의하십시오.", |
... | ... | @@ -121,6 +281,38 @@ export default function addLocaleKorean(locales) { |
121 | 281 | "selected-attributes": "{ count, select, 1 {속성 1개} other {속성 #개} } 선택됨", |
122 | 282 | "selected-telemetry": "{ count, select, 1 {최근 데이터 1개} other {최근 데이터 #개} } 선택됨" |
123 | 283 | }, |
284 | + "audit-log": { // TODO | |
285 | + "audit": "Audit", | |
286 | + "audit-logs": "Audit Logs", | |
287 | + "timestamp": "Timestamp", | |
288 | + "entity-type": "Entity Type", | |
289 | + "entity-name": "Entity Name", | |
290 | + "user": "User", | |
291 | + "type": "Type", | |
292 | + "status": "Status", | |
293 | + "details": "Details", | |
294 | + "type-added": "Added", | |
295 | + "type-deleted": "Deleted", | |
296 | + "type-updated": "Updated", | |
297 | + "type-attributes-updated": "Attributes updated", | |
298 | + "type-attributes-deleted": "Attributes deleted", | |
299 | + "type-rpc-call": "RPC call", | |
300 | + "type-credentials-updated": "Credentials updated", | |
301 | + "type-assigned-to-customer": "Assigned to Customer", | |
302 | + "type-unassigned-from-customer": "Unassigned from Customer", | |
303 | + "type-activated": "Activated", | |
304 | + "type-suspended": "Suspended", | |
305 | + "type-credentials-read": "Credentials read", | |
306 | + "type-attributes-read": "Attributes read", | |
307 | + "status-success": "Success", | |
308 | + "status-failure": "Failure", | |
309 | + "audit-log-details": "Audit log details", | |
310 | + "no-audit-logs-prompt": "No logs found", | |
311 | + "action-data": "Action data", | |
312 | + "failure-details": "Failure details", | |
313 | + "search": "Search audit logs", | |
314 | + "clear-search": "Clear search" | |
315 | + }, | |
124 | 316 | "confirm-on-exit": { |
125 | 317 | "message": "변경 사항을 저장하지 않았습니다. 이 페이지를 나가시겠습니까?", |
126 | 318 | "html-message": "변경 사항을 저장하지 않았습니다.<br/>이 페이지를 나가시겠습니까?", |
... | ... | @@ -145,6 +337,11 @@ export default function addLocaleKorean(locales) { |
145 | 337 | "enter-password": "비밀번호를 입력하세요.", |
146 | 338 | "enter-search": "검색어 입력" |
147 | 339 | }, |
340 | + "content-type": { // TODO | |
341 | + "json": "Json", | |
342 | + "text": "Text", | |
343 | + "binary": "Binary (Base64)" | |
344 | + }, | |
148 | 345 | "customer": { |
149 | 346 | "customers": "커스터머", |
150 | 347 | "management": "커스터머 관리", |
... | ... | @@ -156,6 +353,10 @@ export default function addLocaleKorean(locales) { |
156 | 353 | "manage-customer-users": "커스터머 사용자 관리", |
157 | 354 | "manage-customer-devices": "커스터머 디바이스 관리", |
158 | 355 | "manage-customer-dashboards": "커스터머 대시보드 관리", |
356 | + "manage-public-devices": "Manage public devices", // TODO | |
357 | + "manage-public-dashboards": "Manage public dashboards", // TODO | |
358 | + "manage-customer-assets": "Manage customer assets", // TODO | |
359 | + "manage-public-assets": "Manage public assets", // TODO | |
159 | 360 | "add-customer-text": "커스터머 추가", |
160 | 361 | "no-customers-text": "커스터머가 없습니다.", |
161 | 362 | "customer-details": "커스터머 상세정보", |
... | ... | @@ -169,7 +370,17 @@ export default function addLocaleKorean(locales) { |
169 | 370 | "manage-dashboards": "대시보드 관리", |
170 | 371 | "title": "타이틀", |
171 | 372 | "title-required": "타이틀을 입력하세요.", |
172 | - "description": "설명" | |
373 | + "description": "설명", | |
374 | + "details": "Details", | |
375 | + "events": "Events", | |
376 | + "copyId": "Copy customer Id", | |
377 | + "idCopiedMessage": "Customer Id has been copied to clipboard", | |
378 | + "select-customer": "Select customer", | |
379 | + "no-customers-matching": "No customers matching '{{entity}}' were found.", | |
380 | + "customer-required": "Customer is required", | |
381 | + "select-default-customer": "Select default customer", | |
382 | + "default-customer": "Default customer", | |
383 | + "default-customer-required": "Default customer is required in order to debug dashboard on Tenant level" | |
173 | 384 | }, |
174 | 385 | "datetime": { |
175 | 386 | "date-from": "시작 날짜", |
... | ... | @@ -277,11 +488,15 @@ export default function addLocaleKorean(locales) { |
277 | 488 | "attributes": "Attributes", |
278 | 489 | "timeseries-required": "디바이스 timeseries 를 입력하세요.", |
279 | 490 | "timeseries-or-attributes-required": "디바이스 timeseries/attributes 를 입력하세요.", |
491 | + "maximum-timeseries-or-attributes": "Maximum { count, select, 1 {1 timeseries/attribute is allowed.} other {# timeseries/attributes are allowed} }", // TODO | |
492 | + "alarm-fields-required": "Alarm fields are required.", // TODO | |
280 | 493 | "function-types": "함수 유형", |
281 | - "function-types-required": "함수 유형을 입력하세요." | |
494 | + "function-types-required": "함수 유형을 입력하세요.", | |
495 | + "maximum-function-types": "Maximum { count, select, 1 {1 function type is allowed.} other {# function types are allowed} }" // TODO | |
282 | 496 | }, |
283 | 497 | "datasource": { |
284 | 498 | "type": "데이터소스 유형", |
499 | + "name": "Name", // TODO | |
285 | 500 | "add-datasource-prompt": "데이터소스를 추가하세요." |
286 | 501 | }, |
287 | 502 | "details": { |
... | ... | @@ -375,11 +590,101 @@ export default function addLocaleKorean(locales) { |
375 | 590 | "unhandled-error-code": "처리되지 않은 오류 코드: {{errorCode}}", |
376 | 591 | "unknown-error": "알 수 없는 오류" |
377 | 592 | }, |
593 | + "entity": { // TODO | |
594 | + "entity": "Entity", | |
595 | + "entities": "Entities", | |
596 | + "aliases": "Entity aliases", | |
597 | + "entity-alias": "Entity alias", | |
598 | + "unable-delete-entity-alias-title": "Unable to delete entity alias", | |
599 | + "unable-delete-entity-alias-text": "Entity alias '{{entityAlias}}' can't be deleted as it used by the following widget(s):<br/>{{widgetsList}}", | |
600 | + "duplicate-alias-error": "Duplicate alias found '{{alias}}'.<br>Entity aliases must be unique whithin the dashboard.", | |
601 | + "missing-entity-filter-error": "Filter is missing for alias '{{alias}}'.", | |
602 | + "configure-alias": "Configure '{{alias}}' alias", | |
603 | + "alias": "Alias", | |
604 | + "alias-required": "Entity alias is required.", | |
605 | + "remove-alias": "Remove entity alias", | |
606 | + "add-alias": "Add entity alias", | |
607 | + "entity-list": "Entity list", | |
608 | + "entity-type": "Entity type", | |
609 | + "entity-types": "Entity types", | |
610 | + "entity-type-list": "Entity type list", | |
611 | + "any-entity": "Any entity", | |
612 | + "enter-entity-type": "Enter entity type", | |
613 | + "no-entities-matching": "No entities matching '{{entity}}' were found.", | |
614 | + "no-entity-types-matching": "No entity types matching '{{entityType}}' were found.", | |
615 | + "name-starts-with": "Name starts with", | |
616 | + "use-entity-name-filter": "Use filter", | |
617 | + "entity-list-empty": "No entities selected.", | |
618 | + "entity-type-list-empty": "No entity types selected.", | |
619 | + "entity-name-filter-required": "Entity name filter is required.", | |
620 | + "entity-name-filter-no-entity-matched": "No entities starting with '{{entity}}' were found.", | |
621 | + "all-subtypes": "All", | |
622 | + "select-entities": "Select entities", | |
623 | + "no-aliases-found": "No aliases found.", | |
624 | + "no-alias-matching": "'{{alias}}' not found.", | |
625 | + "create-new-alias": "Create a new one!", | |
626 | + "key": "Key", | |
627 | + "key-name": "Key name", | |
628 | + "no-keys-found": "No keys found.", | |
629 | + "no-key-matching": "'{{key}}' not found.", | |
630 | + "create-new-key": "Create a new one!", | |
631 | + "type": "Type", | |
632 | + "type-required": "Entity type is required.", | |
633 | + "type-device": "Device", | |
634 | + "type-devices": "Devices", | |
635 | + "list-of-devices": "{ count, select, 1 {One device} other {List of # devices} }", | |
636 | + "device-name-starts-with": "Devices whose names start with '{{prefix}}'", | |
637 | + "type-asset": "Asset", | |
638 | + "type-assets": "Assets", | |
639 | + "list-of-assets": "{ count, select, 1 {One asset} other {List of # assets} }", | |
640 | + "asset-name-starts-with": "Assets whose names start with '{{prefix}}'", | |
641 | + "type-rule": "Rule", | |
642 | + "type-rules": "Rules", | |
643 | + "list-of-rules": "{ count, select, 1 {One rule} other {List of # rules} }", | |
644 | + "rule-name-starts-with": "Rules whose names start with '{{prefix}}'", | |
645 | + "type-plugin": "Plugin", | |
646 | + "type-plugins": "Plugins", | |
647 | + "list-of-plugins": "{ count, select, 1 {One plugin} other {List of # plugins} }", | |
648 | + "plugin-name-starts-with": "Plugins whose names start with '{{prefix}}'", | |
649 | + "type-tenant": "Tenant", | |
650 | + "type-tenants": "Tenants", | |
651 | + "list-of-tenants": "{ count, select, 1 {One tenant} other {List of # tenants} }", | |
652 | + "tenant-name-starts-with": "Tenants whose names start with '{{prefix}}'", | |
653 | + "type-customer": "Customer", | |
654 | + "type-customers": "Customers", | |
655 | + "list-of-customers": "{ count, select, 1 {One customer} other {List of # customers} }", | |
656 | + "customer-name-starts-with": "Customers whose names start with '{{prefix}}'", | |
657 | + "type-user": "User", | |
658 | + "type-users": "Users", | |
659 | + "list-of-users": "{ count, select, 1 {One user} other {List of # users} }", | |
660 | + "user-name-starts-with": "Users whose names start with '{{prefix}}'", | |
661 | + "type-dashboard": "Dashboard", | |
662 | + "type-dashboards": "Dashboards", | |
663 | + "list-of-dashboards": "{ count, select, 1 {One dashboard} other {List of # dashboards} }", | |
664 | + "dashboard-name-starts-with": "Dashboards whose names start with '{{prefix}}'", | |
665 | + "type-alarm": "Alarm", | |
666 | + "type-alarms": "Alarms", | |
667 | + "list-of-alarms": "{ count, select, 1 {One alarms} other {List of # alarms} }", | |
668 | + "alarm-name-starts-with": "Alarms whose names start with '{{prefix}}'", | |
669 | + "type-rulechain": "Rule chain", | |
670 | + "type-rulechains": "Rule chains", | |
671 | + "list-of-rulechains": "{ count, select, 1 {One rule chain} other {List of # rule chains} }", | |
672 | + "rulechain-name-starts-with": "Rule chains whose names start with '{{prefix}}'", | |
673 | + "type-current-customer": "Current Customer", | |
674 | + "search": "Search entities", | |
675 | + "selected-entities": "{ count, select, 1 {1 entity} other {# entities} } selected", | |
676 | + "entity-name": "Entity name", | |
677 | + "details": "Entity details", | |
678 | + "no-entities-prompt": "No entities found", | |
679 | + "no-data": "No data to display" | |
680 | + }, | |
378 | 681 | "event": { |
379 | 682 | "event-type": "이벤트 타입", |
380 | 683 | "type-error": "에러", |
381 | 684 | "type-lc-event": "주기적 이벤트", |
382 | 685 | "type-stats": "통계", |
686 | + "type-debug-rule-node": "Debug", // TODO | |
687 | + "type-debug-rule-chain": "Debug", // TODO | |
383 | 688 | "no-events-prompt": "이벤트 없음", |
384 | 689 | "error": "에러", |
385 | 690 | "alarm": "알람", |
... | ... | @@ -387,6 +692,14 @@ export default function addLocaleKorean(locales) { |
387 | 692 | "server": "서버", |
388 | 693 | "body": "Body", |
389 | 694 | "method": "Method", |
695 | + "type": "Type", // TODO | |
696 | + "entity": "Entity", // TODO | |
697 | + "message-id": "Message Id", // TODO | |
698 | + "message-type": "Message Type", // TODO | |
699 | + "data-type": "Data Type", // TODO | |
700 | + "relation-type": "Relation Type", // TODO | |
701 | + "metadata": "Metadata", // TODO | |
702 | + "data": "Data", // TODO | |
390 | 703 | "event": "이벤트", |
391 | 704 | "status": "상태", |
392 | 705 | "success": "성공", |
... | ... | @@ -394,6 +707,163 @@ export default function addLocaleKorean(locales) { |
394 | 707 | "messages-processed": "처리된 메시지", |
395 | 708 | "errors-occurred": "오류가 발생했습니다" |
396 | 709 | }, |
710 | + "extension": { // TODO | |
711 | + "extensions": "Extensions", | |
712 | + "selected-extensions": "{ count, select, 1 {1 extension} other {# extensions} } selected", | |
713 | + "type": "Type", | |
714 | + "key": "Key", | |
715 | + "value": "Value", | |
716 | + "id": "Id", | |
717 | + "extension-id": "Extension id", | |
718 | + "extension-type": "Extension type", | |
719 | + "transformer-json": "JSON *", | |
720 | + "unique-id-required": "Current extension id already exists.", | |
721 | + "delete": "Delete extension", | |
722 | + "add": "Add extension", | |
723 | + "edit": "Edit extension", | |
724 | + "delete-extension-title": "Are you sure you want to delete the extension '{{extensionId}}'?", | |
725 | + "delete-extension-text": "Be careful, after the confirmation the extension and all related data will become unrecoverable.", | |
726 | + "delete-extensions-title": "Are you sure you want to delete { count, select, 1 {1 extension} other {# extensions} }?", | |
727 | + "delete-extensions-text": "Be careful, after the confirmation all selected extensions will be removed.", | |
728 | + "converters": "Converters", | |
729 | + "converter-id": "Converter id", | |
730 | + "configuration": "Configuration", | |
731 | + "converter-configurations": "Converter configurations", | |
732 | + "token": "Security token", | |
733 | + "add-converter": "Add converter", | |
734 | + "add-config": "Add converter configuration", | |
735 | + "device-name-expression": "Device name expression", | |
736 | + "device-type-expression": "Device type expression", | |
737 | + "custom": "Custom", | |
738 | + "to-double": "To Double", | |
739 | + "transformer": "Transformer", | |
740 | + "json-required": "Transformer json is required.", | |
741 | + "json-parse": "Unable to parse transformer json.", | |
742 | + "attributes": "Attributes", | |
743 | + "add-attribute": "Add attribute", | |
744 | + "add-map": "Add mapping element", | |
745 | + "timeseries": "Timeseries", | |
746 | + "add-timeseries": "Add timeseries", | |
747 | + "field-required": "Field is required", | |
748 | + "brokers": "Brokers", | |
749 | + "add-broker": "Add broker", | |
750 | + "host": "Host", | |
751 | + "port": "Port", | |
752 | + "port-range": "Port should be in a range from 1 to 65535.", | |
753 | + "ssl": "Ssl", | |
754 | + "credentials": "Credentials", | |
755 | + "username": "Username", | |
756 | + "password": "Password", | |
757 | + "retry-interval": "Retry interval in milliseconds", | |
758 | + "anonymous": "Anonymous", | |
759 | + "basic": "Basic", | |
760 | + "pem": "PEM", | |
761 | + "ca-cert": "CA certificate file *", | |
762 | + "private-key": "Private key file *", | |
763 | + "cert": "Certificate file *", | |
764 | + "no-file": "No file selected.", | |
765 | + "drop-file": "Drop a file or click to select a file to upload.", | |
766 | + "mapping": "Mapping", | |
767 | + "topic-filter": "Topic filter", | |
768 | + "converter-type": "Converter type", | |
769 | + "converter-json": "Json", | |
770 | + "json-name-expression": "Device name json expression", | |
771 | + "topic-name-expression": "Device name topic expression", | |
772 | + "json-type-expression": "Device type json expression", | |
773 | + "topic-type-expression": "Device type topic expression", | |
774 | + "attribute-key-expression": "Attribute key expression", | |
775 | + "attr-json-key-expression": "Attribute key json expression", | |
776 | + "attr-topic-key-expression": "Attribute key topic expression", | |
777 | + "request-id-expression": "Request id expression", | |
778 | + "request-id-json-expression": "Request id json expression", | |
779 | + "request-id-topic-expression": "Request id topic expression", | |
780 | + "response-topic-expression": "Response topic expression", | |
781 | + "value-expression": "Value expression", | |
782 | + "topic": "Topic", | |
783 | + "timeout": "Timeout in milliseconds", | |
784 | + "converter-json-required": "Converter json is required.", | |
785 | + "converter-json-parse": "Unable to parse converter json.", | |
786 | + "filter-expression": "Filter expression", | |
787 | + "connect-requests": "Connect requests", | |
788 | + "add-connect-request": "Add connect request", | |
789 | + "disconnect-requests": "Disconnect requests", | |
790 | + "add-disconnect-request": "Add disconnect request", | |
791 | + "attribute-requests": "Attribute requests", | |
792 | + "add-attribute-request": "Add attribute request", | |
793 | + "attribute-updates": "Attribute updates", | |
794 | + "add-attribute-update": "Add attribute update", | |
795 | + "server-side-rpc": "Server side RPC", | |
796 | + "add-server-side-rpc-request": "Add server-side RPC request", | |
797 | + "device-name-filter": "Device name filter", | |
798 | + "attribute-filter": "Attribute filter", | |
799 | + "method-filter": "Method filter", | |
800 | + "request-topic-expression": "Request topic expression", | |
801 | + "response-timeout": "Response timeout in milliseconds", | |
802 | + "topic-expression": "Topic expression", | |
803 | + "client-scope": "Client scope", | |
804 | + "add-device": "Add device", | |
805 | + "opc-server": "Servers", | |
806 | + "opc-add-server": "Add server", | |
807 | + "opc-add-server-prompt": "Please add server", | |
808 | + "opc-application-name": "Application name", | |
809 | + "opc-application-uri": "Application uri", | |
810 | + "opc-scan-period-in-seconds": "Scan period in seconds", | |
811 | + "opc-security": "Security", | |
812 | + "opc-identity": "Identity", | |
813 | + "opc-keystore": "Keystore", | |
814 | + "opc-type": "Type", | |
815 | + "opc-keystore-type": "Type", | |
816 | + "opc-keystore-location": "Location *", | |
817 | + "opc-keystore-password": "Password", | |
818 | + "opc-keystore-alias": "Alias", | |
819 | + "opc-keystore-key-password": "Key password", | |
820 | + "opc-device-node-pattern": "Device node pattern", | |
821 | + "opc-device-name-pattern": "Device name pattern", | |
822 | + "modbus-server": "Servers/slaves", | |
823 | + "modbus-add-server": "Add server/slave", | |
824 | + "modbus-add-server-prompt": "Please add server/slave", | |
825 | + "modbus-transport": "Transport", | |
826 | + "modbus-port-name": "Serial port name", | |
827 | + "modbus-encoding": "Encoding", | |
828 | + "modbus-parity": "Parity", | |
829 | + "modbus-baudrate": "Baud rate", | |
830 | + "modbus-databits": "Data bits", | |
831 | + "modbus-stopbits": "Stop bits", | |
832 | + "modbus-databits-range": "Data bits should be in a range from 7 to 8.", | |
833 | + "modbus-stopbits-range": "Stop bits should be in a range from 1 to 2.", | |
834 | + "modbus-unit-id": "Unit ID", | |
835 | + "modbus-unit-id-range": "Unit ID should be in a range from 1 to 247.", | |
836 | + "modbus-device-name": "Device name", | |
837 | + "modbus-poll-period": "Poll period (ms)", | |
838 | + "modbus-attributes-poll-period": "Attributes poll period (ms)", | |
839 | + "modbus-timeseries-poll-period": "Timeseries poll period (ms)", | |
840 | + "modbus-poll-period-range": "Poll period should be positive value.", | |
841 | + "modbus-tag": "Tag", | |
842 | + "modbus-function": "Function", | |
843 | + "modbus-register-address": "Register address", | |
844 | + "modbus-register-address-range": "Register address should be in a range from 0 to 65535.", | |
845 | + "modbus-register-bit-index": "Bit index", | |
846 | + "modbus-register-bit-index-range": "Bit index should be in a range from 0 to 15.", | |
847 | + "modbus-register-count": "Register count", | |
848 | + "modbus-register-count-range": "Register count should be a positive value.", | |
849 | + "modbus-byte-order": "Byte order", | |
850 | + | |
851 | + "sync": { | |
852 | + "status": "Status", | |
853 | + "sync": "Sync", | |
854 | + "not-sync": "Not sync", | |
855 | + "last-sync-time": "Last sync time", | |
856 | + "not-available": "Not available" | |
857 | + }, | |
858 | + | |
859 | + "export-extensions-configuration": "Export extensions configuration", | |
860 | + "import-extensions-configuration": "Import extensions configuration", | |
861 | + "import-extensions": "Import extensions", | |
862 | + "import-extension": "Import extension", | |
863 | + "export-extension": "Export extension", | |
864 | + "file": "Extensions file", | |
865 | + "invalid-file-error": "Invalid extension file" | |
866 | + }, | |
397 | 867 | "fullscreen": { |
398 | 868 | "expand": "전체화면으로 확장", |
399 | 869 | "exit": "전체화면 종료", |
... | ... | @@ -436,7 +906,24 @@ export default function addLocaleKorean(locales) { |
436 | 906 | }, |
437 | 907 | "js-func": { |
438 | 908 | "no-return-error": "함수는 값을 반환해야 합니다!", |
439 | - "return-type-mismatch": "함수는 '{{type}}' 유형의 값을 반환해야 합니다!" | |
909 | + "return-type-mismatch": "함수는 '{{type}}' 유형의 값을 반환해야 합니다!", | |
910 | + "tidy": "Tidy" // TODO | |
911 | + }, | |
912 | + "key-val": { // TODO | |
913 | + "key": "Key", | |
914 | + "value": "Value", | |
915 | + "remove-entry": "Remove entry", | |
916 | + "add-entry": "Add entry", | |
917 | + "no-data": "No entries" | |
918 | + }, | |
919 | + "layout": { // TODO | |
920 | + "layout": "Layout", | |
921 | + "manage": "Manage layouts", | |
922 | + "settings": "Layout settings", | |
923 | + "color": "Color", | |
924 | + "main": "Main", | |
925 | + "right": "Right", | |
926 | + "select": "Select target layout" | |
440 | 927 | }, |
441 | 928 | "legend": { |
442 | 929 | "position": "범례 위치", |
... | ... | @@ -467,45 +954,6 @@ export default function addLocaleKorean(locales) { |
467 | 954 | "password-link-sent-message": "비밀번호 재설정 링크가 성공적으로 전송되었습니다!", |
468 | 955 | "email": "이메일" |
469 | 956 | }, |
470 | - "plugin": { | |
471 | - "plugins": "플러그인", | |
472 | - "delete": "플러그인 삭제", | |
473 | - "activate": "플러그인 활성화", | |
474 | - "suspend": "플러그인 비활성화", | |
475 | - "active": "활성화", | |
476 | - "suspended": "비활성화", | |
477 | - "name": "이름", | |
478 | - "name-required": "이름을 입력하세요.", | |
479 | - "description": "설명", | |
480 | - "add": "플러그인 추가", | |
481 | - "delete-plugin-title": "'{{pluginName}}' 플러그인을 삭제하시겠습니까?", | |
482 | - "delete-plugin-text": "플러그인과 관련된 모든 데이터를 복구할 수 없으므로 주의하십시오.", | |
483 | - "delete-plugins-title": "{ count, select, 1 {플러그인 1개} other {플러그인 #개} }를 삭제하시겠습니까?", | |
484 | - "delete-plugins-action-title": "{ count, select, 1 {플러그인 1개} other {플러그인 #개} } 삭제", | |
485 | - "delete-plugins-text": "선택된 플러그인이 삭제되고 관련된 모든 데이터가 없어지므로 주의하십시오.", | |
486 | - "add-plugin-text": "새로운 플러그인 추가", | |
487 | - "no-plugins-text": "플러그인이 없습니다.", | |
488 | - "plugin-details": "플러그인 상세정보", | |
489 | - "api-token": "API 토큰", | |
490 | - "api-token-required": "API 토큰을 입력하세요.", | |
491 | - "type": "플러그인 종류", | |
492 | - "type-required": "플러그인 종류를 선택해주세요.", | |
493 | - "configuration": "플러그인 구성", | |
494 | - "system": "시스템", | |
495 | - "select-plugin": "플러그인 선택", | |
496 | - "plugin": "플러그인", | |
497 | - "no-plugins-matching": "'{{entity}}'과 일치하는 플러그인을 찾을 수 없습니다.", | |
498 | - "plugin-required": "플러그인을 입력하세요.", | |
499 | - "plugin-require-match": "기존의 플러그인을 선택해주세요.", | |
500 | - "events": "이벤트", | |
501 | - "details": "상세", | |
502 | - "import": "플러그인 가져오기", | |
503 | - "export": "플러그인 내보내기", | |
504 | - "export-failed-error": "플러그인을 내보내기 할 수 없습니다.: {{error}}", | |
505 | - "create-new-plugin": "새로운 플러그인 생성", | |
506 | - "plugin-file": "플러그인 파일", | |
507 | - "invalid-plugin-file-error": "플러그인을 가져오기 할 수 없습니다.: 잘못된 플러그인 데이터 구조입니다." | |
508 | - }, | |
509 | 957 | "position": { |
510 | 958 | "top": "상단", |
511 | 959 | "bottom": "하단", |
... | ... | @@ -517,60 +965,139 @@ export default function addLocaleKorean(locales) { |
517 | 965 | "change-password": "비밀번호 변경", |
518 | 966 | "current-password": "현재 비밀번호" |
519 | 967 | }, |
520 | - "rule": { | |
521 | - "rules": "규칙", | |
522 | - "delete": "규칙 삭제", | |
523 | - "activate": "규칙 활성화", | |
524 | - "suspend": "규칙 비활성화", | |
525 | - "active": "활성화", | |
526 | - "suspended": "비활성화", | |
527 | - "name": "이름", | |
528 | - "name-required": "이름을 입력하세요.", | |
529 | - "description": "설명", | |
530 | - "add": "규칙 추가", | |
531 | - "delete-rule-title": "'{{ruleName}}' 규칙을 삭제하시겠습니까?", | |
532 | - "delete-rule-text": "규칙과 관련된 모든 데이터를 복구할 수 없으므로 주의하십시오.", | |
533 | - "delete-rules-title": "{ count, select, 1 {규칙 1개} other {규칙 #개} }를 삭제하시겠습니까?", | |
534 | - "delete-rules-action-title": "{ count, select, 1 {규칙 1개} other {규칙 #개} } 삭제", | |
535 | - "delete-rules-text": "선택된 규칙이 삭제되고 관련된 모든 데이터를 복구할 수 없으므로 주의하십시오.", | |
536 | - "add-rule-text": "규칙 추가", | |
537 | - "no-rules-text": "규칙이 없습니다.", | |
538 | - "rule-details": "규칙 상세정보", | |
539 | - "filters": "필터", | |
540 | - "filter": "필터", | |
541 | - "add-filter-prompt": "필터를 추가해 주세요.", | |
542 | - "remove-filter": "필터 삭제", | |
543 | - "add-filter": "필터 추가", | |
544 | - "filter-name": "필터 이름", | |
545 | - "filter-type": "필터 종류", | |
546 | - "edit-filter": "필터 수정", | |
547 | - "view-filter": "필터 보기", | |
548 | - "component-name": "이름", | |
549 | - "component-name-required": "이름을 입력하세요.", | |
550 | - "component-type": "종류", | |
551 | - "component-type-required": "타입을 입력하세요.", | |
552 | - "processor": "프로세서", | |
553 | - "no-processor-configured": "프로세서가 구성되지 않았습니다.", | |
554 | - "create-processor": "프로세서 생성", | |
555 | - "processor-name": "프로세서 이름", | |
556 | - "processor-type": "프로세서 종류", | |
557 | - "plugin-action": "플러그인 액션", | |
558 | - "action-name": "액션 이름", | |
559 | - "action-type": "액션 종류", | |
560 | - "create-action-prompt": "액션을 만들어 주세요", | |
561 | - "create-action": "액션 생성", | |
562 | - "details": "상세", | |
563 | - "events": "이벤트", | |
564 | - "system": "시스템", | |
565 | - "import": "규칙 가져오기", | |
566 | - "export": "규칙 내보내기", | |
567 | - "export-failed-error": "규칙을 내보내기 할 수 없습니다.: {{error}}", | |
568 | - "create-new-rule": "새로운 규칙 생성", | |
569 | - "rule-file": "규칙 파일", | |
570 | - "invalid-rule-file-error": "규칙을 가져오기 할 수 없습니다.: 잘못된 데이터 구조입니다." | |
968 | + "relation": { // TODO | |
969 | + "relations": "Relations", | |
970 | + "direction": "Direction", | |
971 | + "search-direction": { | |
972 | + "FROM": "From", | |
973 | + "TO": "To" | |
974 | + }, | |
975 | + "direction-type": { | |
976 | + "FROM": "from", | |
977 | + "TO": "to" | |
978 | + }, | |
979 | + "from-relations": "Outbound relations", | |
980 | + "to-relations": "Inbound relations", | |
981 | + "selected-relations": "{ count, select, 1 {1 relation} other {# relations} } selected", | |
982 | + "type": "Type", | |
983 | + "to-entity-type": "To entity type", | |
984 | + "to-entity-name": "To entity name", | |
985 | + "from-entity-type": "From entity type", | |
986 | + "from-entity-name": "From entity name", | |
987 | + "to-entity": "To entity", | |
988 | + "from-entity": "From entity", | |
989 | + "delete": "Delete relation", | |
990 | + "relation-type": "Relation type", | |
991 | + "relation-type-required": "Relation type is required.", | |
992 | + "any-relation-type": "Any type", | |
993 | + "add": "Add relation", | |
994 | + "edit": "Edit relation", | |
995 | + "delete-to-relation-title": "Are you sure you want to delete relation to the entity '{{entityName}}'?", | |
996 | + "delete-to-relation-text": "Be careful, after the confirmation the entity '{{entityName}}' will be unrelated from the current entity.", | |
997 | + "delete-to-relations-title": "Are you sure you want to delete { count, select, 1 {1 relation} other {# relations} }?", | |
998 | + "delete-to-relations-text": "Be careful, after the confirmation all selected relations will be removed and corresponding entities will be unrelated from the current entity.", | |
999 | + "delete-from-relation-title": "Are you sure you want to delete relation from the entity '{{entityName}}'?", | |
1000 | + "delete-from-relation-text": "Be careful, after the confirmation current entity will be unrelated from the entity '{{entityName}}'.", | |
1001 | + "delete-from-relations-title": "Are you sure you want to delete { count, select, 1 {1 relation} other {# relations} }?", | |
1002 | + "delete-from-relations-text": "Be careful, after the confirmation all selected relations will be removed and current entity will be unrelated from the corresponding entities.", | |
1003 | + "remove-relation-filter": "Remove relation filter", | |
1004 | + "add-relation-filter": "Add relation filter", | |
1005 | + "any-relation": "Any relation", | |
1006 | + "relation-filters": "Relation filters", | |
1007 | + "additional-info": "Additional info (JSON)", | |
1008 | + "invalid-additional-info": "Unable to parse additional info json." | |
1009 | + }, | |
1010 | + "rulechain": { // TODO | |
1011 | + "rulechain": "Rule chain", | |
1012 | + "rulechains": "Rule chains", | |
1013 | + "root": "Root", | |
1014 | + "delete": "Delete rule chain", | |
1015 | + "name": "Name", | |
1016 | + "name-required": "Name is required.", | |
1017 | + "description": "Description", | |
1018 | + "add": "Add Rule Chain", | |
1019 | + "set-root": "Make rule chain root", | |
1020 | + "set-root-rulechain-title": "Are you sure you want to make the rule chain '{{ruleChainName}}' root?", | |
1021 | + "set-root-rulechain-text": "After the confirmation the rule chain will become root and will handle all incoming transport messages.", | |
1022 | + "delete-rulechain-title": "Are you sure you want to delete the rule chain '{{ruleChainName}}'?", | |
1023 | + "delete-rulechain-text": "Be careful, after the confirmation the rule chain and all related data will become unrecoverable.", | |
1024 | + "delete-rulechains-title": "Are you sure you want to delete { count, select, 1 {1 rule chain} other {# rule chains} }?", | |
1025 | + "delete-rulechains-action-title": "Delete { count, select, 1 {1 rule chain} other {# rule chains} }", | |
1026 | + "delete-rulechains-text": "Be careful, after the confirmation all selected rule chains will be removed and all related data will become unrecoverable.", | |
1027 | + "add-rulechain-text": "Add new rule chain", | |
1028 | + "no-rulechains-text": "No rule chains found", | |
1029 | + "rulechain-details": "Rule chain details", | |
1030 | + "details": "Details", | |
1031 | + "events": "Events", | |
1032 | + "system": "System", | |
1033 | + "import": "Import rule chain", | |
1034 | + "export": "Export rule chain", | |
1035 | + "export-failed-error": "Unable to export rule chain: {{error}}", | |
1036 | + "create-new-rulechain": "Create new rule chain", | |
1037 | + "rulechain-file": "Rule chain file", | |
1038 | + "invalid-rulechain-file-error": "Unable to import rule chain: Invalid rule chain data structure.", | |
1039 | + "copyId": "Copy rule chain Id", | |
1040 | + "idCopiedMessage": "Rule chain Id has been copied to clipboard", | |
1041 | + "select-rulechain": "Select rule chain", | |
1042 | + "no-rulechains-matching": "No rule chains matching '{{entity}}' were found.", | |
1043 | + "rulechain-required": "Rule chain is required", | |
1044 | + "management": "Rules management", | |
1045 | + "debug-mode": "Debug mode" | |
571 | 1046 | }, |
572 | - "rule-plugin": { | |
573 | - "management": "규칙 및 플러그인 관리" | |
1047 | + "rulenode": { // TODO | |
1048 | + "details": "Details", | |
1049 | + "events": "Events", | |
1050 | + "search": "Search nodes", | |
1051 | + "open-node-library": "Open node library", | |
1052 | + "add": "Add rule node", | |
1053 | + "name": "Name", | |
1054 | + "name-required": "Name is required.", | |
1055 | + "type": "Type", | |
1056 | + "description": "Description", | |
1057 | + "delete": "Delete rule node", | |
1058 | + "select-all-objects": "Select all nodes and connections", | |
1059 | + "deselect-all-objects": "Deselect all nodes and connections", | |
1060 | + "delete-selected-objects": "Delete selected nodes and connections", | |
1061 | + "delete-selected": "Delete selected", | |
1062 | + "select-all": "Select all", | |
1063 | + "copy-selected": "Copy selected", | |
1064 | + "deselect-all": "Deselect all", | |
1065 | + "rulenode-details": "Rule node details", | |
1066 | + "debug-mode": "Debug mode", | |
1067 | + "configuration": "Configuration", | |
1068 | + "link": "Link", | |
1069 | + "link-details": "Rule node link details", | |
1070 | + "add-link": "Add link", | |
1071 | + "link-label": "Link label", | |
1072 | + "link-label-required": "Link label is required.", | |
1073 | + "custom-link-label": "Custom link label", | |
1074 | + "custom-link-label-required": "Custom link label is required.", | |
1075 | + "type-filter": "Filter", | |
1076 | + "type-filter-details": "Filter incoming messages with configured conditions", | |
1077 | + "type-enrichment": "Enrichment", | |
1078 | + "type-enrichment-details": "Add additional information into Message Metadata", | |
1079 | + "type-transformation": "Transformation", | |
1080 | + "type-transformation-details": "Change Message payload and Metadata", | |
1081 | + "type-action": "Action", | |
1082 | + "type-action-details": "Perform special action", | |
1083 | + "type-external": "External", | |
1084 | + "type-external-details": "Interacts with external system", | |
1085 | + "type-rule-chain": "Rule Chain", | |
1086 | + "type-rule-chain-details": "Forwards incoming messages to specified Rule Chain", | |
1087 | + "type-input": "Input", | |
1088 | + "type-input-details": "Logical input of Rule Chain, forwards incoming messages to next related Rule Node", | |
1089 | + "directive-is-not-loaded": "Defined configuration directive '{{directiveName}}' is not available.", | |
1090 | + "ui-resources-load-error": "Failed to load configuration ui resources.", | |
1091 | + "invalid-target-rulechain": "Unable to resolve target rule chain!", | |
1092 | + "test-script-function": "Test script function", | |
1093 | + "message": "Message", | |
1094 | + "message-type": "Message type", | |
1095 | + "message-type-required": "Message type is required", | |
1096 | + "metadata": "Metadata", | |
1097 | + "metadata-required": "Metadata entries can't be empty.", | |
1098 | + "output": "Output", | |
1099 | + "test": "Test", | |
1100 | + "help": "Help" | |
574 | 1101 | }, |
575 | 1102 | "tenant": { |
576 | 1103 | "tenants": "테넌트", |
... | ... | @@ -589,7 +1116,14 @@ export default function addLocaleKorean(locales) { |
589 | 1116 | "delete-tenants-text": "선택된 테넌트가 삭제되고 관련된 모든 정보를 복구할 수 없으므로 주의하십시오.", |
590 | 1117 | "title": "타이틀", |
591 | 1118 | "title-required": "타이틀을 입력하세요.", |
592 | - "description": "설명" | |
1119 | + "description": "설명", | |
1120 | + "details": "Details", // TODO | |
1121 | + "events": "Events", // TODO | |
1122 | + "copyId": "Copy tenant Id", // TODO | |
1123 | + "idCopiedMessage": "Tenant Id has been copied to clipboard", // TODO | |
1124 | + "select-tenant": "Select tenant", // TODO | |
1125 | + "no-tenants-matching": "No tenants matching '{{entity}}' were found.", | |
1126 | + "tenant-required": "Tenant is required" // TODO | |
593 | 1127 | }, |
594 | 1128 | "timeinterval": { |
595 | 1129 | "seconds-interval": "{ seconds, select, 1 {1 second} other {# seconds} }", |
... | ... | @@ -642,7 +1176,18 @@ export default function addLocaleKorean(locales) { |
642 | 1176 | "last-name": "성", |
643 | 1177 | "description": "설명", |
644 | 1178 | "default-dashboard": "기본 대시보드", |
645 | - "always-fullscreen": "항상 전체화면" | |
1179 | + "always-fullscreen": "항상 전체화면", | |
1180 | + "select-user": "Select user", // TODO | |
1181 | + "no-users-matching": "No users matching '{{entity}}' were found.", // TODO | |
1182 | + "user-required": "User is required", // TODO | |
1183 | + "activation-method": "Activation method", // TODO | |
1184 | + "display-activation-link": "Display activation link", // TODO | |
1185 | + "send-activation-mail": "Send activation mail", // TODO | |
1186 | + "activation-link": "User activation link", // TODO | |
1187 | + "activation-link-text": "In order to activate user use the following <a href='{{activationLink}}' target='_blank'>activation link</a> :", // TODO | |
1188 | + "copy-activation-link": "Copy activation link", // TODO | |
1189 | + "activation-link-copied-message": "User activation link has been copied to clipboard", // TODO | |
1190 | + "details": "Details" // TODO | |
646 | 1191 | }, |
647 | 1192 | "value": { |
648 | 1193 | "type": "Value type", |
... | ... | @@ -707,6 +1252,18 @@ export default function addLocaleKorean(locales) { |
707 | 1252 | "undo": "위젯 변경사항 취소", |
708 | 1253 | "export": "위젯 내보내기" |
709 | 1254 | }, |
1255 | + "widget-action": { // TODO | |
1256 | + "header-button": "Widget header button", | |
1257 | + "open-dashboard-state": "Navigate to new dashboard state", | |
1258 | + "update-dashboard-state": "Update current dashboard state", | |
1259 | + "open-dashboard": "Navigate to other dashboard", | |
1260 | + "custom": "Custom action", | |
1261 | + "target-dashboard-state": "Target dashboard state", | |
1262 | + "target-dashboard-state-required": "Target dashboard state is required", | |
1263 | + "set-entity-from-widget": "Set entity from widget", | |
1264 | + "target-dashboard": "Target dashboard", | |
1265 | + "open-right-layout": "Open right dashboard layout (mobile view)" | |
1266 | + }, | |
710 | 1267 | "widgets-bundle": { |
711 | 1268 | "current": "현재 번들", |
712 | 1269 | "widgets-bundles": "위젯 번들", |
... | ... | @@ -770,6 +1327,20 @@ export default function addLocaleKorean(locales) { |
770 | 1327 | "widget-type-file": "위젯 타입 파일", |
771 | 1328 | "invalid-widget-type-file-error": "위젯 타입을 가져오기 할 수 없습니다.: 잘못된 위젯 타입 데이터 구조입니다." |
772 | 1329 | }, |
1330 | + "icon": { // TODO | |
1331 | + "icon": "Icon", | |
1332 | + "select-icon": "Select icon", | |
1333 | + "material-icons": "Material icons", | |
1334 | + "show-all": "Show all icons" | |
1335 | + }, | |
1336 | + "custom": { | |
1337 | + "widget-action": { | |
1338 | + "action-cell-button": "Action cell button", | |
1339 | + "row-click": "On row click", | |
1340 | + "marker-click": "On marker click", | |
1341 | + "tooltip-tag-action": "Tooltip tag action" | |
1342 | + } | |
1343 | + }, | |
773 | 1344 | "language": { |
774 | 1345 | "language": "언어", |
775 | 1346 | "en_US": "영어", |
... | ... | @@ -779,5 +1350,5 @@ export default function addLocaleKorean(locales) { |
779 | 1350 | "es_ES": "스페인어" |
780 | 1351 | } |
781 | 1352 | }; |
782 | - angular.extend(locales, {'ko_KR': ko_KR}); | |
1353 | + angular.extend(locales, { 'ko_KR': ko_KR }); | |
783 | 1354 | } |
\ No newline at end of file | ... | ... |