Commit 76bb8f13c05453e7f2c55b43c97cf953fb612b45

Authored by Igor Kulikov
2 parents 33928d41 cf40729b

Merge branch 'master' of github.com:thingsboard/thingsboard

... ... @@ -197,7 +197,7 @@ public class DefaultSystemDataLoaderService implements SystemDataLoaderService {
197 197 generalSettings.setKey("general");
198 198 ObjectNode node = objectMapper.createObjectNode();
199 199 node.put("baseUrl", "http://localhost:8080");
200   - node.put("prohibitDifferentUrl", true);
  200 + node.put("prohibitDifferentUrl", false);
201 201 generalSettings.setJsonValue(node);
202 202 adminSettingsService.saveAdminSettings(TenantId.SYS_TENANT_ID, generalSettings);
203 203
... ...
... ... @@ -59,6 +59,7 @@ import org.thingsboard.server.queue.discovery.PartitionService;
59 59 import org.thingsboard.server.queue.util.TbCoreComponent;
60 60 import org.thingsboard.server.service.queue.TbClusterService;
61 61 import org.thingsboard.server.service.telemetry.TelemetrySubscriptionService;
  62 +import org.thingsboard.server.utils.EventDeduplicationExecutor;
62 63
63 64 import javax.annotation.Nullable;
64 65 import javax.annotation.PostConstruct;
... ... @@ -126,13 +127,13 @@ public class DefaultDeviceStateService implements DeviceStateService {
126 127 @Getter
127 128 private int initFetchPackSize;
128 129
129   - private volatile boolean clusterUpdatePending = false;
130   -
131 130 private ListeningScheduledExecutorService queueExecutor;
132 131 private final ConcurrentMap<TopicPartitionInfo, Set<DeviceId>> partitionedDevices = new ConcurrentHashMap<>();
133 132 private final ConcurrentMap<DeviceId, DeviceStateData> deviceStates = new ConcurrentHashMap<>();
134 133 private final ConcurrentMap<DeviceId, Long> deviceLastReportedActivity = new ConcurrentHashMap<>();
135 134 private final ConcurrentMap<DeviceId, Long> deviceLastSavedActivity = new ConcurrentHashMap<>();
  135 + private volatile EventDeduplicationExecutor<Set<TopicPartitionInfo>> deduplicationExecutor;
  136 +
136 137
137 138 public DefaultDeviceStateService(TenantService tenantService, DeviceService deviceService,
138 139 AttributesService attributesService, TimeseriesService tsService,
... ... @@ -155,6 +156,7 @@ public class DefaultDeviceStateService implements DeviceStateService {
155 156 // Should be always single threaded due to absence of locks.
156 157 queueExecutor = MoreExecutors.listeningDecorator(Executors.newSingleThreadScheduledExecutor(ThingsBoardThreadFactory.forName("device-state")));
157 158 queueExecutor.scheduleAtFixedRate(this::updateState, new Random().nextInt(defaultStateCheckIntervalInSec), defaultStateCheckIntervalInSec, TimeUnit.SECONDS);
  159 + deduplicationExecutor = new EventDeduplicationExecutor<>(DefaultDeviceStateService.class.getSimpleName(), queueExecutor, this::initStateFromDB);
158 160 }
159 161
160 162 @PreDestroy
... ... @@ -292,25 +294,14 @@ public class DefaultDeviceStateService implements DeviceStateService {
292 294 }
293 295 }
294 296
295   - volatile Set<TopicPartitionInfo> pendingPartitions;
296   -
297 297 @Override
298 298 public void onApplicationEvent(PartitionChangeEvent partitionChangeEvent) {
299 299 if (ServiceType.TB_CORE.equals(partitionChangeEvent.getServiceType())) {
300   - synchronized (this) {
301   - pendingPartitions = partitionChangeEvent.getPartitions();
302   - if (!clusterUpdatePending) {
303   - clusterUpdatePending = true;
304   - queueExecutor.submit(() -> {
305   - clusterUpdatePending = false;
306   - initStateFromDB();
307   - });
308   - }
309   - }
  300 + deduplicationExecutor.submit(partitionChangeEvent.getPartitions());
310 301 }
311 302 }
312 303
313   - private void initStateFromDB() {
  304 + private void initStateFromDB(Set<TopicPartitionInfo> pendingPartitions) {
314 305 try {
315 306 log.info("CURRENT PARTITIONS: {}", partitionedDevices.keySet());
316 307 log.info("NEW PARTITIONS: {}", pendingPartitions);
... ...
  1 +/**
  2 + * Copyright © 2016-2021 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.utils;
  17 +
  18 +import lombok.extern.slf4j.Slf4j;
  19 +
  20 +import java.util.concurrent.Executor;
  21 +import java.util.concurrent.ExecutorService;
  22 +import java.util.function.Consumer;
  23 +
  24 +/**
  25 + * This class deduplicate executions of the specified function.
  26 + * Useful in cluster mode, when you get event about partition change multiple times.
  27 + * Assuming that the function execution is expensive, we should execute it immediately when first time event occurs and
  28 + * later, once the processing of first event is done, process last pending task.
  29 + *
  30 + * @param <P> parameters of the function
  31 + */
  32 +@Slf4j
  33 +public class EventDeduplicationExecutor<P> {
  34 + private final String name;
  35 + private final ExecutorService executor;
  36 + private final Consumer<P> function;
  37 + private P pendingTask;
  38 + private boolean busy;
  39 +
  40 + public EventDeduplicationExecutor(String name, ExecutorService executor, Consumer<P> function) {
  41 + this.name = name;
  42 + this.executor = executor;
  43 + this.function = function;
  44 + }
  45 +
  46 + public void submit(P params) {
  47 + log.info("[{}] Going to submit: {}", name, params);
  48 + synchronized (EventDeduplicationExecutor.this) {
  49 + if (!busy) {
  50 + busy = true;
  51 + pendingTask = null;
  52 + try {
  53 + log.info("[{}] Submitting task: {}", name, params);
  54 + executor.submit(() -> {
  55 + try {
  56 + log.info("[{}] Executing task: {}", name, params);
  57 + function.accept(params);
  58 + } catch (Throwable e) {
  59 + log.warn("[{}] Failed to process task with parameters: {}", name, params, e);
  60 + throw e;
  61 + } finally {
  62 + unlockAndProcessIfAny();
  63 + }
  64 + });
  65 + } catch (Throwable e) {
  66 + log.warn("[{}] Failed to submit task with parameters: {}", name, params, e);
  67 + unlockAndProcessIfAny();
  68 + throw e;
  69 + }
  70 + } else {
  71 + log.info("[{}] Task is already in progress. {} pending task: {}", name, pendingTask == null ? "adding" : "updating", params);
  72 + pendingTask = params;
  73 + }
  74 + }
  75 + }
  76 +
  77 + private void unlockAndProcessIfAny() {
  78 + synchronized (EventDeduplicationExecutor.this) {
  79 + busy = false;
  80 + if (pendingTask != null) {
  81 + submit(pendingTask);
  82 + }
  83 + }
  84 + }
  85 +}
... ...
  1 +/**
  2 + * Copyright © 2016-2021 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.util;
  17 +
  18 +import com.google.common.util.concurrent.MoreExecutors;
  19 +import lombok.extern.slf4j.Slf4j;
  20 +import org.junit.Test;
  21 +import org.junit.runner.RunWith;
  22 +import org.mockito.Mockito;
  23 +import org.mockito.runners.MockitoJUnitRunner;
  24 +import org.thingsboard.server.utils.EventDeduplicationExecutor;
  25 +
  26 +import java.util.concurrent.ExecutorService;
  27 +import java.util.concurrent.Executors;
  28 +import java.util.function.Consumer;
  29 +
  30 +@Slf4j
  31 +@RunWith(MockitoJUnitRunner.class)
  32 +public class EventDeduplicationExecutorTest {
  33 +
  34 + @Test
  35 + public void testSimpleFlowSameThread() throws InterruptedException {
  36 + simpleFlow(MoreExecutors.newDirectExecutorService());
  37 + }
  38 +
  39 + @Test
  40 + public void testPeriodicFlowSameThread() throws InterruptedException {
  41 + periodicFlow(MoreExecutors.newDirectExecutorService());
  42 + }
  43 +
  44 + @Test
  45 + public void testExceptionFlowSameThread() throws InterruptedException {
  46 + exceptionFlow(MoreExecutors.newDirectExecutorService());
  47 + }
  48 +
  49 + @Test
  50 + public void testSimpleFlowSingleThread() throws InterruptedException {
  51 + simpleFlow(Executors.newSingleThreadExecutor());
  52 + }
  53 +
  54 + @Test
  55 + public void testPeriodicFlowSingleThread() throws InterruptedException {
  56 + periodicFlow(Executors.newSingleThreadExecutor());
  57 + }
  58 +
  59 + @Test
  60 + public void testExceptionFlowSingleThread() throws InterruptedException {
  61 + exceptionFlow(Executors.newSingleThreadExecutor());
  62 + }
  63 +
  64 + @Test
  65 + public void testSimpleFlowMultiThread() throws InterruptedException {
  66 + simpleFlow(Executors.newFixedThreadPool(3));
  67 + }
  68 +
  69 + @Test
  70 + public void testPeriodicFlowMultiThread() throws InterruptedException {
  71 + periodicFlow(Executors.newFixedThreadPool(3));
  72 + }
  73 +
  74 + @Test
  75 + public void testExceptionFlowMultiThread() throws InterruptedException {
  76 + exceptionFlow(Executors.newFixedThreadPool(3));
  77 + }
  78 +
  79 + private void simpleFlow(ExecutorService executorService) throws InterruptedException {
  80 + try {
  81 + Consumer<String> function = Mockito.spy(StringConsumer.class);
  82 + EventDeduplicationExecutor<String> executor = new EventDeduplicationExecutor<>(EventDeduplicationExecutorTest.class.getSimpleName(), executorService, function);
  83 +
  84 + String params1 = "params1";
  85 + String params2 = "params2";
  86 + String params3 = "params3";
  87 +
  88 + executor.submit(params1);
  89 + executor.submit(params2);
  90 + executor.submit(params3);
  91 + Thread.sleep(500);
  92 + Mockito.verify(function).accept(params1);
  93 + Mockito.verify(function).accept(params3);
  94 + } finally {
  95 + executorService.shutdownNow();
  96 + }
  97 + }
  98 +
  99 + private void periodicFlow(ExecutorService executorService) throws InterruptedException {
  100 + try {
  101 + Consumer<String> function = Mockito.spy(StringConsumer.class);
  102 + EventDeduplicationExecutor<String> executor = new EventDeduplicationExecutor<>(EventDeduplicationExecutorTest.class.getSimpleName(), executorService, function);
  103 +
  104 + String params1 = "params1";
  105 + String params2 = "params2";
  106 + String params3 = "params3";
  107 +
  108 + executor.submit(params1);
  109 + Thread.sleep(500);
  110 + executor.submit(params2);
  111 + Thread.sleep(500);
  112 + executor.submit(params3);
  113 + Thread.sleep(500);
  114 + Mockito.verify(function).accept(params1);
  115 + Mockito.verify(function).accept(params2);
  116 + Mockito.verify(function).accept(params3);
  117 + } finally {
  118 + executorService.shutdownNow();
  119 + }
  120 + }
  121 +
  122 + private void exceptionFlow(ExecutorService executorService) throws InterruptedException {
  123 + try {
  124 + Consumer<String> function = Mockito.spy(StringConsumer.class);
  125 + EventDeduplicationExecutor<String> executor = new EventDeduplicationExecutor<>(EventDeduplicationExecutorTest.class.getSimpleName(), executorService, function);
  126 +
  127 + String params1 = "params1";
  128 + String params2 = "params2";
  129 + String params3 = "params3";
  130 +
  131 + Mockito.doThrow(new RuntimeException()).when(function).accept("params1");
  132 + executor.submit(params1);
  133 + executor.submit(params2);
  134 + Thread.sleep(500);
  135 + executor.submit(params3);
  136 + Thread.sleep(500);
  137 + Mockito.verify(function).accept(params2);
  138 + Mockito.verify(function).accept(params3);
  139 + } finally {
  140 + executorService.shutdownNow();
  141 + }
  142 + }
  143 +
  144 + public static class StringConsumer implements Consumer<String> {
  145 + @Override
  146 + public void accept(String s) {
  147 + try {
  148 + Thread.sleep(100);
  149 + } catch (InterruptedException e) {
  150 + throw new RuntimeException(e);
  151 + }
  152 + }
  153 + }
  154 +
  155 +}
... ...
... ... @@ -19,16 +19,18 @@ import com.google.common.util.concurrent.ListenableFuture;
19 19 import org.thingsboard.server.common.data.alarm.Alarm;
20 20 import org.thingsboard.server.common.data.alarm.AlarmInfo;
21 21 import org.thingsboard.server.common.data.alarm.AlarmQuery;
  22 +import org.thingsboard.server.common.data.alarm.AlarmSeverity;
  23 +import org.thingsboard.server.common.data.alarm.AlarmStatus;
22 24 import org.thingsboard.server.common.data.id.CustomerId;
23 25 import org.thingsboard.server.common.data.id.EntityId;
24 26 import org.thingsboard.server.common.data.id.TenantId;
25 27 import org.thingsboard.server.common.data.page.PageData;
26 28 import org.thingsboard.server.common.data.query.AlarmData;
27   -import org.thingsboard.server.common.data.query.AlarmDataPageLink;
28 29 import org.thingsboard.server.common.data.query.AlarmDataQuery;
29 30 import org.thingsboard.server.dao.Dao;
30 31
31 32 import java.util.Collection;
  33 +import java.util.Set;
32 34 import java.util.UUID;
33 35
34 36 /**
... ... @@ -48,4 +50,6 @@ public interface AlarmDao extends Dao<Alarm> {
48 50
49 51 PageData<AlarmData> findAlarmDataByQueryForEntities(TenantId tenantId, CustomerId customerId,
50 52 AlarmDataQuery query, Collection<EntityId> orderedEntityIds);
  53 +
  54 + Set<AlarmSeverity> findAlarmSeverities(TenantId tenantId, EntityId entityId, Set<AlarmStatus> status);
51 55 }
... ...
... ... @@ -39,10 +39,10 @@ import org.thingsboard.server.common.data.id.CustomerId;
39 39 import org.thingsboard.server.common.data.id.EntityId;
40 40 import org.thingsboard.server.common.data.id.TenantId;
41 41 import org.thingsboard.server.common.data.page.PageData;
42   -import org.thingsboard.server.common.data.page.TimePageLink;
43 42 import org.thingsboard.server.common.data.query.AlarmData;
44 43 import org.thingsboard.server.common.data.query.AlarmDataPageLink;
45 44 import org.thingsboard.server.common.data.query.AlarmDataQuery;
  45 +import org.thingsboard.server.common.data.query.DeviceTypeFilter;
46 46 import org.thingsboard.server.common.data.relation.EntityRelation;
47 47 import org.thingsboard.server.common.data.relation.EntityRelationsQuery;
48 48 import org.thingsboard.server.common.data.relation.EntitySearchDirection;
... ... @@ -60,7 +60,6 @@ import javax.annotation.PreDestroy;
60 60 import java.util.ArrayList;
61 61 import java.util.Collection;
62 62 import java.util.Collections;
63   -import java.util.Comparator;
64 63 import java.util.LinkedHashSet;
65 64 import java.util.List;
66 65 import java.util.Set;
... ... @@ -316,37 +315,16 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ
316 315 @Override
317 316 public AlarmSeverity findHighestAlarmSeverity(TenantId tenantId, EntityId entityId, AlarmSearchStatus alarmSearchStatus,
318 317 AlarmStatus alarmStatus) {
319   - TimePageLink nextPageLink = new TimePageLink(100);
320   - boolean hasNext = true;
321   - AlarmSeverity highestSeverity = null;
322   - AlarmQuery query;
323   - while (hasNext && AlarmSeverity.CRITICAL != highestSeverity) {
324   - query = new AlarmQuery(entityId, nextPageLink, alarmSearchStatus, alarmStatus, false, null);
325   - PageData<AlarmInfo> alarms = alarmDao.findAlarms(tenantId, query);
326   - if (alarms.hasNext()) {
327   - nextPageLink = nextPageLink.nextPageLink();
328   - }
329   - AlarmSeverity severity = detectHighestSeverity(alarms.getData());
330   - if (severity == null) {
331   - continue;
332   - }
333   - if (severity == AlarmSeverity.CRITICAL || highestSeverity == null) {
334   - highestSeverity = severity;
335   - } else {
336   - highestSeverity = highestSeverity.compareTo(severity) < 0 ? highestSeverity : severity;
337   - }
  318 + Set<AlarmStatus> statusList = null;
  319 + if (alarmSearchStatus != null) {
  320 + statusList = alarmSearchStatus.getStatuses();
  321 + } else if (alarmStatus != null) {
  322 + statusList = Collections.singleton(alarmStatus);
338 323 }
339   - return highestSeverity;
340   - }
341 324
342   - private AlarmSeverity detectHighestSeverity(List<AlarmInfo> alarms) {
343   - if (!alarms.isEmpty()) {
344   - List<AlarmInfo> sorted = new ArrayList(alarms);
345   - sorted.sort(Comparator.comparing(Alarm::getSeverity));
346   - return sorted.get(0).getSeverity();
347   - } else {
348   - return null;
349   - }
  325 + Set<AlarmSeverity> alarmSeverities = alarmDao.findAlarmSeverities(tenantId, entityId, statusList);
  326 +
  327 + return alarmSeverities.stream().min(AlarmSeverity::compareTo).orElse(null);
350 328 }
351 329
352 330 private void deleteRelation(TenantId tenantId, EntityRelation alarmRelation) {
... ...
... ... @@ -20,6 +20,7 @@ import org.springframework.data.domain.Pageable;
20 20 import org.springframework.data.jpa.repository.Query;
21 21 import org.springframework.data.repository.CrudRepository;
22 22 import org.springframework.data.repository.query.Param;
  23 +import org.thingsboard.server.common.data.alarm.AlarmSeverity;
23 24 import org.thingsboard.server.common.data.alarm.AlarmStatus;
24 25 import org.thingsboard.server.dao.model.sql.AlarmEntity;
25 26 import org.thingsboard.server.dao.model.sql.AlarmInfoEntity;
... ... @@ -75,4 +76,12 @@ public interface AlarmRepository extends CrudRepository<AlarmEntity, UUID> {
75 76 @Param("searchText") String searchText,
76 77 Pageable pageable);
77 78
  79 + @Query("SELECT alarm.severity FROM AlarmEntity alarm" +
  80 + " WHERE alarm.tenantId = :tenantId" +
  81 + " AND alarm.originatorId = :entityId" +
  82 + " AND ((:status) IS NULL OR alarm.status in (:status))")
  83 + Set<AlarmSeverity> findAlarmSeverities(@Param("tenantId") UUID tenantId,
  84 + @Param("entityId") UUID entityId,
  85 + @Param("status") Set<AlarmStatus> status);
  86 +
78 87 }
... ...
... ... @@ -24,6 +24,7 @@ import org.springframework.stereotype.Component;
24 24 import org.thingsboard.server.common.data.alarm.Alarm;
25 25 import org.thingsboard.server.common.data.alarm.AlarmInfo;
26 26 import org.thingsboard.server.common.data.alarm.AlarmQuery;
  27 +import org.thingsboard.server.common.data.alarm.AlarmSeverity;
27 28 import org.thingsboard.server.common.data.alarm.AlarmStatus;
28 29 import org.thingsboard.server.common.data.id.CustomerId;
29 30 import org.thingsboard.server.common.data.id.EntityId;
... ... @@ -120,4 +121,9 @@ public class JpaAlarmDao extends JpaAbstractDao<AlarmEntity, Alarm> implements A
120 121 public PageData<AlarmData> findAlarmDataByQueryForEntities(TenantId tenantId, CustomerId customerId, AlarmDataQuery query, Collection<EntityId> orderedEntityIds) {
121 122 return alarmQueryRepository.findAlarmDataByQueryForEntities(tenantId, customerId, query, orderedEntityIds);
122 123 }
  124 +
  125 + @Override
  126 + public Set<AlarmSeverity> findAlarmSeverities(TenantId tenantId, EntityId entityId, Set<AlarmStatus> status) {
  127 + return alarmRepository.findAlarmSeverities(tenantId.getId(), entityId.getId(), status);
  128 + }
123 129 }
... ...
... ... @@ -116,16 +116,16 @@ public class CassandraBaseTimeseriesDao extends AbstractCassandraBaseTimeseriesD
116 116 super.startExecutor();
117 117 if (!isInstall()) {
118 118 getFetchStmt(Aggregation.NONE, DESC_ORDER);
119   - Optional<NoSqlTsPartitionDate> partition = NoSqlTsPartitionDate.parse(partitioning);
120   - if (partition.isPresent()) {
121   - tsFormat = partition.get();
122   - if (!isFixedPartitioning() && partitionsCacheSize > 0) {
123   - cassandraTsPartitionsCache = new CassandraTsPartitionsCache(partitionsCacheSize);
124   - }
125   - } else {
126   - log.warn("Incorrect configuration of partitioning {}", partitioning);
127   - throw new RuntimeException("Failed to parse partitioning property: " + partitioning + "!");
  119 + }
  120 + Optional<NoSqlTsPartitionDate> partition = NoSqlTsPartitionDate.parse(partitioning);
  121 + if (partition.isPresent()) {
  122 + tsFormat = partition.get();
  123 + if (!isFixedPartitioning() && partitionsCacheSize > 0) {
  124 + cassandraTsPartitionsCache = new CassandraTsPartitionsCache(partitionsCacheSize);
128 125 }
  126 + } else {
  127 + log.warn("Incorrect configuration of partitioning {}", partitioning);
  128 + throw new RuntimeException("Failed to parse partitioning property: " + partitioning + "!");
129 129 }
130 130 }
131 131
... ...
... ... @@ -355,6 +355,62 @@ public abstract class BaseAlarmServiceTest extends AbstractServiceTest {
355 355 }
356 356
357 357 @Test
  358 + public void testFindHighestAlarmSeverity() throws ExecutionException, InterruptedException {
  359 + Customer customer = new Customer();
  360 + customer.setTitle("TestCustomer");
  361 + customer.setTenantId(tenantId);
  362 + customer = customerService.saveCustomer(customer);
  363 +
  364 + Device customerDevice = new Device();
  365 + customerDevice.setName("TestCustomerDevice");
  366 + customerDevice.setType("default");
  367 + customerDevice.setTenantId(tenantId);
  368 + customerDevice.setCustomerId(customer.getId());
  369 + customerDevice = deviceService.saveDevice(customerDevice);
  370 +
  371 + // no one alarms was created
  372 + Assert.assertNull(alarmService.findHighestAlarmSeverity(tenantId, customerDevice.getId(), null, null));
  373 +
  374 + Alarm alarm1 = Alarm.builder()
  375 + .tenantId(tenantId)
  376 + .originator(customerDevice.getId())
  377 + .type(TEST_ALARM)
  378 + .severity(AlarmSeverity.MAJOR)
  379 + .status(AlarmStatus.ACTIVE_UNACK)
  380 + .startTs(System.currentTimeMillis())
  381 + .build();
  382 + alarm1 = alarmService.createOrUpdateAlarm(alarm1).getAlarm();
  383 + alarmService.clearAlarm(tenantId, alarm1.getId(), null, System.currentTimeMillis()).get();
  384 +
  385 + Alarm alarm2 = Alarm.builder()
  386 + .tenantId(tenantId)
  387 + .originator(customerDevice.getId())
  388 + .type(TEST_ALARM)
  389 + .severity(AlarmSeverity.MINOR)
  390 + .status(AlarmStatus.ACTIVE_ACK)
  391 + .startTs(System.currentTimeMillis())
  392 + .build();
  393 + alarm2 = alarmService.createOrUpdateAlarm(alarm2).getAlarm();
  394 + alarmService.clearAlarm(tenantId, alarm2.getId(), null, System.currentTimeMillis()).get();
  395 +
  396 + Alarm alarm3 = Alarm.builder()
  397 + .tenantId(tenantId)
  398 + .originator(customerDevice.getId())
  399 + .type(TEST_ALARM)
  400 + .severity(AlarmSeverity.CRITICAL)
  401 + .status(AlarmStatus.ACTIVE_ACK)
  402 + .startTs(System.currentTimeMillis())
  403 + .build();
  404 + alarm3 = alarmService.createOrUpdateAlarm(alarm3).getAlarm();
  405 +
  406 + Assert.assertEquals(AlarmSeverity.MAJOR, alarmService.findHighestAlarmSeverity(tenantId, customerDevice.getId(), AlarmSearchStatus.UNACK, null));
  407 + Assert.assertEquals(AlarmSeverity.CRITICAL, alarmService.findHighestAlarmSeverity(tenantId, customerDevice.getId(), null, null));
  408 + Assert.assertEquals(AlarmSeverity.MAJOR, alarmService.findHighestAlarmSeverity(tenantId, customerDevice.getId(), null, AlarmStatus.CLEARED_UNACK));
  409 + Assert.assertEquals(AlarmSeverity.CRITICAL, alarmService.findHighestAlarmSeverity(tenantId, customerDevice.getId(), AlarmSearchStatus.ACTIVE, null));
  410 + Assert.assertEquals(AlarmSeverity.MINOR, alarmService.findHighestAlarmSeverity(tenantId, customerDevice.getId(), null, AlarmStatus.CLEARED_ACK));
  411 + }
  412 +
  413 + @Test
358 414 public void testFindAlarmUsingAlarmDataQuery() throws ExecutionException, InterruptedException {
359 415 AssetId parentId = new AssetId(Uuids.timeBased());
360 416 AssetId parentId2 = new AssetId(Uuids.timeBased());
... ...
... ... @@ -1170,7 +1170,7 @@ public class RestClient implements ClientHttpRequestInterceptor, Closeable {
1170 1170
1171 1171 public List<EntitySubtype> getDeviceTypes() {
1172 1172 return restTemplate.exchange(
1173   - baseURL + "/api/devices",
  1173 + baseURL + "/api/device/types",
1174 1174 HttpMethod.GET,
1175 1175 HttpEntity.EMPTY,
1176 1176 new ParameterizedTypeReference<List<EntitySubtype>>() {
... ...
... ... @@ -54,7 +54,10 @@
54 54 "share-via": "Sdílet přes {{provider}}",
55 55 "continue": "Pokračovat",
56 56 "discard-changes": "Zahodit změny",
57   - "download": "Stáhnout"
  57 + "download": "Stáhnout",
  58 + "next-with-label": "Další: {{label}}",
  59 + "read-more": "Zobrazit více",
  60 + "hide": "Skrýt"
58 61 },
59 62 "aggregation": {
60 63 "aggregation": "Agregace",
... ... @@ -77,6 +80,8 @@
77 80 "test-mail-sent": "Testovací zpráva byla úspěšně odeslána!",
78 81 "base-url": "Základní URL",
79 82 "base-url-required": "Hodnota Základní URL je povinná.",
  83 + "prohibit-different-url": "Zakázat použití názvu hosta z hlaviček požadavku klienta",
  84 + "prohibit-different-url-hint": "Toto nastavení by mělo být povoleno v produkčních prostředích. Pokud je zakázáno, může způsobit bezpečnostní problémy",
80 85 "mail-from": "Email od",
81 86 "mail-from-required": "Hodnota Email od je povinná.",
82 87 "smtp-protocol": "SMTP protokol",
... ... @@ -99,6 +104,33 @@
99 104 "proxy-user": "Uživatel proxy",
100 105 "proxy-password": "Heslo proxy",
101 106 "send-test-mail": "Odeslat testovací zprávu",
  107 + "sms-provider": "Poskytovatel SMS",
  108 + "sms-provider-settings": "Nastavení poskytovatele SMS",
  109 + "sms-provider-type": "Typ poskytovatele SMS",
  110 + "sms-provider-type-required": "Typ poskytovatele SMS je povinný.",
  111 + "sms-provider-type-aws-sns": "Amazon SNS",
  112 + "sms-provider-type-twilio": "Twilio",
  113 + "aws-access-key-id": "AWS Access Key ID",
  114 + "aws-access-key-id-required": "AWS Access Key ID je povinný",
  115 + "aws-secret-access-key": "AWS Secret Access Key",
  116 + "aws-secret-access-key-required": "AWS Secret Access Key je povinný",
  117 + "aws-region": "AWS Region",
  118 + "aws-region-required": "AWS Region je povinný",
  119 + "number-from": "Telefonní číslo odesílatele",
  120 + "number-from-required": "Telefonní číslo Odesílatele je povinné.",
  121 + "number-to": "Telefonní číslo příjemce",
  122 + "number-to-required": "Telefonní číslo příjemce je povinné.",
  123 + "phone-number-hint": "Telefonní číslo ve formátu E.164, např. +19995550123",
  124 + "phone-number-pattern": "Neplatné telefonní číslo. Mělo by odpovídat formátu E.164, např. +19995550123.",
  125 + "sms-message": "SMS zpráva",
  126 + "sms-message-required": "SMS zpráva je povinná.",
  127 + "sms-message-max-length": "SMS zpráva nemůže být delší než 1600 znaků",
  128 + "twilio-account-sid": "Twilio Account SID",
  129 + "twilio-account-sid-required": "Twilio Account SID je povinné",
  130 + "twilio-account-token": "Twilio Account Token",
  131 + "twilio-account-token-required": "Twilio Account Token je povinný",
  132 + "send-test-sms": "Odeslat testovací SMS",
  133 + "test-sms-sent": "Testovací SMS úspěšně odeslána!",
102 134 "security-settings": "Bezpečnostní nastavení",
103 135 "password-policy": "Politika hesel",
104 136 "minimum-password-length": "Minimální délka hesla",
... ... @@ -119,8 +151,74 @@
119 151 "general-policy": "Obecná politika",
120 152 "max-failed-login-attempts": "Maximální počet neúspěšných pokusů o přihlášení před zablokováním účtu",
121 153 "minimum-max-failed-login-attempts-range": "Maximální počet neúspěšných pokusů o přihlášení před zablokováním účtu nemůže být záporný",
122   - "user-lockout-notification-email": "V případě zablokování uživatelského účtu odeslat upozornění na email"
123   - },
  154 + "user-lockout-notification-email": "V případě zablokování uživatelského účtu odeslat upozornění na email",
  155 + "domain-name": "Doménové jméno",
  156 + "domain-name-unique": "Doménové jméno a protokol musí být unikátní.",
  157 + "error-verification-url": "Doménové jméno by nemělo obsahovat symbol '/' ani ':'. Příklad: thingsboard.io",
  158 + "oauth2": {
  159 + "access-token-uri": "URI přístupového tokenu",
  160 + "access-token-uri-required": "URI přístupového tokenu je povinné.",
  161 + "activate-user": "Aktivovat uživatele",
  162 + "add-domain": "Přidat doménu",
  163 + "delete-domain": "Smazat doménu",
  164 + "add-provider": "Přidat poskytovatele",
  165 + "delete-provider": "Smazat poskytovatele",
  166 + "allow-user-creation": "Povolit vytvoření uživatele",
  167 + "always-fullscreen": "Vždy v režimu celé obrazovky",
  168 + "authorization-uri": "Autorizační URI",
  169 + "authorization-uri-required": "Autorizační URI je povinné.",
  170 + "client-authentication-method": "Metoda autentizace klienta",
  171 + "client-id": "ID klienta",
  172 + "client-id-required": "ID klienta je povinné.",
  173 + "client-secret": "Heslo klienta",
  174 + "client-secret-required": "Heslo klienta je povinné.",
  175 + "custom-setting": "Vlastní nastavení",
  176 + "customer-name-pattern": "Vzor názvu zákazníka",
  177 + "default-dashboard-name": "Název defaultního dashboardu",
  178 + "delete-domain-text": "Budťe opatrní, protože po potvrzení nebudou doména ani žádná data poskytovatele dostupné.",
  179 + "delete-domain-title": "Jste si jisti, že chcete smazat nastavení domény '{{domainName}}'?",
  180 + "delete-registration-text": "Buďte opatrní, protože po potvrzení nebudou data poskytovatele dostupná.",
  181 + "delete-registration-title": "Jste si jisti, že chcete smazat poskytovatele '{{name}}'?",
  182 + "email-attribute-key": "Atribut klíče email",
  183 + "email-attribute-key-required": "Atribut klíče email je povinný.",
  184 + "first-name-attribute-key": "Atribut klíče jméno",
  185 + "general": "Obecné",
  186 + "jwk-set-uri": "JSON Web Key URI",
  187 + "last-name-attribute-key": "Atribut klíče příjmení",
  188 + "login-button-icon": "Ikona tlačítka přihlášení",
  189 + "login-button-label": "Označení poskytovatele",
  190 + "login-button-label-placeholder": "Přihlásit se přes $(Provider label)",
  191 + "login-button-label-required": "Označení je povinné.",
  192 + "login-provider": "Poskytovatel přihlášení",
  193 + "mapper": "Mapper",
  194 + "new-domain": "Nová doména",
  195 + "oauth2": "OAuth2",
  196 + "redirect-uri-template": "Šablona URI přesměrování",
  197 + "copy-redirect-uri": "Zkopírovat URI přesměrování",
  198 + "registration-id": "ID registrace",
  199 + "registration-id-required": "ID registrace je povinné.",
  200 + "registration-id-unique": "Id registrace musí být v systému unikátní.",
  201 + "scope": "Rozsah",
  202 + "scope-required": "Rozsah je povinný.",
  203 + "tenant-name-pattern": "Vzor názvu tenanta",
  204 + "tenant-name-pattern-required": "Vzor názvu tenanta je povinný.",
  205 + "tenant-name-strategy": "Strategie názvu tenanta",
  206 + "type": "Typ mapperu",
  207 + "uri-pattern-error": "Neplatný formát URI.",
  208 + "url": "URL",
  209 + "url-pattern": "Neplatný formát URL.",
  210 + "url-required": "URL je povinná.",
  211 + "user-info-uri": "User info URI",
  212 + "user-info-uri-required": "User info URI je povinné.",
  213 + "user-name-attribute-name": "Atribut klíče název uživatele",
  214 + "user-name-attribute-name-required": "Atribut klíče název uživatele je povinný",
  215 + "protocol": "Protokol",
  216 + "domain-schema-http": "HTTP",
  217 + "domain-schema-https": "HTTPS",
  218 + "domain-schema-mixed": "HTTP+HTTPS",
  219 + "enable": "Povolit nastavení OAuth2"
  220 + }
  221 + },
124 222 "alarm": {
125 223 "alarm": "Alarm",
126 224 "alarms": "Alarmy",
... ... @@ -128,6 +226,8 @@
128 226 "no-alarms-matching": "Žádné alarmy odpovídající '{{entity}}' nebyly nalezeny.",
129 227 "alarm-required": "Alarm je povinný",
130 228 "alarm-status": "Stav alarmu",
  229 + "alarm-status-list": "Seznam stavů alarmu",
  230 + "any-status": "Všechny stavy",
131 231 "search-status": {
132 232 "ANY": "Všechny",
133 233 "ACTIVE": "Aktivní",
... ... @@ -154,6 +254,8 @@
154 254 "end-time": "Datum ukončení",
155 255 "ack-time": "Datum přijetí",
156 256 "clear-time": "Datum vyřešení",
  257 + "alarm-severity-list": "Seznam závažností alarmu",
  258 + "any-severity": "Všechny závažnosti",
157 259 "severity-critical": "Kritická",
158 260 "severity-major": "Vysoká",
159 261 "severity-minor": "Nízká",
... ... @@ -176,12 +278,16 @@
176 278 "clear-alarm-title": "Odstranit alarm",
177 279 "clear-alarm-text": "Jste si jisti, že chcete alarm odstranit?",
178 280 "alarm-status-filter": "Filtr stavu alarmu",
  281 + "alarm-filter": "Filtr alarmu",
179 282 "max-count-load": "Maximální počet nahraných alarmů (0 - neomezeně)",
180 283 "max-count-load-required": "Maximální počet nahraných alarmů je povinný.",
181 284 "max-count-load-error-min": "Minimální hodnota je 0.",
182 285 "fetch-size": "Velikost dávky",
183 286 "fetch-size-required": "Velikost dávky je povinná.",
184   - "fetch-size-error-min": "Minimální hodnota je 10."
  287 + "fetch-size-error-min": "Minimální hodnota je 10.",
  288 + "alarm-type-list": "Seznam typů alarmu",
  289 + "any-type": "Všechny typy",
  290 + "search-propagated-alarms": "Vyhledat zpropagované alarmy"
185 291 },
186 292 "alias": {
187 293 "add": "Přidat alias",
... ... @@ -211,6 +317,7 @@
211 317 "filter-type-device-search-query-description": "Zařízení typů {{deviceTypes}} se {{relationType}} vztahem {{direction}} {{rootEntity}}",
212 318 "filter-type-entity-view-search-query": "Dotaz na vyhledání zobrazení entity",
213 319 "filter-type-entity-view-search-query-description": "Entitní pohledy typů {{entityViewTypes}} se {{relationType}} vztahem {{direction}} {{rootEntity}}",
  320 + "filter-type-apiUsageState": "Stav využití Api",
214 321 "entity-filter": "Filtr entity",
215 322 "resolve-multiple": "Použít jako více entit",
216 323 "filter-type": "Typ filtru",
... ... @@ -325,6 +432,59 @@
325 432 "no-attributes-text": "Žádné atributy nebyly nalezeny",
326 433 "no-telemetry-text": "Žádná telemetrie nebyla nalezena"
327 434 },
  435 + "api-usage": {
  436 + "api-usage": "Využití Api",
  437 + "data-points": "Datové body",
  438 + "data-points-storage-days": "Dny uložení datových bodů",
  439 + "email": "Email",
  440 + "email-messages": "Emailové zprávy",
  441 + "email-messages-daily-activity": "Denní aktivita emailových zpráv",
  442 + "email-messages-hourly-activity": "Hodinová aktivita emailových zpráv",
  443 + "email-messages-monthly-activity": "Měsíční aktivita emailových zpráv",
  444 + "exceptions": "Výjimky",
  445 + "executions": "Zpracování",
  446 + "javascript": "JavaScript",
  447 + "javascript-executions": "JavaScript výjimky",
  448 + "javascript-functions": "JavaScript funkce",
  449 + "javascript-functions-daily-activity": "Denní aktivita JavaScript funkcí",
  450 + "javascript-functions-hourly-activity": "Hodinová aktivita JavaScript funkcí",
  451 + "javascript-functions-monthly-activity": "Měsíční aktivita JavaScript funkcí",
  452 + "latest-error": "Poslední chyba",
  453 + "messages": "Zprávy",
  454 + "permanent-failures": "${entityName} permanentní chyby",
  455 + "permanent-timeouts": "${entityName} permanentní timeouty",
  456 + "processing-failures": "${entityName} chyby zpracování",
  457 + "processing-failures-and-timeouts": "Chyby a timeouty zpracování",
  458 + "processing-timeouts": "${entityName} timeouty zpracování",
  459 + "queue-stats": "Statistiky fronty",
  460 + "rule-chain": "Řetěz pravidel",
  461 + "rule-engine": "Engine pro zpracování pravidel",
  462 + "rule-engine-daily-activity": "Denní aktivita enginu pro zpracování pravidel",
  463 + "rule-engine-executions": "Zpracování Enginu pro zpracování pravidel",
  464 + "rule-engine-hourly-activity": "Hodinová aktivita enginu pro zpracování pravidel",
  465 + "rule-engine-monthly-activity": "Měsíční aktivita enginu pro zpracování pravidel",
  466 + "rule-engine-statistics": "Statistiky enginu pro zpracování pravidel",
  467 + "rule-node": "Uzel pravidla",
  468 + "sms": "SMS",
  469 + "sms-messages": "SMS zprávy",
  470 + "sms-messages-daily-activity": "Denní aktivita SMS zpráv",
  471 + "sms-messages-hourly-activity": "Hodinová aktivita SMS zpráv",
  472 + "sms-messages-monthly-activity": "Měsíční aktivita SMS zpráv",
  473 + "successful": "${entityName} úspěšnost",
  474 + "telemetry": "Telemetrie",
  475 + "telemetry-persistence": "Uložení telemetrie",
  476 + "telemetry-persistence-daily-activity": "Denní aktivita uložení telemetrie",
  477 + "telemetry-persistence-hourly-activity": "Hodinová aktivita uložení telemetrie",
  478 + "telemetry-persistence-monthly-activity": "Měsíční aktivita uložení telemetrie",
  479 + "transport": "Přenos",
  480 + "transport-daily-activity": "Denní aktivita přenosu",
  481 + "transport-data-points": "Datové body přenosu",
  482 + "transport-hourly-activity": "Hodinová aktivita přenosu",
  483 + "transport-messages": "Zprávy přenosu",
  484 + "transport-monthly-activity": "Měsíční aktivita přenosu",
  485 + "view-details": "Zobrazit detail",
  486 + "view-statistics": "Zobrazit statistiky"
  487 + },
328 488 "audit-log": {
329 489 "audit": "Audit",
330 490 "audit-logs": "Záznamy auditu",
... ... @@ -363,7 +523,13 @@
363 523 "action-data": "Data akce",
364 524 "failure-details": "Detail chyby",
365 525 "search": "Prohledat záznamy auditu",
366   - "clear-search": "Vymazat vyhledávání"
  526 + "clear-search": "Vymazat vyhledávání",
  527 + "type-assigned-from-tenant": "Odebráno tenantovi",
  528 + "type-assigned-to-tenant": "Přiřazeno tenantovi",
  529 + "type-provision-success": "Zřízení zařízení",
  530 + "type-provision-failure": "Selhání zřízení zařízení",
  531 + "type-timeseries-updated": "Aktualizace telemetrie",
  532 + "type-timeseries-deleted": "Smazání telemetrie"
367 533 },
368 534 "confirm-on-exit": {
369 535 "message": "Některé změny nebyly uloženy. Jste si jisti, že chcete tuto stránku opustit?",
... ... @@ -549,6 +715,7 @@
549 715 "title-color": "Barva názvu",
550 716 "display-dashboards-selection": "Zobrazit výběr dashboardů",
551 717 "display-entities-selection": "Zobrazit výběr entit",
  718 + "display-filters": "Zobrazit filtry",
552 719 "display-dashboard-timewindow": "Zobrazit časové okno",
553 720 "display-dashboard-export": "Zobrazit export",
554 721 "import": "Importovat dashboard",
... ... @@ -615,6 +782,7 @@
615 782 "alarm": "Pole alarmu",
616 783 "timeseries-required": "Časové řady entity jsou povinné.",
617 784 "timeseries-or-attributes-required": "Časové řady / atributy entity jsou povinné.",
  785 + "alarm-fields-timeseries-or-attributes-required": "Pole alarmu nebo časové řady / atributy jsou povinné.",
618 786 "maximum-timeseries-or-attributes": "Maximálně { count, plural, 1 {1 časová řada/atribut je povolena.} other {# časových řad/atributů je povoleno} }",
619 787 "alarm-fields-required": "Pole alarmu jsou povinná.",
620 788 "function-types": "Typy funkcí",
... ... @@ -706,6 +874,12 @@
706 874 "access-token-invalid": "Délka přístupového tokenu musí být od 1 do 20 znaků.",
707 875 "rsa-key": "RSA veřejný klíč",
708 876 "rsa-key-required": "RSA veřejný klíč je povinný.",
  877 + "client-id": "ID klienta",
  878 + "client-id-pattern": "Obsahuje neplatné znaky.",
  879 + "user-name": "Název uživatele",
  880 + "user-name-required": "Název uživatele je povinný.",
  881 + "client-id-or-user-name-necessary": "ID klienta a/nebo název uživatele jsou povinné",
  882 + "password": "Heslo",
709 883 "secret": "Heslo",
710 884 "secret-required": "Heslo je povinné.",
711 885 "device-type": "Typ zařízení",
... ... @@ -724,19 +898,183 @@
724 898 "details": "Detail",
725 899 "copyId": "Kopírovat Id zařízení",
726 900 "copyAccessToken": "Kopírovat přístupový token",
  901 + "copy-mqtt-authentication": "Kopírovat přístupové údaje MQTT",
727 902 "idCopiedMessage": "Id zařízení bylo zkopírováno do schránky",
728 903 "accessTokenCopiedMessage": "Přístupový token zařízení byl zkopírován do schránky",
  904 + "mqtt-authentication-copied-message": "MQTT autentizace zařízení byla zkopírována do schránky",
729 905 "assignedToCustomer": "Přiřazeno zákazníkovi",
730 906 "unable-delete-device-alias-title": "Nebylo možné smazat alias zařízení",
731 907 "unable-delete-device-alias-text": "Alias zařízení '{{deviceAlias}}' nelze smazat, protože je používán následujícími widgety:<br/>{{widgetsList}}",
732 908 "is-gateway": "Je bránou",
  909 + "overwrite-activity-time": "Přepsat čas aktivity připojeného zařízení",
733 910 "public": "Veřejné",
734 911 "device-public": "Zařízení je veřejné",
735 912 "select-device": "Vybrat zařízení",
736 913 "import": "Importovat zařízení",
737 914 "device-file": "Soubor zařízení",
738 915 "search": "Vyhledat zařízení",
739   - "selected-devices": "Vybráno { count, plural, 1 {1 zařízení} other {# zařízení} }"
  916 + "selected-devices": "Vybráno { count, plural, 1 {1 zařízení} other {# zařízení} }",
  917 + "device-configuration": "Konfigurace zařízení",
  918 + "transport-configuration": "Konfigurace přenosu",
  919 + "wizard": {
  920 + "device-wizard": "Průvodce zařízením",
  921 + "device-details": "Detail zařízení",
  922 + "new-device-profile": "Vytvořit nový profil zařízení",
  923 + "existing-device-profile": "Vybrat existující profil zařízení",
  924 + "specific-configuration": "Specifická konfigurace",
  925 + "customer-to-assign-device": "Přiřadit zařízení zákazníkovi",
  926 + "add-credential": "Přidat přístupový údaj"
  927 + }
  928 + },
  929 + "device-profile": {
  930 + "device-profile": "Profil zařízení",
  931 + "device-profiles": "Profily zařízení",
  932 + "all-device-profiles": "Všechny",
  933 + "add": "Přidat profil zařízení",
  934 + "edit": "Editovat profil zařízení",
  935 + "device-profile-details": "Detail profilu zařízení",
  936 + "no-device-profiles-text": "Žádné profily zařízení nebyly nalezeny",
  937 + "search": "Vyhledat profily zařízení",
  938 + "selected-device-profiles": "Vybráno { count, plural, 1 {1 profil zařízení} other {# profilů zařízení} }",
  939 + "no-device-profiles-matching": "Žádný profil zařízení odpovídající '{{entity}}' nebyl nalezen.",
  940 + "device-profile-required": "Profil zařízení je povinný",
  941 + "idCopiedMessage": "Id profilu zařízení bylo zkopírováno do schránky",
  942 + "set-default": "Učinit profil zařízení defaultním",
  943 + "delete": "Smazat profil zařízení",
  944 + "copyId": "Kopírovat Id profilu zařízení",
  945 + "new-device-profile-name": "Název profilu zařízení",
  946 + "new-device-profile-name-required": "Název profilu zařízení je povinný.",
  947 + "name": "Název",
  948 + "name-required": "Název je povinný.",
  949 + "type": "Typ profilu",
  950 + "type-required": "Typ profilu je povinný.",
  951 + "type-default": "Defaultní",
  952 + "transport-type": "Typ přenosu",
  953 + "transport-type-required": "Typ přenosu je povinný.",
  954 + "transport-type-default": "Defaultní",
  955 + "transport-type-default-hint": "Podporuje základní MQTT, HTTP and CoAP přenos",
  956 + "transport-type-mqtt": "MQTT",
  957 + "transport-type-mqtt-hint": "Umožňuje pokročilé nastavení MQTT přenosu",
  958 + "transport-type-lwm2m": "LWM2M",
  959 + "transport-type-lwm2m-hint": "Typ transportu LWM2M",
  960 + "description": "Popis",
  961 + "default": "Defaultní",
  962 + "profile-configuration": "Konfigurace profilu",
  963 + "transport-configuration": "Konfigurace přenosu",
  964 + "default-rule-chain": "Defaultní řetěz pravidel",
  965 + "select-queue-hint": "Vyberte z rozbalovacího seznamu nebo přidejte vlastní název.",
  966 + "delete-device-profile-title": "Jste si jisti, že chcete smazat profil zařízení '{{deviceProfileName}}'?",
  967 + "delete-device-profile-text": "Buďte opatrní, protože po potvrzení nebude možné profil zařízení ani žádná související data obnovit.",
  968 + "delete-device-profiles-title": "Jste si jisti, že chcete smazat { count, plural, 1 {1 profil zařízení} other {# profilů zařízení} }?",
  969 + "delete-device-profiles-text": "Buďte opatrní, protože po potvrzení budou všechny vybrané profily zařízení odstraněny a žádná související data nebude možné obnovit.",
  970 + "set-default-device-profile-title": "Jste si jisti, že chcete profil zařízení '{{deviceProfileName}}' učinit defaultním?",
  971 + "set-default-device-profile-text": "Po potvrzení bude profil zařízení označen jako defaultní a bude použit pro nová zařízení bez specifikovaného profilu.",
  972 + "no-device-profiles-found": "Žádné profily zařízení nebyly nalezeny.",
  973 + "create-new-device-profile": "Vytvořit nový!",
  974 + "mqtt-device-topic-filters": "Filtry MQTT fronty zařízení",
  975 + "mqtt-device-topic-filters-unique": "Filtry MQTT fronty zařízení musí být unikátní.",
  976 + "mqtt-device-payload-type": "MQTT zpráva zařízení",
  977 + "mqtt-device-payload-type-json": "JSON",
  978 + "mqtt-device-payload-type-proto": "Protobuf",
  979 + "mqtt-payload-type-required": "Typ zprávy je povinný.",
  980 + "support-level-wildcards": "Jsou podporovány jednoúrovňové <code>[+]</code> a víceúrovňové <code>[#]</code> zástupné znaky.",
  981 + "telemetry-topic-filter": "Filtr fronty telemetrie",
  982 + "telemetry-topic-filter-required": "Filtr fronty telemetrie je povinný.",
  983 + "attributes-topic-filter": "Filtr atributů fronty",
  984 + "attributes-topic-filter-required": "Filtr atributů fronty je povinný.",
  985 + "telemetry-proto-schema": "Proto schéma telemetrie",
  986 + "telemetry-proto-schema-required": "Proto schéma telemetrie je povinné.",
  987 + "attributes-proto-schema": "Atributy proto schémata",
  988 + "attributes-proto-schema-required": "Atributy proto schémata jsou povinné.",
  989 + "rpc-response-topic-filter": "Filtr fronty RPC odpovědi",
  990 + "rpc-response-topic-filter-required": "Filtr fronty RPC odpovědi je povinný.",
  991 + "not-valid-pattern-topic-filter": "Neplatný vzor filtru fronty",
  992 + "not-valid-single-character": "Neplatné použití jednoúrovňového zástupného znaku",
  993 + "not-valid-multi-character": "Neplatné použití víceúrovňového zástupného znaku",
  994 + "single-level-wildcards-hint": "<code>[+]</code> je vhodný pro jakoukoli úroveň filtru fronty. Př.: <b>v1/devices/+/telemetry</b> or <b>+/devices/+/attributes</b>.",
  995 + "multi-level-wildcards-hint": "<code>[#]</code> může nahradit filtr fronty a může se jednat o poslední symbol fronty. Př.: <b>#</b> or <b>v1/devices/me/#</b>.",
  996 + "alarm-rules": "Pravidla alarmu",
  997 + "alarm-rules-with-count": "Pravidla alarmu ({{count}})",
  998 + "no-alarm-rules": "Žádná pravidla alarmu nejsou konfigurována",
  999 + "add-alarm-rule": "Přidat pravidlo alarmu",
  1000 + "edit-alarm-rule": "Editovat pravidlo alarmu",
  1001 + "alarm-type": "Typ alarmu",
  1002 + "alarm-type-required": "Typ alarmu je povinný.",
  1003 + "alarm-type-unique": "Typ alarmu musí být v rámci pravidel alarmu profilu zařízení unikátní.",
  1004 + "create-alarm-pattern": "Vytvořit <b>{{alarmType}}</b> alarm",
  1005 + "create-alarm-rules": "Vytvořit pravidla alarmu",
  1006 + "no-create-alarm-rules": "Nejsou konfigurovány žádné podmínky vytvoření",
  1007 + "add-create-alarm-rule-prompt": "Přidejte prosím pravidlo vytvoření alarmu",
  1008 + "clear-alarm-rule": "Pravidlo zrušení alarmu",
  1009 + "no-clear-alarm-rule": "Není konfigurována žádná podmínka zrušení",
  1010 + "add-create-alarm-rule": "Přidat podmínku vytvoření",
  1011 + "add-clear-alarm-rule": "Přidat podmínku zrušení",
  1012 + "select-alarm-severity": "Vybrat závažnost alarmu",
  1013 + "alarm-severity-required": "Závažnost alarmu je povinná.",
  1014 + "condition-duration": "Doba trvání podmínky",
  1015 + "condition-duration-value": "Hodnota doby trvání",
  1016 + "condition-duration-time-unit": "Jednotka času",
  1017 + "condition-duration-value-range": "Hodnota doby trvání musí být v rozsahu od 1 do 2147483647.",
  1018 + "condition-duration-value-pattern": "Doba trvání musí být celé číslo.",
  1019 + "condition-duration-value-required": "Doba trvání je povinná.",
  1020 + "condition-duration-time-unit-required": "Jednotka času je povinná.",
  1021 + "advanced-settings": "Pokročilá nastavení",
  1022 + "alarm-rule-details": "Detail",
  1023 + "add-alarm-rule-details": "Přidat detail",
  1024 + "propagate-alarm": "Propagovat alarm",
  1025 + "alarm-rule-relation-types-list": "Typy vztahů ke zpropagování",
  1026 + "alarm-rule-relation-types-list-hint": "Pokud nejsou vybrány žádné typy vztahů, alarmy budou propagovány bez filtru typu vztahu.",
  1027 + "alarm-details": "Detail alarmu",
  1028 + "alarm-rule-condition": "Podmínka pravidla alarmu",
  1029 + "enter-alarm-rule-condition-prompt": "Přidejte prosím podmínku pravidla alarmu",
  1030 + "edit-alarm-rule-condition": "Editovat podmínku pravidla alarmu",
  1031 + "device-provisioning": "Zřízení zařízení",
  1032 + "provision-strategy": "Strategie zřízení",
  1033 + "provision-strategy-required": "Strategie zřízení je povinná.",
  1034 + "provision-strategy-disabled": "Zakázáno",
  1035 + "provision-strategy-created-new": "Povolit vytváření nových zařízení",
  1036 + "provision-strategy-check-pre-provisioned": "Zkontrolovat předvytvořená zařízení",
  1037 + "provision-device-key": "Klíč pro zřízení zařízení",
  1038 + "provision-device-key-required": "Klíč pro zřízení zařízení je povinný.",
  1039 + "copy-provision-key": "Kopírovat klíč pro zřízení",
  1040 + "provision-key-copied-message": "Klíč pro zřízení byl zkopírován do schránky",
  1041 + "provision-device-secret": "Heslo pro zřízení zařízení",
  1042 + "provision-device-secret-required": "Heslo pro zřízení zařízení je povinné.",
  1043 + "copy-provision-secret": "Kopírovat heslo pro zřízení",
  1044 + "provision-secret-copied-message": "Heslo pro zřízení zařízení bylo zkopírováno do schránky",
  1045 + "condition": "Podmínka",
  1046 + "condition-type": "Typ podmínky",
  1047 + "condition-type-simple": "Jednoduchá",
  1048 + "condition-type-duration": "Doba trvání",
  1049 + "condition-during": "V průběhu {{during}}",
  1050 + "condition-type-repeating": "Opakování",
  1051 + "condition-type-required": "Typ podmínky je povinný.",
  1052 + "condition-repeating-value": "Počet událostí",
  1053 + "condition-repeating-value-range": "Počet událostí musí být v rozsahu od 1 do 2147483647.",
  1054 + "condition-repeating-value-pattern": "Počet událostí musí být celé číslo.",
  1055 + "condition-repeating-value-required": "Počet událostí je povinný.",
  1056 + "condition-repeat-times": "Opakování { count, plural, 1 {1 krát} other {# krát} }",
  1057 + "schedule-type": "Typ plánovače",
  1058 + "schedule-type-required": "Typ plánovače je povinný.",
  1059 + "schedule": "Časový plán",
  1060 + "edit-schedule": "Editovat časový plán alarmu",
  1061 + "schedule-any-time": "Aktivní neustále",
  1062 + "schedule-specific-time": "Aktivní v konkrétním čase",
  1063 + "schedule-custom": "Vlastní",
  1064 + "schedule-day": {
  1065 + "monday": "Pondělí",
  1066 + "tuesday": "Úterý",
  1067 + "wednesday": "Středa",
  1068 + "thursday": "Čtvrtek",
  1069 + "friday": "Pátek",
  1070 + "saturday": "Sobota",
  1071 + "sunday": "Neděle"
  1072 + },
  1073 + "schedule-days": "Dny",
  1074 + "schedule-time": "Čas",
  1075 + "schedule-time-from": "Od",
  1076 + "schedule-time-to": "Do",
  1077 + "schedule-days-of-week-required": "Musí být vybrán minimálně jeden den v týdnu."
740 1078 },
741 1079 "dialog": {
742 1080 "close": "Zavřít dialog"
... ... @@ -757,7 +1095,7 @@
757 1095 "entity-alias": "Alias entity",
758 1096 "unable-delete-entity-alias-title": "Alias entity nebylo možné smazat",
759 1097 "unable-delete-entity-alias-text": "Alias entity '{{entityAlias}}' nelze smazat, protože je používán následujícími widgety:<br/>{{widgetsList}}",
760   - "duplicate-alias-error": "Nalezen dupliticní alias '{{alias}}'.<br>Aliasy entit musí být v rámci dashboardu unikátní.",
  1098 + "duplicate-alias-error": "Nalezen duplicitní alias '{{alias}}'.<br>Aliasy entit musí být v rámci dashboardu unikátní.",
761 1099 "missing-entity-filter-error": "Ve filtru chybí alias '{{alias}}'.",
762 1100 "configure-alias": "Konfigurovat '{{alias}}' alias",
763 1101 "alias": "Alias",
... ... @@ -794,6 +1132,10 @@
794 1132 "type-devices": "Zařízení",
795 1133 "list-of-devices": "{ count, plural, 1 {Jedno zařízení} other {Seznam # zařízení} }",
796 1134 "device-name-starts-with": "Zařízení, jejichž název začíná '{{prefix}}'",
  1135 + "type-device-profile": "Profil zařízení",
  1136 + "type-device-profiles": "Profily zařízení",
  1137 + "list-of-device-profiles": "{ count, plural, 1 {Jeden profil zařízení} other {Seznam # profilů zařízení} }",
  1138 + "device-profile-name-starts-with": "Profily zařízení, jejichž název začíná '{{prefix}}'",
797 1139 "type-asset": "Aktivum",
798 1140 "type-assets": "Aktiva",
799 1141 "list-of-assets": "{ count, plural, 1 {Jedno aktivum} other {Seznam # aktiv} }",
... ... @@ -814,6 +1156,10 @@
814 1156 "type-tenants": "Tenanti",
815 1157 "list-of-tenants": "{ count, plural, 1 {Jeden tenant} other {Seznam # tenantů} }",
816 1158 "tenant-name-starts-with": "Tenanti, jejichž název začíná '{{prefix}}'",
  1159 + "type-tenant-profile": "Profil tenanta",
  1160 + "type-tenant-profiles": "Profily tenantů",
  1161 + "list-of-tenant-profiles": "{ count, plural, 1 {Jeden profil tenanta} other {Seznam # profilů tenantů} }",
  1162 + "tenant-profile-name-starts-with": "Profily tenantů, jejichž název začíná '{{prefix}}'",
817 1163 "type-customer": "Zákazník",
818 1164 "type-customers": "Zákazníci",
819 1165 "list-of-customers": "{ count, plural, 1 {Jeden zákazník} other {Seznam # zákazníků} }",
... ... @@ -840,6 +1186,8 @@
840 1186 "rulenode-name-starts-with": "Uzly pravidel, jejichž název začíná '{{prefix}}'",
841 1187 "type-current-customer": "Stávající zákazník",
842 1188 "type-current-tenant": "Stávající tenant",
  1189 + "type-current-user": "Stávající uživatel",
  1190 + "type-current-user-owner": "Vlastník stávajícího uživatele",
843 1191 "search": "Vyhledat entity",
844 1192 "selected-entities": "{ count, plural, 1 {1 entita} other {# entit} } zvoleno",
845 1193 "entity-name": "Název entity",
... ... @@ -847,7 +1195,8 @@
847 1195 "details": "Detail entity",
848 1196 "no-entities-prompt": "Žádné entity nebyly nalezeny",
849 1197 "no-data": "Nelze zobrazit žádná data",
850   - "columns-to-display": "Zobrazit sloupce"
  1198 + "columns-to-display": "Zobrazit sloupce",
  1199 + "type-api-usage-state": "Stav využití API"
851 1200 },
852 1201 "entity-field": {
853 1202 "created-time": "Datum vytvoření",
... ... @@ -1048,7 +1397,7 @@
1048 1397 "anonymous": "Anonymní",
1049 1398 "basic": "Základní",
1050 1399 "pem": "PEM",
1051   - "ca-cert": "soubor CA certifikátu *",
  1400 + "ca-cert": "Soubor CA certifikátu *",
1052 1401 "private-key": "Soubor privátního klíče *",
1053 1402 "cert": "Soubor certifikátu *",
1054 1403 "no-file": "Žádný soubor nebyl vybrán.",
... ... @@ -1154,6 +1503,93 @@
1154 1503 "file": "Soubor rozšíření",
1155 1504 "invalid-file-error": "Neplatný soubor rozšíření"
1156 1505 },
  1506 + "filter": {
  1507 + "add": "Přidat filtr",
  1508 + "edit": "Editovat filtr",
  1509 + "name": "Název filtru",
  1510 + "name-required": "Název filtru je povinný.",
  1511 + "duplicate-filter": "Filtr s identickým názvem již existuje.",
  1512 + "filters": "Filtry",
  1513 + "unable-delete-filter-title": "Smazat filtr není možné",
  1514 + "unable-delete-filter-text": "Filtr '{{filter}}' není možné smazat, protože je používán následujícím widgetem(y):<br/>{{widgetsList}}",
  1515 + "duplicate-filter-error": "Nalezen duplicitní filtr '{{filter}}'.<br>Filtry musí být v rámci dashboardu unikátní.",
  1516 + "missing-key-filters-error": "U filtru '{{filter}}' chybí klíčové filtry.",
  1517 + "filter": "Filtr",
  1518 + "editable": "Editovatelné",
  1519 + "no-filters-found": "Žádné filtry nebyly nalezeny.",
  1520 + "no-filter-text": "Není specifikován žádný filtr",
  1521 + "add-filter-prompt": "Přidejte prosím filtr",
  1522 + "no-filter-matching": "'{{filter}}' nebyl nalezen.",
  1523 + "create-new-filter": "Vytvořit nový!",
  1524 + "filter-required": "Filtr je povinný.",
  1525 + "operation": {
  1526 + "operation": "Operace",
  1527 + "equal": "je rovno",
  1528 + "not-equal": "není rovno",
  1529 + "starts-with": "začíná na",
  1530 + "ends-with": "končí na",
  1531 + "contains": "obsahuje",
  1532 + "not-contains": "neobsahuje",
  1533 + "greater": "větší než",
  1534 + "less": "menší než",
  1535 + "greater-or-equal": "větší nebo rovno",
  1536 + "less-or-equal": "menší nebo rovno",
  1537 + "and": "a",
  1538 + "or": "nebo"
  1539 + },
  1540 + "ignore-case": "ignorovat velikost písmen",
  1541 + "value": "Hodnota",
  1542 + "remove-filter": "Odebrat filtr",
  1543 + "preview": "Náhled filtru",
  1544 + "no-filters": "Nejsou konfigurovány žádné filtry",
  1545 + "add-filter": "Přidat filtr",
  1546 + "add-complex-filter": "Přidat komplexní filtr",
  1547 + "add-complex": "Přidat komplex",
  1548 + "complex-filter": "Komplexní filtr",
  1549 + "edit-complex-filter": "Editovat komplexní filtr",
  1550 + "edit-filter-user-params": "Editovat filtr predikátu parametrů uživatele",
  1551 + "filter-user-params": "Filtr predikátu parametrů uživatele",
  1552 + "user-parameters": "Parametry uživatele",
  1553 + "display-label": "Zobrazované označení",
  1554 + "autogenerated-label": "Automaticky vygenerovat označení",
  1555 + "order-priority": "Priority pořadí polí",
  1556 + "key-filter": "Klíčový filtr",
  1557 + "key-filters": "Klíčové filtry",
  1558 + "key-name": "Název klíče",
  1559 + "key-name-required": "Název klíče je povinný.",
  1560 + "key-type": {
  1561 + "key-type": "Typ klíče",
  1562 + "attribute": "Atribut",
  1563 + "timeseries": "Časové řady",
  1564 + "entity-field": "Pole entity"
  1565 + },
  1566 + "value-type": {
  1567 + "value-type": "Typ hodnoty",
  1568 + "string": "Řetězec",
  1569 + "numeric": "Číslo",
  1570 + "boolean": "Pravdivostní hodnota",
  1571 + "date-time": "Datum a čas"
  1572 + },
  1573 + "value-type-required": "Typ hodnoty klíče je povinný.",
  1574 + "key-value-type-change-title": "Jste si jisti, že chcete změnit typ klíče hodnoty?",
  1575 + "key-value-type-change-message": "Pokud potvrdíte nový typ hodnoty, všechny zadané klíčové filtry budou odstraněny.",
  1576 + "no-key-filters": "Nejsou konfigurovány žádné klíčové filtry",
  1577 + "add-key-filter": "Přidat klíčový filtr",
  1578 + "remove-key-filter": "Odebrat klíčový filtr",
  1579 + "edit-key-filter": "Editovat klíčový filtr",
  1580 + "date": "Datum",
  1581 + "time": "Čas",
  1582 + "current-tenant": "Stávající tenant",
  1583 + "current-customer": "Stávající zákazník",
  1584 + "current-user": "Stávající uživatel",
  1585 + "current-device": "Stávající zařízení",
  1586 + "default-value": "Defaultní hodnota",
  1587 + "dynamic-source-type": "Dynamický typ zdroje",
  1588 + "no-dynamic-value": "Žádná dynamická hodnota",
  1589 + "source-attribute": "Atribut zdroje",
  1590 + "switch-to-dynamic-value": "Přepnout na dynamickou hodnotu",
  1591 + "switch-to-default-value": "Přepnout na defaultní hodnotu"
  1592 + },
1157 1593 "fullscreen": {
1158 1594 "expand": "Rozšířit do režimu celé obrazovky",
1159 1595 "exit": "Ukončit režim celé obrazovky",
... ... @@ -1286,6 +1722,7 @@
1286 1722 "entity-field": "Pole entity",
1287 1723 "access-token": "Přístupový token",
1288 1724 "isgateway": "Je bránou",
  1725 + "activity-time-from-gateway-device": "Čas aktivity ze zařízení brány",
1289 1726 "description": "Popis"
1290 1727 },
1291 1728 "stepper-text":{
... ... @@ -1329,6 +1766,7 @@
1329 1766 "legend": {
1330 1767 "direction": "Směr legendy",
1331 1768 "position": "Pozice legendy",
  1769 + "sort-legend": "Setřídit datové klíče v legendě",
1332 1770 "show-max": "Zobrazit max hodnotu",
1333 1771 "show-min": "Zobrazit min hodnotu",
1334 1772 "show-avg": "Zobrazit průměrnou hodnotu",
... ... @@ -1525,6 +1963,12 @@
1525 1963 "help": "Nápověda",
1526 1964 "reset-debug-mode": "Resetovat režim ladění na všech uzlech"
1527 1965 },
  1966 + "timezone": {
  1967 + "timezone": "Časová zóna",
  1968 + "select-timezone": "Vyberte časovou zónu",
  1969 + "no-timezones-matching": "žádné časové zóny odpovídající '{{timezone}}' nebyly nalezeny.",
  1970 + "timezone-required": "Časová zóna je povinná."
  1971 + },
1528 1972 "queue": {
1529 1973 "select_name": "Vybrat název fronty",
1530 1974 "name": "Název fronty",
... ... @@ -1563,6 +2007,87 @@
1563 2007 "isolated-tb-core-details": "Vyžaduje samostatnou mikroslužbu(y) pro každého izolovaného tenanta",
1564 2008 "isolated-tb-rule-engine-details": "Vyžaduje samostatnou mikroslužbu(y) pro každého izolovaného tenanta"
1565 2009 },
  2010 + "tenant-profile": {
  2011 + "tenant-profile": "Profil tenanta",
  2012 + "tenant-profiles": "Profily tenantů",
  2013 + "add": "Přidat profil tenanta",
  2014 + "edit": "Editovat profil tenanta",
  2015 + "tenant-profile-details": "Detail profilu tenanta",
  2016 + "no-tenant-profiles-text": "Nebyly nalezeny žádné profily tenantů",
  2017 + "search": "Vyhledat profily tenantů",
  2018 + "selected-tenant-profiles": "Vybráno { count, plural, 1 {1 profilů tenantů} other {# profilů tenantů} }",
  2019 + "no-tenant-profiles-matching": "Žádné profily tenantů odpovídající '{{entity}}' nebyly nalezeny.",
  2020 + "tenant-profile-required": "Profil tenanta je povinný",
  2021 + "idCopiedMessage": "Id profilu tenanta bylo zkopírováno do schránky",
  2022 + "set-default": "Učinit profil tenanta defaultním",
  2023 + "delete": "Smazat profil tenanta",
  2024 + "copyId": "Kopírovat Id profilu tenanta",
  2025 + "name": "Název",
  2026 + "name-required": "Název je povinný.",
  2027 + "data": "Data profilu",
  2028 + "profile-configuration": "Konfigurace profilu",
  2029 + "description": "Popis",
  2030 + "default": "Defaultní",
  2031 + "delete-tenant-profile-title": "Jste si jisti, že chcete smazat profil tenanta '{{tenantProfileName}}'?",
  2032 + "delete-tenant-profile-text": "Buďte opatrní, protože po potvrzení nebude možné profil tenanta ani žádná související data obnovit.",
  2033 + "delete-tenant-profiles-title": "Jste si jisti, že chcete smazat { count, plural, 1 {1 profil tenanta} other {# profilů tenanta} }?",
  2034 + "delete-tenant-profiles-text": "Buďte opatrní, protože po potvrzení budou všechny vybrané profily tenantů odstraněny a žádná související data nebude možné obnovit.",
  2035 + "set-default-tenant-profile-title": "Jste si jisti, že chcete učinit profil tenanta '{{tenantProfileName}}' defaultním?",
  2036 + "set-default-tenant-profile-text": "Po potvrzení bude profil tenanta označen jako defaultní a bude použit pro nové tenanty bez specifikovaného profilu.",
  2037 + "no-tenant-profiles-found": "Nebyly nalezeny žádné profily tenantů.",
  2038 + "create-new-tenant-profile": "Vytvořit nový!",
  2039 + "maximum-devices": "Maximální počet zařízení (0 - neomezeno)",
  2040 + "maximum-devices-required": "Maximální počet zařízení je povinný.",
  2041 + "maximum-devices-range": "Minimální počet zařízení nemůže být záporný",
  2042 + "maximum-assets": "Maximální počet aktiv (0 - neomezeno)",
  2043 + "maximum-assets-required": "Maximální počet aktiv je povinný.",
  2044 + "maximum-assets-range": "Maximální počet aktiv nemůže být záporný",
  2045 + "maximum-customers": "Maximální počet zákazníků (0 - neomezeno)",
  2046 + "maximum-customers-required": "Maximální počet zákazníkůje povinný.",
  2047 + "maximum-customers-range": "Maximální počet zákazníků nemůže být záporný",
  2048 + "maximum-users": "Maximální počet uživatelů (0 - neomezeno)",
  2049 + "maximum-users-required": "Maximální počet uživatelů je povinný.",
  2050 + "maximum-users-range": "Maximální počet uživatelů nemůže být záporný",
  2051 + "maximum-dashboards": "Maximální počet dashboardů (0 - neomezeno)",
  2052 + "maximum-dashboards-required": "Maximální počet dashboardů je povinný.",
  2053 + "maximum-dashboards-range": "Maximální počet dashboardů nemůže být záporný",
  2054 + "maximum-rule-chains": "Maximální počet řetězů pravidel (0 - neomezeno)",
  2055 + "maximum-rule-chains-required": "Maximální počet řetězů pravidel je povinný.",
  2056 + "maximum-rule-chains-range": "Maximální počet řetězů pravidel nemůže být záporný",
  2057 + "transport-tenant-msg-rate-limit": "Limit přenosu zpráv tenanta.",
  2058 + "transport-tenant-telemetry-msg-rate-limit": "Limit přenosu zpráv telemetrie tenanta.",
  2059 + "transport-tenant-telemetry-data-points-rate-limit": "Limit přenosu datových bodů telemetrie tenanta.",
  2060 + "transport-device-msg-rate-limit": "Limit přenosu zpráv zařízení.",
  2061 + "transport-device-telemetry-msg-rate-limit": "Limit přenosu zpráv zařízení telemetrie tenanta.",
  2062 + "transport-device-telemetry-data-points-rate-limit": "Limit přenosu datových bodů zařízení telemetrie tenanta.",
  2063 + "max-transport-messages": "Maximální počet zpráv přenosu (0 - neomezeno)",
  2064 + "max-transport-messages-required": "Maximální počet zpráv přenosu je povinný.",
  2065 + "max-transport-messages-range": "Maximální počet zpráv přenosu nemůže být záporný",
  2066 + "max-transport-data-points": "Maximální počet datových bodů přenosu (0 - neomezeno)",
  2067 + "max-transport-data-points-required": "Maximální počet datových bodů přenosu je povinný.",
  2068 + "max-transport-data-points-range": "Maximální počet datových bodů přenosu nemůže být záporný",
  2069 + "max-r-e-executions": "Maximální počet zpracování enginu pro zpracování pravidel (0 - neomezeno)",
  2070 + "max-r-e-executions-required": "Maximální počet zpracování enginu pro zpracování pravidel je povinný.",
  2071 + "max-r-e-executions-range": "Maximální počet zpracování enginu pro zpracování pravidel nemůže být záporný",
  2072 + "max-j-s-executions": "Maximální počet JavaScript zpracování (0 - neomezeno)",
  2073 + "max-j-s-executions-required": "Maximální počet JavaScript zpracování je povinný.",
  2074 + "max-j-s-executions-range": "Maximální počet JavaScript zpracování nemůže být záporný",
  2075 + "max-d-p-storage-days": "Maximální počet dnů uložení datových bodů (0 - neomezeno)",
  2076 + "max-d-p-storage-days-required": "Maximální počet dnů uložení datových bodů je povinný.",
  2077 + "max-d-p-storage-days-range": "Maximální počet dnů uložení datových bodů nemůže být záporný",
  2078 + "default-storage-ttl-days": "Defaultní počet dnů TTL úložiště (0 - neomezeno)",
  2079 + "default-storage-ttl-days-required": "Defaultní počet dnů TTL úložiště je povinný.",
  2080 + "default-storage-ttl-days-range": "Defaultní počet dnů TTL úložiště nemůže být záporný",
  2081 + "max-rule-node-executions-per-message": "Maximální počet zpracování uzlů pravidel na zprávu (0 - neomezeno)",
  2082 + "max-rule-node-executions-per-message-required": "Maximální počet zpracování uzlů pravidel na zprávu je povinný.",
  2083 + "max-rule-node-executions-per-message-range": "Maximální počet zpracování uzlů pravidel na zprávu nemůže být záporný",
  2084 + "max-emails": "Maximální počet odeslaných emailů (0 - neomezeno)",
  2085 + "max-emails-required": "Maximální počet odeslaných emailů je povinný.",
  2086 + "max-emails-range": "Maximální počet odeslaných emailů nemůže být záporný",
  2087 + "max-sms": "Maximální počet odeslaných SMS (0 - neomezeno)",
  2088 + "max-sms-required": "Maximální počet odeslaných SMS je povinný.",
  2089 + "max-sms-range": "Maximální počet odeslaných SMS nemůže být záporný"
  2090 + },
1566 2091 "timeinterval": {
1567 2092 "seconds-interval": "{ seconds, plural, 1 {1 vteřina} other {# vteřin} }",
1568 2093 "minutes-interval": "{ minutes, plural, 1 {1 minuta} other {# minut} }",
... ... @@ -1574,8 +2099,14 @@
1574 2099 "seconds": "Vteřiny",
1575 2100 "advanced": "Rozšířené"
1576 2101 },
  2102 + "timeunit": {
  2103 + "seconds": "Vteřiny",
  2104 + "minutes": "Minuty",
  2105 + "hours": "Hodiny",
  2106 + "days": "Dny"
  2107 + },
1577 2108 "timewindow": {
1578   - "days": "{ days, plural, 1 { den } other {# days } }",
  2109 + "days": "{ days, plural, 1 { den } other {# d } }",
1579 2110 "hours": "{ hours, plural, 0 { hodina } 1 {1 hodina } other {# hodin } }",
1580 2111 "minutes": "{ minutes, plural, 0 { minuta } 1 {1 minuta } other {# minut } }",
1581 2112 "seconds": "{ seconds, plural, 0 { vteřina } 1 {1 vteřina } other {# vteřin } }",
... ... @@ -1694,6 +2225,7 @@
1694 2225 "type": "Typ widgetu",
1695 2226 "resources": "Zdroje",
1696 2227 "resource-url": "JavaScript/CSS URL",
  2228 + "resource-is-module": "Je modulem",
1697 2229 "remove-resource": "Odebrat zdroj",
1698 2230 "add-resource": "Přidat zdroj",
1699 2231 "html": "HTML",
... ... @@ -1711,7 +2243,10 @@
1711 2243 "widget-template-load-failed-error": "Nahrání šablony widgetu selhalo!",
1712 2244 "add": "Přidat widget",
1713 2245 "undo": "Vrátit změny widgetu",
1714   - "export": "Exportovat widget"
  2246 + "export": "Exportovat widget",
  2247 + "no-data": "Nejsou k dispozici žádná data pro zobrazení ve widgetu",
  2248 + "data-overflow": "Widget zobrazuje {{count}} z {{total}} entit",
  2249 + "alarm-data-overflow": "Widget zobrazuje alarmy {{allowedEntities}} (maxima možných) entit z {{totalEntities}} entit"
1715 2250 },
1716 2251 "widget-action": {
1717 2252 "header-button": "Tlačítko hlavičky widgetu",
... ... @@ -1724,7 +2259,14 @@
1724 2259 "target-dashboard-state-required": "Cílový stav dashboardu je povinný",
1725 2260 "set-entity-from-widget": "Nastavit entitu z widgetu",
1726 2261 "target-dashboard": "Cílový dashboard",
1727   - "open-right-layout": "Otevřít rozmístění dashboardu vpravo (mobilní zobrazení)"
  2262 + "open-right-layout": "Otevřít rozmístění dashboardu vpravo (mobilní zobrazení)",
  2263 + "open-in-separate-dialog": "Otevřít v samostatném okně",
  2264 + "dialog-title": "Název okna",
  2265 + "dialog-hide-dashboard-toolbar": "Skrýt v okně nástrojovou lištu dashboardu",
  2266 + "dialog-width": "Šířka okna v procentech vzhledem k šířce obrazovky",
  2267 + "dialog-height": "Výška okna v procentech vzhledem k výšce obrazovky",
  2268 + "dialog-size-range-error": "Hodnota procentuální velikosti musí být v rozsahu od 1 do 100.",
  2269 + "open-new-browser-tab": "Otevřít na nové záložce prohlížeče"
1728 2270 },
1729 2271 "widgets-bundle": {
1730 2272 "current": "Vybraná kategorie",
... ... @@ -1891,8 +2433,11 @@
1891 2433 "entity-coordinate-required": "Obě pole, zeměpisná šířka i zeměpisná délka, jsou povinná",
1892 2434 "entity-timeseries-required": "Časové řady entity jsou povinné",
1893 2435 "get-location": "Získat aktuální polohu",
  2436 + "invalid-date": "Neplatné datum",
1894 2437 "latitude": "Zeměpisná šířka",
1895 2438 "longitude": "Zeměpisná délka",
  2439 + "min-value-error": "Minimální hodnota je {{value}}",
  2440 + "max-value-error": "Maximální hodnota je {{value}}",
1896 2441 "not-allowed-entity": "Vybraná entita nemůže mít sdílené atributy",
1897 2442 "no-attribute-selected": "Není vybrán žádný atribut",
1898 2443 "no-datakey-selected": "Není vybrán žádný datový klíč",
... ... @@ -1900,7 +2445,10 @@
1900 2445 "no-entity-selected": "Není vybrána žádná entita",
1901 2446 "no-image": "Žádný obrázek",
1902 2447 "no-support-geolocation": "Váš prohlížeč nepodporuje geolokaci",
1903   - "no-support-web-camera": "Žádná podporovaná webová kamera",
  2448 + "no-support-web-camera": "Váš prohlížeč nepodporuje kamery",
  2449 + "enable-https-use-widget": "Prosím povolte HTTPS abyste mohli používat tento widget",
  2450 + "no-found-your-camera": "Nelze nalézt vyši kameru",
  2451 + "no-permission-camera": "Přístup byl zakázán uživatelem / Tato stránka nemá oprávnění použít kameru",
1904 2452 "no-timeseries-selected": "Nejsou vybrány žádné časové řady",
1905 2453 "secret-key": "Tajný klíč",
1906 2454 "secret-key-required": "Tajný klíč je povinný",
... ...