Commit c2bd4117e440da4c1a2ff982e31ae7ae45e23ef2
Merge branch 'master' of https://github.com/thingsboard/thingsboard
Showing
18 changed files
with
210 additions
and
107 deletions
1 | +/** | ||
2 | + * Copyright © 2016-2020 The Thingsboard Authors | ||
3 | + * | ||
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | + * you may not use this file except in compliance with the License. | ||
6 | + * You may obtain a copy of the License at | ||
7 | + * | ||
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * | ||
10 | + * Unless required by applicable law or agreed to in writing, software | ||
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | + * See the License for the specific language governing permissions and | ||
14 | + * limitations under the License. | ||
15 | + */ | ||
16 | +package org.thingsboard.server.queue.util; | ||
17 | + | ||
18 | +import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; | ||
19 | + | ||
20 | +import java.lang.annotation.Retention; | ||
21 | +import java.lang.annotation.RetentionPolicy; | ||
22 | + | ||
23 | +@Retention(RetentionPolicy.RUNTIME) | ||
24 | +@ConditionalOnExpression("('${service.type:null}'=='monolith' && '${transport.api_enabled:true}'=='true') || '${service.type:null}'=='tb-transport'") | ||
25 | +public @interface TbTransportComponent { | ||
26 | +} |
@@ -20,6 +20,7 @@ import org.thingsboard.server.common.data.DeviceTransportType; | @@ -20,6 +20,7 @@ import org.thingsboard.server.common.data.DeviceTransportType; | ||
20 | import org.thingsboard.server.common.data.id.DeviceProfileId; | 20 | import org.thingsboard.server.common.data.id.DeviceProfileId; |
21 | import org.thingsboard.server.common.transport.auth.GetOrCreateDeviceFromGatewayResponse; | 21 | import org.thingsboard.server.common.transport.auth.GetOrCreateDeviceFromGatewayResponse; |
22 | import org.thingsboard.server.common.transport.auth.ValidateDeviceCredentialsResponse; | 22 | import org.thingsboard.server.common.transport.auth.ValidateDeviceCredentialsResponse; |
23 | +import org.thingsboard.server.common.transport.limits.TransportRateLimitType; | ||
23 | import org.thingsboard.server.gen.transport.TransportProtos; | 24 | import org.thingsboard.server.gen.transport.TransportProtos; |
24 | import org.thingsboard.server.gen.transport.TransportProtos.ClaimDeviceMsg; | 25 | import org.thingsboard.server.gen.transport.TransportProtos.ClaimDeviceMsg; |
25 | import org.thingsboard.server.gen.transport.TransportProtos.GetAttributeRequestMsg; | 26 | import org.thingsboard.server.gen.transport.TransportProtos.GetAttributeRequestMsg; |
@@ -69,6 +70,8 @@ public interface TransportService { | @@ -69,6 +70,8 @@ public interface TransportService { | ||
69 | 70 | ||
70 | boolean checkLimits(SessionInfoProto sessionInfo, Object msg, TransportServiceCallback<Void> callback); | 71 | boolean checkLimits(SessionInfoProto sessionInfo, Object msg, TransportServiceCallback<Void> callback); |
71 | 72 | ||
73 | + boolean checkLimits(SessionInfoProto sessionInfo, Object msg, TransportServiceCallback<Void> callback, int dataPoints, TransportRateLimitType... limits); | ||
74 | + | ||
72 | void process(SessionInfoProto sessionInfo, SessionEventMsg msg, TransportServiceCallback<Void> callback); | 75 | void process(SessionInfoProto sessionInfo, SessionEventMsg msg, TransportServiceCallback<Void> callback); |
73 | 76 | ||
74 | void process(SessionInfoProto sessionInfo, PostTelemetryMsg msg, TransportServiceCallback<Void> callback); | 77 | void process(SessionInfoProto sessionInfo, PostTelemetryMsg msg, TransportServiceCallback<Void> callback); |
@@ -23,11 +23,13 @@ import org.thingsboard.server.common.data.id.DeviceId; | @@ -23,11 +23,13 @@ import org.thingsboard.server.common.data.id.DeviceId; | ||
23 | import org.thingsboard.server.common.data.id.TenantId; | 23 | import org.thingsboard.server.common.data.id.TenantId; |
24 | import org.thingsboard.server.common.transport.TransportTenantProfileCache; | 24 | import org.thingsboard.server.common.transport.TransportTenantProfileCache; |
25 | import org.thingsboard.server.common.transport.profile.TenantProfileUpdateResult; | 25 | import org.thingsboard.server.common.transport.profile.TenantProfileUpdateResult; |
26 | +import org.thingsboard.server.queue.util.TbTransportComponent; | ||
26 | 27 | ||
27 | import java.util.concurrent.ConcurrentHashMap; | 28 | import java.util.concurrent.ConcurrentHashMap; |
28 | import java.util.concurrent.ConcurrentMap; | 29 | import java.util.concurrent.ConcurrentMap; |
29 | 30 | ||
30 | @Service | 31 | @Service |
32 | +@TbTransportComponent | ||
31 | @Slf4j | 33 | @Slf4j |
32 | public class DefaultTransportRateLimitService implements TransportRateLimitService { | 34 | public class DefaultTransportRateLimitService implements TransportRateLimitService { |
33 | 35 | ||
@@ -43,23 +45,21 @@ public class DefaultTransportRateLimitService implements TransportRateLimitServi | @@ -43,23 +45,21 @@ public class DefaultTransportRateLimitService implements TransportRateLimitServi | ||
43 | } | 45 | } |
44 | 46 | ||
45 | @Override | 47 | @Override |
46 | - public TransportRateLimit getRateLimit(TenantId tenantId, TransportRateLimitType limitType) { | ||
47 | - TransportRateLimit[] limits = perTenantLimits.get(tenantId); | ||
48 | - if (limits == null) { | ||
49 | - limits = fetchProfileAndInit(tenantId); | ||
50 | - perTenantLimits.put(tenantId, limits); | ||
51 | - } | ||
52 | - return limits[limitType.ordinal()]; | ||
53 | - } | ||
54 | - | ||
55 | - @Override | ||
56 | - public TransportRateLimit getRateLimit(TenantId tenantId, DeviceId deviceId, TransportRateLimitType limitType) { | ||
57 | - TransportRateLimit[] limits = perDeviceLimits.get(deviceId); | ||
58 | - if (limits == null) { | ||
59 | - limits = fetchProfileAndInit(tenantId); | ||
60 | - perDeviceLimits.put(deviceId, limits); | 48 | + public TransportRateLimitType checkLimits(TenantId tenantId, DeviceId deviceId, int dataPoints, TransportRateLimitType... limits) { |
49 | + TransportRateLimit[] tenantLimits = getTenantRateLimits(tenantId); | ||
50 | + TransportRateLimit[] deviceLimits = getDeviceRateLimits(tenantId, deviceId); | ||
51 | + for (TransportRateLimitType limitType : limits) { | ||
52 | + TransportRateLimit rateLimit; | ||
53 | + if (limitType.isTenantLevel()) { | ||
54 | + rateLimit = tenantLimits[limitType.ordinal()]; | ||
55 | + } else { | ||
56 | + rateLimit = deviceLimits[limitType.ordinal()]; | ||
57 | + } | ||
58 | + if (!rateLimit.tryConsume(limitType.isMessageLevel() ? 1L : dataPoints)) { | ||
59 | + return limitType; | ||
60 | + } | ||
61 | } | 61 | } |
62 | - return limits[limitType.ordinal()]; | 62 | + return null; |
63 | } | 63 | } |
64 | 64 | ||
65 | @Override | 65 | @Override |
@@ -75,7 +75,17 @@ public class DefaultTransportRateLimitService implements TransportRateLimitServi | @@ -75,7 +75,17 @@ public class DefaultTransportRateLimitService implements TransportRateLimitServi | ||
75 | mergeLimits(tenantId, fetchProfileAndInit(tenantId)); | 75 | mergeLimits(tenantId, fetchProfileAndInit(tenantId)); |
76 | } | 76 | } |
77 | 77 | ||
78 | - public void mergeLimits(TenantId tenantId, TransportRateLimit[] newRateLimits) { | 78 | + @Override |
79 | + public void remove(TenantId tenantId) { | ||
80 | + perTenantLimits.remove(tenantId); | ||
81 | + } | ||
82 | + | ||
83 | + @Override | ||
84 | + public void remove(DeviceId deviceId) { | ||
85 | + perDeviceLimits.remove(deviceId); | ||
86 | + } | ||
87 | + | ||
88 | + private void mergeLimits(TenantId tenantId, TransportRateLimit[] newRateLimits) { | ||
79 | TransportRateLimit[] oldRateLimits = perTenantLimits.get(tenantId); | 89 | TransportRateLimit[] oldRateLimits = perTenantLimits.get(tenantId); |
80 | if (oldRateLimits == null) { | 90 | if (oldRateLimits == null) { |
81 | perTenantLimits.put(tenantId, newRateLimits); | 91 | perTenantLimits.put(tenantId, newRateLimits); |
@@ -90,16 +100,6 @@ public class DefaultTransportRateLimitService implements TransportRateLimitServi | @@ -90,16 +100,6 @@ public class DefaultTransportRateLimitService implements TransportRateLimitServi | ||
90 | } | 100 | } |
91 | } | 101 | } |
92 | 102 | ||
93 | - @Override | ||
94 | - public void remove(TenantId tenantId) { | ||
95 | - perTenantLimits.remove(tenantId); | ||
96 | - } | ||
97 | - | ||
98 | - @Override | ||
99 | - public void remove(DeviceId deviceId) { | ||
100 | - perDeviceLimits.remove(deviceId); | ||
101 | - } | ||
102 | - | ||
103 | private TransportRateLimit[] fetchProfileAndInit(TenantId tenantId) { | 103 | private TransportRateLimit[] fetchProfileAndInit(TenantId tenantId) { |
104 | return perTenantLimits.computeIfAbsent(tenantId, tmp -> createTransportRateLimits(tenantProfileCache.get(tenantId))); | 104 | return perTenantLimits.computeIfAbsent(tenantId, tmp -> createTransportRateLimits(tenantProfileCache.get(tenantId))); |
105 | } | 105 | } |
@@ -112,4 +112,22 @@ public class DefaultTransportRateLimitService implements TransportRateLimitServi | @@ -112,4 +112,22 @@ public class DefaultTransportRateLimitService implements TransportRateLimitServi | ||
112 | } | 112 | } |
113 | return rateLimits; | 113 | return rateLimits; |
114 | } | 114 | } |
115 | + | ||
116 | + private TransportRateLimit[] getTenantRateLimits(TenantId tenantId) { | ||
117 | + TransportRateLimit[] limits = perTenantLimits.get(tenantId); | ||
118 | + if (limits == null) { | ||
119 | + limits = fetchProfileAndInit(tenantId); | ||
120 | + perTenantLimits.put(tenantId, limits); | ||
121 | + } | ||
122 | + return limits; | ||
123 | + } | ||
124 | + | ||
125 | + private TransportRateLimit[] getDeviceRateLimits(TenantId tenantId, DeviceId deviceId) { | ||
126 | + TransportRateLimit[] limits = perDeviceLimits.get(deviceId); | ||
127 | + if (limits == null) { | ||
128 | + limits = fetchProfileAndInit(tenantId); | ||
129 | + perDeviceLimits.put(deviceId, limits); | ||
130 | + } | ||
131 | + return limits; | ||
132 | + } | ||
115 | } | 133 | } |
@@ -23,6 +23,11 @@ public class DummyTransportRateLimit implements TransportRateLimit { | @@ -23,6 +23,11 @@ public class DummyTransportRateLimit implements TransportRateLimit { | ||
23 | } | 23 | } |
24 | 24 | ||
25 | @Override | 25 | @Override |
26 | + public boolean tryConsume(long number) { | ||
27 | + return true; | ||
28 | + } | ||
29 | + | ||
30 | + @Override | ||
26 | public boolean tryConsume() { | 31 | public boolean tryConsume() { |
27 | return true; | 32 | return true; |
28 | } | 33 | } |
@@ -31,4 +31,8 @@ public class SimpleTransportRateLimit implements TransportRateLimit { | @@ -31,4 +31,8 @@ public class SimpleTransportRateLimit implements TransportRateLimit { | ||
31 | return rateLimit.tryConsume(); | 31 | return rateLimit.tryConsume(); |
32 | } | 32 | } |
33 | 33 | ||
34 | + @Override | ||
35 | + public boolean tryConsume(long number) { | ||
36 | + return number <= 0 || rateLimit.tryConsume(number); | ||
37 | + } | ||
34 | } | 38 | } |
@@ -21,9 +21,7 @@ import org.thingsboard.server.common.transport.profile.TenantProfileUpdateResult | @@ -21,9 +21,7 @@ import org.thingsboard.server.common.transport.profile.TenantProfileUpdateResult | ||
21 | 21 | ||
22 | public interface TransportRateLimitService { | 22 | public interface TransportRateLimitService { |
23 | 23 | ||
24 | - TransportRateLimit getRateLimit(TenantId tenantId, TransportRateLimitType limit); | ||
25 | - | ||
26 | - TransportRateLimit getRateLimit(TenantId tenantId, DeviceId deviceId, TransportRateLimitType limit); | 24 | + TransportRateLimitType checkLimits(TenantId tenantId, DeviceId deviceId, int dataPoints, TransportRateLimitType... limits); |
27 | 25 | ||
28 | void update(TenantProfileUpdateResult update); | 26 | void update(TenantProfileUpdateResult update); |
29 | 27 |
@@ -19,15 +19,29 @@ import lombok.Getter; | @@ -19,15 +19,29 @@ import lombok.Getter; | ||
19 | 19 | ||
20 | public enum TransportRateLimitType { | 20 | public enum TransportRateLimitType { |
21 | 21 | ||
22 | - TENANT_MAX_MSGS("transport.tenant.max.msg"), | ||
23 | - TENANT_MAX_DATA_POINTS("transport.tenant.max.dataPoints"), | ||
24 | - DEVICE_MAX_MSGS("transport.device.max.msg"), | ||
25 | - DEVICE_MAX_DATA_POINTS("transport.device.max.dataPoints"); | 22 | + TENANT_MAX_MSGS("transport.tenant.msg", true, true), |
23 | + TENANT_TELEMETRY_MSGS("transport.tenant.telemetry", true, true), | ||
24 | + TENANT_MAX_DATA_POINTS("transport.tenant.dataPoints", true, false), | ||
25 | + DEVICE_MAX_MSGS("transport.device.msg", false, true), | ||
26 | + DEVICE_TELEMETRY_MSGS("transport.device.telemetry", false, true), | ||
27 | + DEVICE_MAX_DATA_POINTS("transport.device.dataPoints", false, false); | ||
26 | 28 | ||
27 | @Getter | 29 | @Getter |
28 | private final String configurationKey; | 30 | private final String configurationKey; |
31 | + @Getter | ||
32 | + private final boolean tenantLevel; | ||
33 | + @Getter | ||
34 | + private final boolean deviceLevel; | ||
35 | + @Getter | ||
36 | + private final boolean messageLevel; | ||
37 | + @Getter | ||
38 | + private final boolean dataPointLevel; | ||
29 | 39 | ||
30 | - TransportRateLimitType(String configurationKey) { | 40 | + TransportRateLimitType(String configurationKey, boolean tenantLevel, boolean messageLevel) { |
31 | this.configurationKey = configurationKey; | 41 | this.configurationKey = configurationKey; |
42 | + this.tenantLevel = tenantLevel; | ||
43 | + this.deviceLevel = !tenantLevel; | ||
44 | + this.messageLevel = messageLevel; | ||
45 | + this.dataPointLevel = !messageLevel; | ||
32 | } | 46 | } |
33 | } | 47 | } |
@@ -23,6 +23,7 @@ import org.thingsboard.server.common.data.DeviceProfile; | @@ -23,6 +23,7 @@ import org.thingsboard.server.common.data.DeviceProfile; | ||
23 | import org.thingsboard.server.common.data.id.DeviceProfileId; | 23 | import org.thingsboard.server.common.data.id.DeviceProfileId; |
24 | import org.thingsboard.server.common.transport.TransportDeviceProfileCache; | 24 | import org.thingsboard.server.common.transport.TransportDeviceProfileCache; |
25 | import org.thingsboard.server.common.transport.util.DataDecodingEncodingService; | 25 | import org.thingsboard.server.common.transport.util.DataDecodingEncodingService; |
26 | +import org.thingsboard.server.queue.util.TbTransportComponent; | ||
26 | 27 | ||
27 | import java.util.Optional; | 28 | import java.util.Optional; |
28 | import java.util.concurrent.ConcurrentHashMap; | 29 | import java.util.concurrent.ConcurrentHashMap; |
@@ -30,7 +31,7 @@ import java.util.concurrent.ConcurrentMap; | @@ -30,7 +31,7 @@ import java.util.concurrent.ConcurrentMap; | ||
30 | 31 | ||
31 | @Slf4j | 32 | @Slf4j |
32 | @Component | 33 | @Component |
33 | -@ConditionalOnExpression("('${service.type:null}'=='monolith' && '${transport.api_enabled:true}'=='true') || '${service.type:null}'=='tb-transport'") | 34 | +@TbTransportComponent |
34 | public class DefaultTransportDeviceProfileCache implements TransportDeviceProfileCache { | 35 | public class DefaultTransportDeviceProfileCache implements TransportDeviceProfileCache { |
35 | 36 | ||
36 | private final ConcurrentMap<DeviceProfileId, DeviceProfile> deviceProfiles = new ConcurrentHashMap<>(); | 37 | private final ConcurrentMap<DeviceProfileId, DeviceProfile> deviceProfiles = new ConcurrentHashMap<>(); |
@@ -79,6 +79,7 @@ import org.thingsboard.server.queue.discovery.PartitionService; | @@ -79,6 +79,7 @@ import org.thingsboard.server.queue.discovery.PartitionService; | ||
79 | import org.thingsboard.server.queue.discovery.TbServiceInfoProvider; | 79 | import org.thingsboard.server.queue.discovery.TbServiceInfoProvider; |
80 | import org.thingsboard.server.queue.provider.TbQueueProducerProvider; | 80 | import org.thingsboard.server.queue.provider.TbQueueProducerProvider; |
81 | import org.thingsboard.server.queue.provider.TbTransportQueueFactory; | 81 | import org.thingsboard.server.queue.provider.TbTransportQueueFactory; |
82 | +import org.thingsboard.server.queue.util.TbTransportComponent; | ||
82 | 83 | ||
83 | import javax.annotation.PostConstruct; | 84 | import javax.annotation.PostConstruct; |
84 | import javax.annotation.PreDestroy; | 85 | import javax.annotation.PreDestroy; |
@@ -103,7 +104,7 @@ import java.util.concurrent.atomic.AtomicInteger; | @@ -103,7 +104,7 @@ import java.util.concurrent.atomic.AtomicInteger; | ||
103 | */ | 104 | */ |
104 | @Slf4j | 105 | @Slf4j |
105 | @Service | 106 | @Service |
106 | -@ConditionalOnExpression("('${service.type:null}'=='monolith' && '${transport.api_enabled:true}'=='true') || '${service.type:null}'=='tb-transport'") | 107 | +@TbTransportComponent |
107 | public class DefaultTransportService implements TransportService { | 108 | public class DefaultTransportService implements TransportService { |
108 | 109 | ||
109 | @Value("${transport.sessions.inactivity_timeout}") | 110 | @Value("${transport.sessions.inactivity_timeout}") |
@@ -363,7 +364,11 @@ public class DefaultTransportService implements TransportService { | @@ -363,7 +364,11 @@ public class DefaultTransportService implements TransportService { | ||
363 | 364 | ||
364 | @Override | 365 | @Override |
365 | public void process(TransportProtos.SessionInfoProto sessionInfo, TransportProtos.PostTelemetryMsg msg, TransportServiceCallback<Void> callback) { | 366 | public void process(TransportProtos.SessionInfoProto sessionInfo, TransportProtos.PostTelemetryMsg msg, TransportServiceCallback<Void> callback) { |
366 | - if (checkLimits(sessionInfo, msg, callback)) { | 367 | + int dataPoints = 0; |
368 | + for (TransportProtos.TsKvListProto tsKv : msg.getTsKvListList()) { | ||
369 | + dataPoints += tsKv.getKvCount(); | ||
370 | + } | ||
371 | + if (checkLimits(sessionInfo, msg, callback, dataPoints, TELEMETRY)) { | ||
367 | reportActivityInternal(sessionInfo); | 372 | reportActivityInternal(sessionInfo); |
368 | TenantId tenantId = new TenantId(new UUID(sessionInfo.getTenantIdMSB(), sessionInfo.getTenantIdLSB())); | 373 | TenantId tenantId = new TenantId(new UUID(sessionInfo.getTenantIdMSB(), sessionInfo.getTenantIdLSB())); |
369 | DeviceId deviceId = new DeviceId(new UUID(sessionInfo.getDeviceIdMSB(), sessionInfo.getDeviceIdLSB())); | 374 | DeviceId deviceId = new DeviceId(new UUID(sessionInfo.getDeviceIdMSB(), sessionInfo.getDeviceIdLSB())); |
@@ -384,7 +389,7 @@ public class DefaultTransportService implements TransportService { | @@ -384,7 +389,7 @@ public class DefaultTransportService implements TransportService { | ||
384 | 389 | ||
385 | @Override | 390 | @Override |
386 | public void process(TransportProtos.SessionInfoProto sessionInfo, TransportProtos.PostAttributeMsg msg, TransportServiceCallback<Void> callback) { | 391 | public void process(TransportProtos.SessionInfoProto sessionInfo, TransportProtos.PostAttributeMsg msg, TransportServiceCallback<Void> callback) { |
387 | - if (checkLimits(sessionInfo, msg, callback)) { | 392 | + if (checkLimits(sessionInfo, msg, callback, msg.getKvCount(), TELEMETRY)) { |
388 | reportActivityInternal(sessionInfo); | 393 | reportActivityInternal(sessionInfo); |
389 | TenantId tenantId = new TenantId(new UUID(sessionInfo.getTenantIdMSB(), sessionInfo.getTenantIdLSB())); | 394 | TenantId tenantId = new TenantId(new UUID(sessionInfo.getTenantIdMSB(), sessionInfo.getTenantIdLSB())); |
390 | DeviceId deviceId = new DeviceId(new UUID(sessionInfo.getDeviceIdMSB(), sessionInfo.getDeviceIdLSB())); | 395 | DeviceId deviceId = new DeviceId(new UUID(sessionInfo.getDeviceIdMSB(), sessionInfo.getDeviceIdLSB())); |
@@ -574,37 +579,34 @@ public class DefaultTransportService implements TransportService { | @@ -574,37 +579,34 @@ public class DefaultTransportService implements TransportService { | ||
574 | sessions.remove(toSessionId(sessionInfo)); | 579 | sessions.remove(toSessionId(sessionInfo)); |
575 | } | 580 | } |
576 | 581 | ||
582 | + private TransportRateLimitType[] DEFAULT = new TransportRateLimitType[]{TransportRateLimitType.TENANT_MAX_MSGS, TransportRateLimitType.DEVICE_MAX_MSGS}; | ||
583 | + private TransportRateLimitType[] TELEMETRY = TransportRateLimitType.values(); | ||
584 | + | ||
577 | @Override | 585 | @Override |
578 | public boolean checkLimits(TransportProtos.SessionInfoProto sessionInfo, Object msg, TransportServiceCallback<Void> callback) { | 586 | public boolean checkLimits(TransportProtos.SessionInfoProto sessionInfo, Object msg, TransportServiceCallback<Void> callback) { |
587 | + return checkLimits(sessionInfo, msg, callback, 0, DEFAULT); | ||
588 | + } | ||
589 | + | ||
590 | + @Override | ||
591 | + public boolean checkLimits(TransportProtos.SessionInfoProto sessionInfo, Object msg, TransportServiceCallback<Void> callback, int dataPoints, TransportRateLimitType... limits) { | ||
579 | if (log.isTraceEnabled()) { | 592 | if (log.isTraceEnabled()) { |
580 | log.trace("[{}] Processing msg: {}", toSessionId(sessionInfo), msg); | 593 | log.trace("[{}] Processing msg: {}", toSessionId(sessionInfo), msg); |
581 | } | 594 | } |
582 | TenantId tenantId = new TenantId(new UUID(sessionInfo.getTenantIdMSB(), sessionInfo.getTenantIdLSB())); | 595 | TenantId tenantId = new TenantId(new UUID(sessionInfo.getTenantIdMSB(), sessionInfo.getTenantIdLSB())); |
583 | - | ||
584 | - TransportRateLimit tenantRateLimit = rateLimitService.getRateLimit(tenantId, TransportRateLimitType.TENANT_MAX_MSGS); | ||
585 | - | ||
586 | - if (!tenantRateLimit.tryConsume()) { | ||
587 | - if (callback != null) { | ||
588 | - callback.onError(new TbRateLimitsException(EntityType.TENANT)); | ||
589 | - } | ||
590 | - if (log.isTraceEnabled()) { | ||
591 | - log.trace("[{}][{}] Tenant level rate limit detected: {}", toSessionId(sessionInfo), tenantId, msg); | ||
592 | - } | ||
593 | - return false; | ||
594 | - } | ||
595 | DeviceId deviceId = new DeviceId(new UUID(sessionInfo.getDeviceIdMSB(), sessionInfo.getDeviceIdLSB())); | 596 | DeviceId deviceId = new DeviceId(new UUID(sessionInfo.getDeviceIdMSB(), sessionInfo.getDeviceIdLSB())); |
596 | - TransportRateLimit deviceRateLimit = rateLimitService.getRateLimit(tenantId, deviceId, TransportRateLimitType.DEVICE_MAX_MSGS); | ||
597 | - if (!deviceRateLimit.tryConsume()) { | 597 | + |
598 | + TransportRateLimitType limit = rateLimitService.checkLimits(tenantId, deviceId, 0, limits); | ||
599 | + if (limit == null) { | ||
600 | + return true; | ||
601 | + } else { | ||
598 | if (callback != null) { | 602 | if (callback != null) { |
599 | - callback.onError(new TbRateLimitsException(EntityType.DEVICE)); | 603 | + callback.onError(new TbRateLimitsException(limit.isTenantLevel() ? EntityType.TENANT : EntityType.DEVICE)); |
600 | } | 604 | } |
601 | if (log.isTraceEnabled()) { | 605 | if (log.isTraceEnabled()) { |
602 | - log.trace("[{}][{}] Device level rate limit detected: {}", toSessionId(sessionInfo), deviceId, msg); | 606 | + log.trace("[{}][{}] {} rateLimit detected: {}", toSessionId(sessionInfo), tenantId, limit, msg); |
603 | } | 607 | } |
604 | return false; | 608 | return false; |
605 | } | 609 | } |
606 | - | ||
607 | - return true; | ||
608 | } | 610 | } |
609 | 611 | ||
610 | protected void processToTransportMsg(TransportProtos.ToTransportMsg toSessionMsg) { | 612 | protected void processToTransportMsg(TransportProtos.ToTransportMsg toSessionMsg) { |
@@ -33,6 +33,7 @@ import org.thingsboard.server.common.transport.util.DataDecodingEncodingService; | @@ -33,6 +33,7 @@ import org.thingsboard.server.common.transport.util.DataDecodingEncodingService; | ||
33 | import org.thingsboard.server.gen.transport.TransportProtos; | 33 | import org.thingsboard.server.gen.transport.TransportProtos; |
34 | import org.thingsboard.server.queue.discovery.TenantRoutingInfo; | 34 | import org.thingsboard.server.queue.discovery.TenantRoutingInfo; |
35 | import org.thingsboard.server.queue.discovery.TenantRoutingInfoService; | 35 | import org.thingsboard.server.queue.discovery.TenantRoutingInfoService; |
36 | +import org.thingsboard.server.queue.util.TbTransportComponent; | ||
36 | 37 | ||
37 | import java.util.Collections; | 38 | import java.util.Collections; |
38 | import java.util.Optional; | 39 | import java.util.Optional; |
@@ -43,7 +44,7 @@ import java.util.concurrent.locks.Lock; | @@ -43,7 +44,7 @@ import java.util.concurrent.locks.Lock; | ||
43 | import java.util.concurrent.locks.ReentrantLock; | 44 | import java.util.concurrent.locks.ReentrantLock; |
44 | 45 | ||
45 | @Component | 46 | @Component |
46 | -@ConditionalOnExpression("('${service.type:null}'=='monolith' && '${transport.api_enabled:true}'=='true') || '${service.type:null}'=='tb-transport'") | 47 | +@TbTransportComponent |
47 | @Slf4j | 48 | @Slf4j |
48 | public class DefaultTransportTenantProfileCache implements TransportTenantProfileCache { | 49 | public class DefaultTransportTenantProfileCache implements TransportTenantProfileCache { |
49 | 50 |
@@ -91,6 +91,12 @@ | @@ -91,6 +91,12 @@ | ||
91 | </mat-error> | 91 | </mat-error> |
92 | </mat-form-field> | 92 | </mat-form-field> |
93 | </div> | 93 | </div> |
94 | + <div fxLayout="column" fxLayoutAlign="flex-end start"> | ||
95 | + <tb-rule-chain-autocomplete | ||
96 | + labelText="device-profile.default-rule-chain" | ||
97 | + formControlName="defaultRuleChainId"> | ||
98 | + </tb-rule-chain-autocomplete> | ||
99 | + </div> | ||
94 | </div> | 100 | </div> |
95 | <mat-checkbox formControlName="gateway" style="padding-bottom: 16px;"> | 101 | <mat-checkbox formControlName="gateway" style="padding-bottom: 16px;"> |
96 | {{ 'device.is-gateway' | translate }} | 102 | {{ 'device.is-gateway' | translate }} |
@@ -42,6 +42,7 @@ import { ErrorStateMatcher } from '@angular/material/core'; | @@ -42,6 +42,7 @@ import { ErrorStateMatcher } from '@angular/material/core'; | ||
42 | import { StepperSelectionEvent } from '@angular/cdk/stepper'; | 42 | import { StepperSelectionEvent } from '@angular/cdk/stepper'; |
43 | import { BreakpointObserver, BreakpointState } from '@angular/cdk/layout'; | 43 | import { BreakpointObserver, BreakpointState } from '@angular/cdk/layout'; |
44 | import { MediaBreakpoints } from '@shared/models/constants'; | 44 | import { MediaBreakpoints } from '@shared/models/constants'; |
45 | +import { RuleChainId } from '@shared/models/id/rule-chain-id'; | ||
45 | 46 | ||
46 | @Component({ | 47 | @Component({ |
47 | selector: 'tb-device-wizard', | 48 | selector: 'tb-device-wizard', |
@@ -103,6 +104,7 @@ export class DeviceWizardDialogComponent extends | @@ -103,6 +104,7 @@ export class DeviceWizardDialogComponent extends | ||
103 | addProfileType: [0], | 104 | addProfileType: [0], |
104 | deviceProfileId: [null, Validators.required], | 105 | deviceProfileId: [null, Validators.required], |
105 | newDeviceProfileTitle: [{value: null, disabled: true}], | 106 | newDeviceProfileTitle: [{value: null, disabled: true}], |
107 | + defaultRuleChainId: [{value: null, disabled: true}], | ||
106 | description: [''] | 108 | description: [''] |
107 | } | 109 | } |
108 | ); | 110 | ); |
@@ -114,6 +116,7 @@ export class DeviceWizardDialogComponent extends | @@ -114,6 +116,7 @@ export class DeviceWizardDialogComponent extends | ||
114 | this.deviceWizardFormGroup.get('deviceProfileId').enable(); | 116 | this.deviceWizardFormGroup.get('deviceProfileId').enable(); |
115 | this.deviceWizardFormGroup.get('newDeviceProfileTitle').setValidators(null); | 117 | this.deviceWizardFormGroup.get('newDeviceProfileTitle').setValidators(null); |
116 | this.deviceWizardFormGroup.get('newDeviceProfileTitle').disable(); | 118 | this.deviceWizardFormGroup.get('newDeviceProfileTitle').disable(); |
119 | + this.deviceWizardFormGroup.get('defaultRuleChainId').disable(); | ||
117 | this.deviceWizardFormGroup.updateValueAndValidity(); | 120 | this.deviceWizardFormGroup.updateValueAndValidity(); |
118 | this.createProfile = false; | 121 | this.createProfile = false; |
119 | this.createTransportConfiguration = false; | 122 | this.createTransportConfiguration = false; |
@@ -122,6 +125,7 @@ export class DeviceWizardDialogComponent extends | @@ -122,6 +125,7 @@ export class DeviceWizardDialogComponent extends | ||
122 | this.deviceWizardFormGroup.get('deviceProfileId').disable(); | 125 | this.deviceWizardFormGroup.get('deviceProfileId').disable(); |
123 | this.deviceWizardFormGroup.get('newDeviceProfileTitle').setValidators([Validators.required]); | 126 | this.deviceWizardFormGroup.get('newDeviceProfileTitle').setValidators([Validators.required]); |
124 | this.deviceWizardFormGroup.get('newDeviceProfileTitle').enable(); | 127 | this.deviceWizardFormGroup.get('newDeviceProfileTitle').enable(); |
128 | + this.deviceWizardFormGroup.get('defaultRuleChainId').enable(); | ||
125 | this.deviceWizardFormGroup.updateValueAndValidity(); | 129 | this.deviceWizardFormGroup.updateValueAndValidity(); |
126 | this.createProfile = true; | 130 | this.createProfile = true; |
127 | this.createTransportConfiguration = this.deviceWizardFormGroup.get('transportType').value && | 131 | this.createTransportConfiguration = this.deviceWizardFormGroup.get('transportType').value && |
@@ -274,6 +278,9 @@ export class DeviceWizardDialogComponent extends | @@ -274,6 +278,9 @@ export class DeviceWizardDialogComponent extends | ||
274 | provisionConfiguration: deviceProvisionConfiguration | 278 | provisionConfiguration: deviceProvisionConfiguration |
275 | } | 279 | } |
276 | }; | 280 | }; |
281 | + if (this.deviceWizardFormGroup.get('defaultRuleChainId').value) { | ||
282 | + deviceProfile.defaultRuleChainId = new RuleChainId(this.deviceWizardFormGroup.get('defaultRuleChainId').value); | ||
283 | + } | ||
277 | return this.deviceProfileService.saveDeviceProfile(deviceProfile).pipe( | 284 | return this.deviceProfileService.saveDeviceProfile(deviceProfile).pipe( |
278 | map(profile => profile.id), | 285 | map(profile => profile.id), |
279 | tap((profileId) => { | 286 | tap((profileId) => { |
@@ -142,6 +142,7 @@ export class OAuth2SettingsComponent extends PageComponent implements OnInit, Ha | @@ -142,6 +142,7 @@ export class OAuth2SettingsComponent extends PageComponent implements OnInit, Ha | ||
142 | tenantNamePattern = {value: null, disabled: true}; | 142 | tenantNamePattern = {value: null, disabled: true}; |
143 | } | 143 | } |
144 | const basicGroup = this.fb.group({ | 144 | const basicGroup = this.fb.group({ |
145 | + emailAttributeKey: [mapperConfigBasic?.emailAttributeKey ? mapperConfigBasic.emailAttributeKey : 'email', Validators.required], | ||
145 | firstNameAttributeKey: [mapperConfigBasic?.firstNameAttributeKey ? mapperConfigBasic.firstNameAttributeKey : ''], | 146 | firstNameAttributeKey: [mapperConfigBasic?.firstNameAttributeKey ? mapperConfigBasic.firstNameAttributeKey : ''], |
146 | lastNameAttributeKey: [mapperConfigBasic?.lastNameAttributeKey ? mapperConfigBasic.lastNameAttributeKey : ''], | 147 | lastNameAttributeKey: [mapperConfigBasic?.lastNameAttributeKey ? mapperConfigBasic.lastNameAttributeKey : ''], |
147 | tenantNameStrategy: [mapperConfigBasic?.tenantNameStrategy ? mapperConfigBasic.tenantNameStrategy : TenantNameStrategy.DOMAIN], | 148 | tenantNameStrategy: [mapperConfigBasic?.tenantNameStrategy ? mapperConfigBasic.tenantNameStrategy : TenantNameStrategy.DOMAIN], |
@@ -151,11 +152,6 @@ export class OAuth2SettingsComponent extends PageComponent implements OnInit, Ha | @@ -151,11 +152,6 @@ export class OAuth2SettingsComponent extends PageComponent implements OnInit, Ha | ||
151 | alwaysFullScreen: [isDefinedAndNotNull(mapperConfigBasic?.alwaysFullScreen) ? mapperConfigBasic.alwaysFullScreen : false] | 152 | alwaysFullScreen: [isDefinedAndNotNull(mapperConfigBasic?.alwaysFullScreen) ? mapperConfigBasic.alwaysFullScreen : false] |
152 | }); | 153 | }); |
153 | 154 | ||
154 | - if (MapperConfigType.GITHUB !== type) { | ||
155 | - basicGroup.addControl('emailAttributeKey', | ||
156 | - this.fb.control( mapperConfigBasic?.emailAttributeKey ? mapperConfigBasic.emailAttributeKey : 'email', Validators.required)); | ||
157 | - } | ||
158 | - | ||
159 | this.subscriptions.push(basicGroup.get('tenantNameStrategy').valueChanges.subscribe((domain) => { | 155 | this.subscriptions.push(basicGroup.get('tenantNameStrategy').valueChanges.subscribe((domain) => { |
160 | if (domain === 'CUSTOM') { | 156 | if (domain === 'CUSTOM') { |
161 | basicGroup.get('tenantNamePattern').enable(); | 157 | basicGroup.get('tenantNamePattern').enable(); |
@@ -358,11 +354,15 @@ export class OAuth2SettingsComponent extends PageComponent implements OnInit, Ha | @@ -358,11 +354,15 @@ export class OAuth2SettingsComponent extends PageComponent implements OnInit, Ha | ||
358 | mapperConfig.addControl('custom', this.formCustomGroup(predefinedValue?.custom)); | 354 | mapperConfig.addControl('custom', this.formCustomGroup(predefinedValue?.custom)); |
359 | } else { | 355 | } else { |
360 | mapperConfig.removeControl('custom'); | 356 | mapperConfig.removeControl('custom'); |
361 | - if (mapperConfig.get('basic')) { | ||
362 | - mapperConfig.setControl('basic', this.formBasicGroup(type, predefinedValue?.basic)); | ||
363 | - } else { | 357 | + if (!mapperConfig.get('basic')) { |
364 | mapperConfig.addControl('basic', this.formBasicGroup(type, predefinedValue?.basic)); | 358 | mapperConfig.addControl('basic', this.formBasicGroup(type, predefinedValue?.basic)); |
365 | } | 359 | } |
360 | + if (type === MapperConfigType.GITHUB) { | ||
361 | + mapperConfig.get('basic.emailAttributeKey').disable(); | ||
362 | + mapperConfig.get('basic.emailAttributeKey').patchValue(null, {emitEvent: false}); | ||
363 | + } else { | ||
364 | + mapperConfig.get('basic.emailAttributeKey').enable(); | ||
365 | + } | ||
366 | } | 366 | } |
367 | } | 367 | } |
368 | 368 |
@@ -97,10 +97,6 @@ export class EntitySelectComponent implements ControlValueAccessor, OnInit, Afte | @@ -97,10 +97,6 @@ export class EntitySelectComponent implements ControlValueAccessor, OnInit, Afte | ||
97 | ngOnInit() { | 97 | ngOnInit() { |
98 | this.entitySelectFormGroup.get('entityType').valueChanges.subscribe( | 98 | this.entitySelectFormGroup.get('entityType').valueChanges.subscribe( |
99 | (value) => { | 99 | (value) => { |
100 | - if(value === AliasEntityType.CURRENT_TENANT || value === AliasEntityType.CURRENT_USER || | ||
101 | - value === AliasEntityType.CURRENT_USER_OWNER) { | ||
102 | - this.modelValue.id = NULL_UUID; | ||
103 | - } | ||
104 | this.updateView(value, this.modelValue.id); | 100 | this.updateView(value, this.modelValue.id); |
105 | } | 101 | } |
106 | ); | 102 | ); |
@@ -140,20 +136,23 @@ export class EntitySelectComponent implements ControlValueAccessor, OnInit, Afte | @@ -140,20 +136,23 @@ export class EntitySelectComponent implements ControlValueAccessor, OnInit, Afte | ||
140 | } | 136 | } |
141 | 137 | ||
142 | updateView(entityType: EntityType | AliasEntityType | null, entityId: string | null) { | 138 | updateView(entityType: EntityType | AliasEntityType | null, entityId: string | null) { |
143 | - if (this.modelValue.entityType !== entityType || | ||
144 | - this.modelValue.id !== entityId) { | ||
145 | - this.modelValue = { | ||
146 | - entityType, | ||
147 | - id: this.modelValue.entityType !== entityType ? null : entityId | ||
148 | - }; | ||
149 | - if (this.modelValue.entityType && (this.modelValue.id || | ||
150 | - this.modelValue.entityType === AliasEntityType.CURRENT_TENANT || | ||
151 | - this.modelValue.entityType === AliasEntityType.CURRENT_USER || | ||
152 | - this.modelValue.entityType === AliasEntityType.CURRENT_USER_OWNER)) { | ||
153 | - this.propagateChange(this.modelValue); | ||
154 | - } else { | ||
155 | - this.propagateChange(null); | ||
156 | - } | 139 | + if (this.modelValue.entityType !== entityType || this.modelValue.id !== entityId) { |
140 | + this.modelValue = { | ||
141 | + entityType, | ||
142 | + id: this.modelValue.entityType !== entityType ? null : entityId | ||
143 | + }; | ||
144 | + | ||
145 | + if (this.modelValue.entityType === AliasEntityType.CURRENT_TENANT | ||
146 | + || this.modelValue.entityType === AliasEntityType.CURRENT_USER | ||
147 | + || this.modelValue.entityType === AliasEntityType.CURRENT_USER_OWNER) { | ||
148 | + this.modelValue.id = NULL_UUID; | ||
149 | + } | ||
150 | + | ||
151 | + if (this.modelValue.entityType && this.modelValue.id) { | ||
152 | + this.propagateChange(this.modelValue); | ||
153 | + } else { | ||
154 | + this.propagateChange(null); | ||
155 | + } | ||
157 | } | 156 | } |
158 | } | 157 | } |
159 | } | 158 | } |
@@ -36,7 +36,6 @@ import { TranslateService } from '@ngx-translate/core'; | @@ -36,7 +36,6 @@ import { TranslateService } from '@ngx-translate/core'; | ||
36 | import { CancelAnimationFrame, RafService } from '@core/services/raf.service'; | 36 | import { CancelAnimationFrame, RafService } from '@core/services/raf.service'; |
37 | import { ResizeObserver } from '@juggle/resize-observer'; | 37 | import { ResizeObserver } from '@juggle/resize-observer'; |
38 | import { TbEditorCompleter } from '@shared/models/ace/completion.models'; | 38 | import { TbEditorCompleter } from '@shared/models/ace/completion.models'; |
39 | -import { widgetEditorCompleter } from '@home/pages/widget/widget-editor.models'; | ||
40 | 39 | ||
41 | @Component({ | 40 | @Component({ |
42 | selector: 'tb-js-func', | 41 | selector: 'tb-js-func', |
@@ -64,6 +63,7 @@ export class JsFuncComponent implements OnInit, OnDestroy, ControlValueAccessor, | @@ -64,6 +63,7 @@ export class JsFuncComponent implements OnInit, OnDestroy, ControlValueAccessor, | ||
64 | private jsEditor: ace.Ace.Editor; | 63 | private jsEditor: ace.Ace.Editor; |
65 | private editorsResizeCaf: CancelAnimationFrame; | 64 | private editorsResizeCaf: CancelAnimationFrame; |
66 | private editorResize$: ResizeObserver; | 65 | private editorResize$: ResizeObserver; |
66 | + private ignoreChange = false; | ||
67 | 67 | ||
68 | toastTargetId = `jsFuncEditor-${guid()}`; | 68 | toastTargetId = `jsFuncEditor-${guid()}`; |
69 | 69 | ||
@@ -154,8 +154,10 @@ export class JsFuncComponent implements OnInit, OnDestroy, ControlValueAccessor, | @@ -154,8 +154,10 @@ export class JsFuncComponent implements OnInit, OnDestroy, ControlValueAccessor, | ||
154 | this.jsEditor.session.setUseWrapMode(true); | 154 | this.jsEditor.session.setUseWrapMode(true); |
155 | this.jsEditor.setValue(this.modelValue ? this.modelValue : '', -1); | 155 | this.jsEditor.setValue(this.modelValue ? this.modelValue : '', -1); |
156 | this.jsEditor.on('change', () => { | 156 | this.jsEditor.on('change', () => { |
157 | - this.cleanupJsErrors(); | ||
158 | - this.updateView(); | 157 | + if (!this.ignoreChange) { |
158 | + this.cleanupJsErrors(); | ||
159 | + this.updateView(); | ||
160 | + } | ||
159 | }); | 161 | }); |
160 | if (this.editorCompleter) { | 162 | if (this.editorCompleter) { |
161 | this.jsEditor.completers = [this.editorCompleter, ...(this.jsEditor.completers || [])]; | 163 | this.jsEditor.completers = [this.editorCompleter, ...(this.jsEditor.completers || [])]; |
@@ -332,7 +334,9 @@ export class JsFuncComponent implements OnInit, OnDestroy, ControlValueAccessor, | @@ -332,7 +334,9 @@ export class JsFuncComponent implements OnInit, OnDestroy, ControlValueAccessor, | ||
332 | writeValue(value: string): void { | 334 | writeValue(value: string): void { |
333 | this.modelValue = value; | 335 | this.modelValue = value; |
334 | if (this.jsEditor) { | 336 | if (this.jsEditor) { |
337 | + this.ignoreChange = true; | ||
335 | this.jsEditor.setValue(this.modelValue ? this.modelValue : '', -1); | 338 | this.jsEditor.setValue(this.modelValue ? this.modelValue : '', -1); |
339 | + this.ignoreChange = false; | ||
336 | } | 340 | } |
337 | } | 341 | } |
338 | 342 |
@@ -61,6 +61,7 @@ export class JsonContentComponent implements OnInit, ControlValueAccessor, Valid | @@ -61,6 +61,7 @@ export class JsonContentComponent implements OnInit, ControlValueAccessor, Valid | ||
61 | private jsonEditor: ace.Ace.Editor; | 61 | private jsonEditor: ace.Ace.Editor; |
62 | private editorsResizeCaf: CancelAnimationFrame; | 62 | private editorsResizeCaf: CancelAnimationFrame; |
63 | private editorResize$: ResizeObserver; | 63 | private editorResize$: ResizeObserver; |
64 | + private ignoreChange = false; | ||
64 | 65 | ||
65 | toastTargetId = `jsonContentEditor-${guid()}`; | 66 | toastTargetId = `jsonContentEditor-${guid()}`; |
66 | 67 | ||
@@ -140,8 +141,13 @@ export class JsonContentComponent implements OnInit, ControlValueAccessor, Valid | @@ -140,8 +141,13 @@ export class JsonContentComponent implements OnInit, ControlValueAccessor, Valid | ||
140 | this.jsonEditor.session.setUseWrapMode(true); | 141 | this.jsonEditor.session.setUseWrapMode(true); |
141 | this.jsonEditor.setValue(this.contentBody ? this.contentBody : '', -1); | 142 | this.jsonEditor.setValue(this.contentBody ? this.contentBody : '', -1); |
142 | this.jsonEditor.on('change', () => { | 143 | this.jsonEditor.on('change', () => { |
143 | - this.cleanupJsonErrors(); | ||
144 | - this.updateView(); | 144 | + if (!this.ignoreChange) { |
145 | + this.cleanupJsonErrors(); | ||
146 | + this.updateView(); | ||
147 | + } | ||
148 | + }); | ||
149 | + this.jsonEditor.on('blur', () => { | ||
150 | + this.contentValid = !this.validateContent || this.doValidate(true); | ||
145 | }); | 151 | }); |
146 | this.editorResize$ = new ResizeObserver(() => { | 152 | this.editorResize$ = new ResizeObserver(() => { |
147 | this.onAceEditorResize(); | 153 | this.onAceEditorResize(); |
@@ -210,34 +216,36 @@ export class JsonContentComponent implements OnInit, ControlValueAccessor, Valid | @@ -210,34 +216,36 @@ export class JsonContentComponent implements OnInit, ControlValueAccessor, Valid | ||
210 | this.cleanupJsonErrors(); | 216 | this.cleanupJsonErrors(); |
211 | this.contentValid = true; | 217 | this.contentValid = true; |
212 | this.propagateChange(this.contentBody); | 218 | this.propagateChange(this.contentBody); |
213 | - this.contentValid = this.doValidate(); | 219 | + this.contentValid = this.doValidate(true); |
214 | this.propagateChange(this.contentBody); | 220 | this.propagateChange(this.contentBody); |
215 | } | 221 | } |
216 | } | 222 | } |
217 | 223 | ||
218 | - private doValidate(): boolean { | 224 | + private doValidate(showErrorToast = false): boolean { |
219 | try { | 225 | try { |
220 | if (this.validateContent && this.contentType === ContentType.JSON) { | 226 | if (this.validateContent && this.contentType === ContentType.JSON) { |
221 | JSON.parse(this.contentBody); | 227 | JSON.parse(this.contentBody); |
222 | } | 228 | } |
223 | return true; | 229 | return true; |
224 | } catch (ex) { | 230 | } catch (ex) { |
225 | - let errorInfo = 'Error:'; | ||
226 | - if (ex.name) { | ||
227 | - errorInfo += ' ' + ex.name + ':'; | ||
228 | - } | ||
229 | - if (ex.message) { | ||
230 | - errorInfo += ' ' + ex.message; | 231 | + if (showErrorToast) { |
232 | + let errorInfo = 'Error:'; | ||
233 | + if (ex.name) { | ||
234 | + errorInfo += ' ' + ex.name + ':'; | ||
235 | + } | ||
236 | + if (ex.message) { | ||
237 | + errorInfo += ' ' + ex.message; | ||
238 | + } | ||
239 | + this.store.dispatch(new ActionNotificationShow( | ||
240 | + { | ||
241 | + message: errorInfo, | ||
242 | + type: 'error', | ||
243 | + target: this.toastTargetId, | ||
244 | + verticalPosition: 'bottom', | ||
245 | + horizontalPosition: 'left' | ||
246 | + })); | ||
247 | + this.errorShowed = true; | ||
231 | } | 248 | } |
232 | - this.store.dispatch(new ActionNotificationShow( | ||
233 | - { | ||
234 | - message: errorInfo, | ||
235 | - type: 'error', | ||
236 | - target: this.toastTargetId, | ||
237 | - verticalPosition: 'bottom', | ||
238 | - horizontalPosition: 'left' | ||
239 | - })); | ||
240 | - this.errorShowed = true; | ||
241 | return false; | 249 | return false; |
242 | } | 250 | } |
243 | } | 251 | } |
@@ -256,8 +264,9 @@ export class JsonContentComponent implements OnInit, ControlValueAccessor, Valid | @@ -256,8 +264,9 @@ export class JsonContentComponent implements OnInit, ControlValueAccessor, Valid | ||
256 | this.contentBody = value; | 264 | this.contentBody = value; |
257 | this.contentValid = true; | 265 | this.contentValid = true; |
258 | if (this.jsonEditor) { | 266 | if (this.jsonEditor) { |
267 | + this.ignoreChange = true; | ||
259 | this.jsonEditor.setValue(this.contentBody ? this.contentBody : '', -1); | 268 | this.jsonEditor.setValue(this.contentBody ? this.contentBody : '', -1); |
260 | - // this.jsonEditor. | 269 | + this.ignoreChange = false; |
261 | } | 270 | } |
262 | } | 271 | } |
263 | 272 |