diff --git a/application/pom.xml b/application/pom.xml index 978b86257a..47772dfa97 100644 --- a/application/pom.xml +++ b/application/pom.xml @@ -382,35 +382,35 @@ rocksdbjni - dev.langchain4j + org.thingsboard.langchain4j langchain4j-open-ai - dev.langchain4j + org.thingsboard.langchain4j langchain4j-azure-open-ai - dev.langchain4j + org.thingsboard.langchain4j langchain4j-google-ai-gemini - dev.langchain4j + org.thingsboard.langchain4j langchain4j-vertex-ai-gemini - dev.langchain4j + org.thingsboard.langchain4j langchain4j-mistral-ai - dev.langchain4j + org.thingsboard.langchain4j langchain4j-anthropic - dev.langchain4j + org.thingsboard.langchain4j langchain4j-bedrock - dev.langchain4j + org.thingsboard.langchain4j langchain4j-github-models @@ -420,7 +420,7 @@ - dev.langchain4j + org.thingsboard.langchain4j langchain4j-ollama diff --git a/application/src/main/data/json/edge/instructions/install/centos/instructions.md b/application/src/main/data/json/edge/instructions/install/centos/instructions.md index de5e57d926..1822add6d8 100644 --- a/application/src/main/data/json/edge/instructions/install/centos/instructions.md +++ b/application/src/main/data/json/edge/instructions/install/centos/instructions.md @@ -1,7 +1,7 @@ -Here is the list of commands, that can be used to quickly install ThingsBoard Edge on RHEL/CentOS 7/8 and connect to the server. +Here is the list of commands that can be used to quickly install ThingsBoard Edge on RHEL/CentOS 7/8 and connect to the server. #### Prerequisites -Before continue to installation execute the following commands in order to install necessary tools: +Before continuing to installation, execute the following commands to install the necessary tools: ```bash sudo yum install -y nano wget && sudo yum install -y https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm @@ -9,29 +9,28 @@ sudo yum install -y nano wget && sudo yum install -y https://dl.fedoraproject.or ``` #### Step 1. Install Java 17 (OpenJDK) -ThingsBoard service is running on Java 17. Follow these instructions to install OpenJDK 17: +ThingsBoard service is running on Java 17. To install OpenJDK 17, follow these instructions: ```bash sudo dnf install java-17-openjdk {:copy-code} ``` -Please don't forget to configure your operating system to use OpenJDK 17 by default. -You can configure which version is the default using the following command: +Configure your operating system to use OpenJDK 17 by default. You can configure the default version by running the following command: ```bash sudo update-alternatives --config java {:copy-code} ``` -You can check the installation using the following command: +To check the installed Java version on your system, use the following command: ```bash java -version {:copy-code} ``` -Expected command output is: +The expected result is: ```text openjdk version "17.x.xx" @@ -39,14 +38,13 @@ OpenJDK Runtime Environment (...) OpenJDK 64-Bit Server VM (build ...) ``` -#### Step 2. Configure ThingsBoard Database -ThingsBoard Edge supports SQL and hybrid database approaches. -In this guide we will use SQL only. -For hybrid details please follow official installation instructions from the ThingsBoard documentation site. +#### Step 2. Configure ThingsBoard Edge Database -### PostgresSql -ThingsBoard Edge uses PostgreSQL database as a local storage. -To install PostgreSQL, follow the instructions below. +ThingsBoard Edge supports **SQL** and **hybrid** database configurations. +In this guide, we’ll use an **SQL** database. +For more details about the hybrid setup, please refer to the official installation instructions on the ThingsBoard documentation site. + +To install the PostgreSQL database, run these commands: ```bash # Update your system @@ -55,7 +53,8 @@ sudo dnf update ``` Install the repository RPM: -**For CentOS/RHEL 8:** + +* **For CentOS/RHEL 8:** ```bash # Install the repository RPM (For CentOS/RHEL 8): @@ -63,7 +62,7 @@ sudo sudo dnf -y install https://download.postgresql.org/pub/repos/yum/reporpms/ {:copy-code} ``` -**For CentOS/RHEL 9:** +* **For CentOS/RHEL 9:** ```bash # Install the repository RPM (for CentOS 9): @@ -111,22 +110,11 @@ sudo systemctl restart postgresql-16.service && psql -U postgres -d postgres -h {:copy-code} ``` -#### Step 3. Choose Queue Service - -ThingsBoard Edge supports only Kafka or in-memory queue (since v4.0) for message storage and communication between ThingsBoard services. -How to choose the right queue implementation? - -In Memory queue implementation is built-in and default. It is useful for development(PoC) environments and is not suitable for production deployments or any sort of cluster deployments. - -Kafka is recommended for production deployments. This queue is used on the most of ThingsBoard production environments now. - -In Memory queue is built in and enabled by default. No additional configuration is required. - -#### Step 4. ThingsBoard Edge Service Installation +#### Step 3. ThingsBoard Edge Service Installation Download installation package: ```bash -wget wget https://github.com/thingsboard/thingsboard-edge/releases/download/v${TB_EDGE_TAG}/tb-edge-${TB_EDGE_TAG}.rpm +wget https://github.com/thingsboard/thingsboard-edge/releases/download/v${TB_EDGE_TAG}/tb-edge-${TB_EDGE_TAG}.rpm {:copy-code} ``` @@ -137,8 +125,8 @@ sudo rpm -Uvh tb-edge-${TB_EDGE_TAG}.rpm {:copy-code} ``` -#### Step 5. Configure ThingsBoard Edge -To configure ThingsBoard Edge, you can use the following command to automatically update the configuration file with specific values: +#### Step 4. Configure ThingsBoard Edge +To configure ThingsBoard Edge, you can use the following command to automatically update the configuration file with specific values: ```bash sudo sh -c 'cat <> /etc/tb-edge/conf/tb-edge.conf @@ -151,7 +139,7 @@ EOL' {:copy-code} ``` -##### Configure PostgreSQL (Optional) +##### [Optional] Configure PostgreSQL Connection If you changed PostgreSQL default datasource settings, use the following command: ```bash @@ -163,11 +151,10 @@ EOL' {:copy-code} ``` -PUT_YOUR_POSTGRESQL_PASSWORD_HERE: Replace with your actual PostgreSQL user password. - +* **PUT_YOUR_POSTGRESQL_PASSWORD_HERE**: Replace with your actual **PostgreSQL user password**. -##### [Optional] Update bind ports -If ThingsBoard Edge is going to be running on the same machine where ThingsBoard server (cloud) is running, you'll need to update configuration parameters to avoid port collision between ThingsBoard server and ThingsBoard Edge. +##### [Optional] Update Bind Ports +If ThingsBoard Edge runs on the same machine as the ThingsBoard Server, you need to update the port configuration to avoid conflicts between the two services. Please execute the following command to update ThingsBoard Edge configuration file (**/etc/tb-edge/conf/tb-edge.conf**): @@ -182,28 +169,26 @@ EOL' {:copy-code} ``` -Make sure that ports above (18080, 11883, 15683) are not used by any other application. +Make sure that ports **18080**, **11883**, and **15683–15688** are not being used by any other applications. + +#### Step 5. Run Installation Script -#### Step 6. Run installation Script -Once ThingsBoard Edge is installed and configured please execute the following install script: +Once ThingsBoard Edge is installed and configured, please execute the following install script: ```bash sudo /usr/share/tb-edge/bin/install/install.sh {:copy-code} ``` -#### Step 7. Restart ThingsBoard Edge Service +#### Step 6. Start ThingsBoard Edge Service ```bash -sudo service tb-edge restart +sudo service tb-edge start {:copy-code} ``` -#### Step 8. Open ThingsBoard Edge UI - -Once started, you will be able to open **ThingsBoard Edge UI** using the following link http://localhost:8080. - -###### NOTE: Edge HTTP bind port update +#### Step 7. Open ThingsBoard Edge UI -If the Edge HTTP bind port was changed to 18080 during Edge installation, access the ThingsBoard Edge instance at http://localhost:18080. +Once the Edge service has started, open the Edge web interface at http://localhost:8080, or http://localhost:18080 if you modified the HTTP bind port configuration in the previous step. +Log in using your **tenant credentials** from either your local ThingsBoard Server or the **ThingsBoard Live Demo**. \ No newline at end of file diff --git a/application/src/main/data/json/edge/instructions/install/docker/instructions.md b/application/src/main/data/json/edge/instructions/install/docker/instructions.md index e568d273af..8325c006d3 100644 --- a/application/src/main/data/json/edge/instructions/install/docker/instructions.md +++ b/application/src/main/data/json/edge/instructions/install/docker/instructions.md @@ -1,34 +1,17 @@ -Here is the list of commands, that can be used to quickly install ThingsBoard Edge using docker compose and connect to the server. +Here is the list of commands that can be used to quickly install ThingsBoard Edge using docker compose and connect to the server. #### Prerequisites Install Docker CE and Docker Compose. -#### Step 1. Running ThingsBoard Edge +#### Step 1. Create the ThingsBoard Edge Docker Compose file -Here you can find ThingsBoard Edge docker image: +ThingsBoard Edge supports both **in-memory** and **Kafka** queues for message storage and communication between ThingsBoard services. +It also supports **SQL** and **hybrid** database configurations. +In this guide, we’ll use the **in-memory** queue and an **SQL** database. +For more details about the hybrid setup, please refer to the official installation instructions on the ThingsBoard documentation site. - thingsboard/tb-edge - -#### Step 2. Choose Queue and/or Database Services - -ThingsBoard Edge supports only Kafka or in-memory queue (since v4.0) for message storage and communication between ThingsBoard services. - -ThingsBoard Edge supports SQL and hybrid database approaches. -In this guide we will use SQL only. -For hybrid details please follow official installation instructions from the ThingsBoard documentation site. - -How to choose the right queue implementation? - -In Memory queue implementation is built-in and default. It is useful for development(PoC) environments and is not suitable for production deployments or any sort of cluster deployments. - -Kafka is recommended for production deployments. This queue is used on the most of ThingsBoard production environments now. - -Hybrid implementation combines PostgreSQL and Cassandra databases with Kafka queue service. It is recommended if you plan to manage 1M+ devices in production or handle high data ingestion rate (more than 5000 msg/sec). - -Create a docker compose file for the ThingsBoard Edge service: - -##### In Memory +Now, create a Docker Compose file for the ThingsBoard Edge service: ```bash nano docker-compose.yml @@ -38,7 +21,6 @@ nano docker-compose.yml Add the following lines to the yml file: ```bash -version: '3.8' services: mytbedge: restart: always @@ -54,6 +36,7 @@ services: CLOUD_RPC_HOST: ${BASE_URL} CLOUD_RPC_PORT: ${CLOUD_RPC_PORT} CLOUD_RPC_SSL_ENABLED: ${CLOUD_RPC_SSL_ENABLED} + ${EXTRA_HOSTS} volumes: - tb-edge-data:/data - tb-edge-logs:/var/log/tb-edge @@ -78,41 +61,28 @@ volumes: {:copy-code} ``` -##### [Optional] Update bind ports -If ThingsBoard Edge is set to run on the same machine where the ThingsBoard server is operating, you need to update port configuration to prevent port collision between the ThingsBoard server and ThingsBoard Edge. +##### [Optional] Update Bind Ports +If ThingsBoard Edge runs on the same machine as the ThingsBoard Server, you need to update the port configuration to avoid conflicts between the two services. -Ensure that the ports 18080, 11883, 15683-15688 are not used by any other application. +Make sure that ports **18080**, **11883**, and **15683–15688** are not being used by any other applications. -Then, update the port configuration in the docker-compose.yml file: -```bash -sed -i ‘s/8080:8080/18080:8080/; s/1883:1883/11883:1883/; s/5683-5688:5683-5688\/udp/15683-15688:5683-5688\/udp/’ docker-compose.yml -{:copy-code} -``` -#### Start ThingsBoard Edge -Set the terminal in the directory which contains the docker-compose.yml file and execute the following commands to up this docker compose directly: +Then, update the port configuration in the `docker-compose.yml` file accordingly: ```bash -docker compose up -d && docker compose logs -f mytbedge +sed -i 's/8080:8080/18080:8080/; s/1883:1883/11883:1883/; s/5683-5688:5683-5688\/udp/15683-15688:5683-5688\/udp/' docker-compose.yml {:copy-code} ``` -###### NOTE: Docker Compose V2 vs docker-compose (with a hyphen) - -ThingsBoard supports Docker Compose V2 (Docker Desktop or Compose plugin) starting from **3.4.2** release, because **docker-compose** as standalone setup is no longer supported by Docker. -We **strongly** recommend to update to Docker Compose V2 and use it. -If you still rely on using Docker Compose as docker-compose (with a hyphen), then please execute the following commands to start ThingsBoard Edge: +#### Step 2. Start ThingsBoard Edge +Navigate to the directory containing the `docker-compose.yml` file and run the following command to start the ThingsBoard Edge service: ```bash -docker-compose up -d -docker-compose logs -f mytbedge +docker compose up -d && docker compose logs -f mytbedge +{:copy-code} ``` #### Step 3. Open ThingsBoard Edge UI -Once the Edge service is started, open the Edge UI at http://localhost:8080. - -###### NOTE: Edge HTTP bind port update - -If the Edge HTTP bind port was changed to 18080 during Edge installation, access the ThingsBoard Edge instance at http://localhost:18080. +Once the Edge service has started, open the Edge web interface at http://localhost:8080, or http://localhost:18080 if you modified the HTTP bind port configuration in the previous step. -Please use your tenant credentials from local Server instance or ThingsBoard Live Demo to log in to the ThingsBoard Edge. +Log in using your **tenant credentials** from either your local ThingsBoard Server or the **ThingsBoard Live Demo**. diff --git a/application/src/main/data/json/edge/instructions/install/ubuntu/instructions.md b/application/src/main/data/json/edge/instructions/install/ubuntu/instructions.md index a56b83e558..b4782dd46a 100644 --- a/application/src/main/data/json/edge/instructions/install/ubuntu/instructions.md +++ b/application/src/main/data/json/edge/instructions/install/ubuntu/instructions.md @@ -1,4 +1,4 @@ -Here is the list of commands, that can be used to quickly install ThingsBoard Edge on Ubuntu Server and connect to the server. +Here is the list of commands that can be used to quickly install ThingsBoard Edge on Ubuntu Server and connect to the server. #### Step 1. Install Java 17 (OpenJDK) ThingsBoard service is running on Java 17. To install OpenJDK 17, follow these instructions: @@ -25,19 +25,16 @@ java -version The expected result is: ```text -openjdk version "17.x.xx" +openjdk version "17.x.xx" OpenJDK Runtime Environment (...) -OpenJDK 64-Bit Server VM (...) +OpenJDK 64-Bit Server VM (build ...) ``` #### Step 2. Configure ThingsBoard Edge Database -ThingsBoard Edge supports SQL and hybrid database approaches. -In this guide we will use SQL only. -For hybrid details please follow official installation instructions from the ThingsBoard documentation site. - -### Configure PostgreSQL -ThingsBoard Edge uses PostgreSQL database as a local storage. +ThingsBoard Edge supports **SQL** and **hybrid** database configurations. +In this guide, we’ll use an **SQL** database. +For more details about the hybrid setup, please refer to the official installation instructions on the ThingsBoard documentation site. To install the PostgreSQL database, run these commands: @@ -71,18 +68,8 @@ echo "CREATE DATABASE tb_edge;" | psql -U postgres -d postgres -h 127.0.0.1 -W {:copy-code} ``` -#### Step 3. Choose Queue Service - -ThingsBoard Edge supports only Kafka or in-memory queue (since v4.0) for message storage and communication between ThingsBoard services. Choose the appropriate queue implementation based on your specific business needs: - -In Memory: The built-in and default queue implementation. It is useful for development or proof-of-concept (PoC) environments, but is not recommended for production or any type of clustered deployments due to limited scalability. - -Kafka: Recommended for production deployments. This queue is used in the most of ThingsBoard production environments now. - -In Memory queue is built in and enabled by default. No additional configuration is required. - -#### Step 4. ThingsBoard Edge Service Installation -Download installation package: +#### Step 3. ThingsBoard Edge Service Installation +Download the installation package: ```bash wget https://github.com/thingsboard/thingsboard-edge/releases/download/v${TB_EDGE_TAG}/tb-edge-${TB_EDGE_TAG}.deb @@ -96,8 +83,8 @@ sudo dpkg -i tb-edge-${TB_EDGE_TAG}.deb {:copy-code} ``` -#### Step 5. Configure ThingsBoard Edge -To configure ThingsBoard Edge, you can use the following command to automatically update the configuration file with specific values: +#### Step 4. Configure ThingsBoard Edge +To configure ThingsBoard Edge, you can use the following command to automatically update the configuration file with specific values: ```bash sudo sh -c 'cat <> /etc/tb-edge/conf/tb-edge.conf @@ -110,7 +97,7 @@ EOL' {:copy-code} ``` -##### [Optional] Configure PostgreSQL +##### [Optional] Configure PostgreSQL Connection If you changed PostgreSQL default datasource settings, use the following command: ```bash @@ -122,10 +109,10 @@ EOL' {:copy-code} ``` -PUT_YOUR_POSTGRESQL_PASSWORD_HERE: Replace with your actual PostgreSQL user password. +* **PUT_YOUR_POSTGRESQL_PASSWORD_HERE**: Replace with your actual **PostgreSQL user password**. -##### [Optional] Update bind ports -If ThingsBoard Edge is going to be running on the same machine where ThingsBoard server (cloud) is running, you'll need to update configuration parameters to avoid port collision between ThingsBoard server and ThingsBoard Edge. +##### [Optional] Update Bind Ports +If ThingsBoard Edge runs on the same machine as the ThingsBoard Server, you need to update the port configuration to avoid conflicts between the two services. Please execute the following command to update ThingsBoard Edge configuration file (**/etc/tb-edge/conf/tb-edge.conf**): @@ -140,29 +127,26 @@ EOL' {:copy-code} ``` -Make sure that ports above (18080, 11883, 15683) are not used by any other application. +Make sure that ports **18080**, **11883**, and **15683–15688** are not being used by any other applications. -#### Step 6. Run installation Script +#### Step 5. Run Installation Script -Once ThingsBoard Edge is installed and configured please execute the following install script: +Once ThingsBoard Edge is installed and configured, please execute the following installation script: ```bash sudo /usr/share/tb-edge/bin/install/install.sh {:copy-code} ``` -#### Step 7. Restart ThingsBoard Edge Service +#### Step 6. Start ThingsBoard Edge Service ```bash -sudo service tb-edge restart +sudo service tb-edge start {:copy-code} ``` -#### Step 8. Open ThingsBoard Edge UI - -Once started, you will be able to open **ThingsBoard Edge UI** using the following link http://localhost:8080. - -###### NOTE: Edge HTTP bind port update +#### Step 7. Open ThingsBoard Edge UI -Use next **ThingsBoard Edge UI** link **http://localhost:18080** if you updated HTTP 8080 bind port to **18080**. +Once the Edge service has started, open the Edge web interface at http://localhost:8080, or http://localhost:18080 if you modified the HTTP bind port configuration in the previous step. +Log in using your **tenant credentials** from either your local ThingsBoard Server or the **ThingsBoard Live Demo**. \ No newline at end of file diff --git a/application/src/main/data/json/edge/instructions/upgrade/centos/instructions.md b/application/src/main/data/json/edge/instructions/upgrade/centos/instructions.md index c0e721ace2..82774e89cb 100644 --- a/application/src/main/data/json/edge/instructions/upgrade/centos/instructions.md +++ b/application/src/main/data/json/edge/instructions/upgrade/centos/instructions.md @@ -1,15 +1,15 @@ #### Upgrading to ${TB_EDGE_VERSION}EDGE -**ThingsBoard Edge package download:** +ThingsBoard Edge package download: ```bash wget https://github.com/thingsboard/thingsboard-edge/releases/download/v${TB_EDGE_TAG}/tb-edge-${TB_EDGE_TAG}.rpm {:copy-code} ``` -##### ThingsBoard Edge service upgrade Install package: ```bash sudo rpm -Uvh tb-edge-${TB_EDGE_TAG}.rpm {:copy-code} ``` + ${UPGRADE_DB} diff --git a/application/src/main/data/json/edge/instructions/upgrade/docker/instructions.md b/application/src/main/data/json/edge/instructions/upgrade/docker/instructions.md index f1b9931e8b..68c7597f84 100644 --- a/application/src/main/data/json/edge/instructions/upgrade/docker/instructions.md +++ b/application/src/main/data/json/edge/instructions/upgrade/docker/instructions.md @@ -1,10 +1,3 @@ #### Upgrading to ${TB_EDGE_VERSION} -Execute the following command to pull **${TB_EDGE_VERSION}** image: - -```bash -docker pull thingsboard/tb-edge:${TB_EDGE_VERSION} -{:copy-code} -``` - ${UPGRADE_DB} diff --git a/application/src/main/data/json/edge/instructions/upgrade/docker/start_service.md b/application/src/main/data/json/edge/instructions/upgrade/docker/start_service.md index a6c9c6731c..11dc99a637 100644 --- a/application/src/main/data/json/edge/instructions/upgrade/docker/start_service.md +++ b/application/src/main/data/json/edge/instructions/upgrade/docker/start_service.md @@ -1,11 +1,10 @@ -Modify ‘main’ docker compose (`docker-compose.yml`) file for ThingsBoard Edge and update version of the image: +Modify ‘main’ docker compose (`docker-compose.yml`) a file for ThingsBoard Edge and update a version of the image: ```bash nano docker-compose.yml {:copy-code} ``` ```text -version: '3.8' services: mytbedge: restart: always @@ -13,7 +12,7 @@ services: ... ``` -Make sure your image is the set to **tb-edge-${TB_EDGE_VERSION}**. +Make sure your image is set to **tb-edge:${TB_EDGE_VERSION}**. Execute the following commands to up this docker compose directly: ```bash diff --git a/application/src/main/data/json/edge/instructions/upgrade/docker/upgrade_db.md b/application/src/main/data/json/edge/instructions/upgrade/docker/upgrade_db.md index 386c5f2743..523316cdae 100644 --- a/application/src/main/data/json/edge/instructions/upgrade/docker/upgrade_db.md +++ b/application/src/main/data/json/edge/instructions/upgrade/docker/upgrade_db.md @@ -1,4 +1,4 @@ -Create docker compose file for ThingsBoard Edge upgrade process: +Create a docker compose file for ThingsBoard Edge upgrade process: ```bash > docker-compose-upgrade.yml && nano docker-compose-upgrade.yml @@ -8,7 +8,6 @@ Create docker compose file for ThingsBoard Edge upgrade process: Add the following lines to the yml file: ```bash -version: '3.8' services: mytbedge: restart: on-failure @@ -40,7 +39,7 @@ volumes: {:copy-code} ``` -Execute the following command to start upgrade process: +Execute the following command to start an upgrade process: ```bash docker compose -f docker-compose-upgrade.yml up --abort-on-container-exit diff --git a/application/src/main/data/json/edge/instructions/upgrade/docker/upgrade_preparing.md b/application/src/main/data/json/edge/instructions/upgrade/docker/upgrade_preparing.md index f12eaa5fc0..d2a6f796a1 100644 --- a/application/src/main/data/json/edge/instructions/upgrade/docker/upgrade_preparing.md +++ b/application/src/main/data/json/edge/instructions/upgrade/docker/upgrade_preparing.md @@ -1,6 +1,6 @@ -Here is the list of commands, that can be used to quickly upgrade ThingsBoard Edge on Docker (Linux or MacOS). +Here is the list of commands that can be used to quickly upgrade ThingsBoard Edge on Docker (Linux or macOS). -#### Prepare for upgrading ThingsBoard Edge +#### Prepare for Upgrading ThingsBoard Edge Set the terminal in the directory which contains the `docker-compose.yml` file and execute the following command to stop and remove currently running TB Edge container: @@ -10,70 +10,6 @@ docker compose rm mytbedge {:copy-code} ``` -**OPTIONAL:** If you still rely on Docker Compose as docker-compose (with a hyphen) here is the list of the above commands: -```text -docker-compose stop -docker-compose rm mytbedge -``` - -##### Migrating Data from Docker Bind Mount Folders to Docker Volumes -Starting with the **3.6.2** release, the ThingsBoard team has transitioned from using Docker bind mount folders to Docker volumes. -This change aims to enhance security and efficiency in storing data for Docker containers and to mitigate permission issues across various environments. - -To migrate from Docker bind mounts to Docker volumes, please execute the following commands: - -```bash -docker run --rm -v tb-edge-data:/volume -v ~/.mytb-edge-data:/backup busybox sh -c "cp -a /backup/. /volume" -docker run --rm -v tb-edge-logs:/volume -v ~/.mytb-edge-logs:/backup busybox sh -c "cp -a /backup/. /volume" -docker run --rm -v tb-edge-postgres-data:/volume -v ~/.mytb-edge-data/db:/backup busybox sh -c "cp -a /backup/. /volume" -{:copy-code} -``` - -After completing the data migration to the newly created Docker volumes, you'll need to update the volume mounts in your Docker Compose configuration. -Modify the `docker-compose.yml` file for ThingsBoard Edge to update the volume settings. - -Update volume mounts. Locate the following snippet: -```text - volumes: - - ~/.mytb-edge-data:/data - - ~/.mytb-edge-logs:/var/log/tb-edge -... -``` - -And replace it with: -```text - volumes: - - tb-edge-data:/data - - tb-edge-logs:/var/log/tb-edge -... -``` - -Apply a similar update for the PostgreSQL service. Find the section: -```text - volumes: - - ~/.mytb-edge-data/db:/var/lib/postgresql/data -... -``` - -And replace it with: -```text - volumes: - - tb-edge-postgres-data:/var/lib/postgresql/data -... -``` - -Finally, please add next volumes section at the end of the file: -```text -... -volumes: - tb-edge-data: - name: tb-edge-data - tb-edge-logs: - name: tb-edge-logs - tb-edge-postgres-data: - name: tb-edge-postgres-data -``` - ##### Backup Database Make a copy of the database volume before upgrading: diff --git a/application/src/main/data/json/edge/instructions/upgrade/start_service.md b/application/src/main/data/json/edge/instructions/upgrade/start_service.md index c26c183154..109ccf5b4b 100644 --- a/application/src/main/data/json/edge/instructions/upgrade/start_service.md +++ b/application/src/main/data/json/edge/instructions/upgrade/start_service.md @@ -1,4 +1,4 @@ -Start the service +#### Start the Service ```bash sudo systemctl tb-edge start diff --git a/application/src/main/data/json/edge/instructions/upgrade/ubuntu/instructions.md b/application/src/main/data/json/edge/instructions/upgrade/ubuntu/instructions.md index 59d243c63c..8d4a8d6e26 100644 --- a/application/src/main/data/json/edge/instructions/upgrade/ubuntu/instructions.md +++ b/application/src/main/data/json/edge/instructions/upgrade/ubuntu/instructions.md @@ -1,15 +1,14 @@ #### Upgrading to ${TB_EDGE_VERSION}EDGE -**ThingsBoard Edge package download:** +ThingsBoard Edge package download: ```bash wget https://github.com/thingsboard/thingsboard-edge/releases/download/v${TB_EDGE_TAG}/tb-edge-${TB_EDGE_TAG}.deb {:copy-code} ``` -##### ThingsBoard Edge service upgrade - Install package: ```bash sudo dpkg -i tb-edge-${TB_EDGE_TAG}.deb {:copy-code} ``` + ${UPGRADE_DB} diff --git a/application/src/main/data/json/edge/instructions/upgrade/upgrade_preparing.md b/application/src/main/data/json/edge/instructions/upgrade/upgrade_preparing.md index bdd6c4ea18..3d3ac8c705 100644 --- a/application/src/main/data/json/edge/instructions/upgrade/upgrade_preparing.md +++ b/application/src/main/data/json/edge/instructions/upgrade/upgrade_preparing.md @@ -1,6 +1,6 @@ -Here is the list of commands, that can be used to quickly upgrade ThingsBoard Edge on ${OS} +Here is the list of commands that can be used to quickly upgrade ThingsBoard Edge on ${OS} -#### Prepare for upgrading ThingsBoard Edge +#### Prepare for Upgrading ThingsBoard Edge Stop ThingsBoard Edge service: @@ -33,4 +33,4 @@ sudo -Hiu postgres pg_dump tb_edge > tb_edge.sql.bak {:copy-code} ``` -Check backup file created successfully. +Check the backup file created successfully. diff --git a/application/src/main/data/json/system/widget_types/attributes_card.json b/application/src/main/data/json/system/widget_types/attributes_card.json index 6246811769..2beedd2a76 100644 --- a/application/src/main/data/json/system/widget_types/attributes_card.json +++ b/application/src/main/data/json/system/widget_types/attributes_card.json @@ -11,7 +11,7 @@ "resources": [], "templateHtml": "", "templateCss": "#container {\n overflow: auto;\n}\n\n.tbDatasource-container {\n margin: 5px;\n padding: 8px;\n}\n\n.tbDatasource-title {\n font-size: 1.200rem;\n font-weight: 500;\n padding-bottom: 10px;\n}\n\n.tbDatasource-table {\n width: 100%;\n box-shadow: 0 0 10px #ccc;\n border-collapse: collapse;\n white-space: nowrap;\n font-size: 1.000rem;\n color: #757575;\n}\n\n.tbDatasource-table td {\n position: relative;\n border-top: 1px solid rgba(0, 0, 0, 0.12);\n border-bottom: 1px solid rgba(0, 0, 0, 0.12);\n padding: 0px 18px;\n box-sizing: border-box;\n}", - "controllerScript": "self.onInit = function() {\n \n self.ctx.datasourceTitleCells = [];\n self.ctx.valueCells = [];\n self.ctx.labelCells = [];\n \n for (var i=0; i < self.ctx.datasources.length; i++) {\n var tbDatasource = self.ctx.datasources[i];\n\n var datasourceId = 'tbDatasource' + i;\n self.ctx.$container.append(\n \"
\"\n );\n\n var datasourceContainer = $('#' + datasourceId,\n self.ctx.$container);\n\n datasourceContainer.append(\n \"
\" +\n tbDatasource.name + \"
\"\n );\n \n var datasourceTitleCell = $('.tbDatasource-title', datasourceContainer);\n self.ctx.datasourceTitleCells.push(datasourceTitleCell);\n \n var tableId = 'table' + i;\n datasourceContainer.append(\n \"
\"\n );\n var table = $('#' + tableId, self.ctx.$container);\n\n for (var a = 0; a < tbDatasource.dataKeys.length; a++) {\n var dataKey = tbDatasource.dataKeys[a];\n var labelCellId = 'labelCell' + a;\n var cellId = 'cell' + a;\n table.append(\"\" + dataKey.label +\n \"\");\n var labelCell = $('#' + labelCellId, table);\n self.ctx.labelCells.push(labelCell);\n var valueCell = $('#' + cellId, table);\n self.ctx.valueCells.push(valueCell);\n }\n } \n \n self.onResize();\n}\n\nself.onDataUpdated = function() {\n for (var i = 0; i < self.ctx.valueCells.length; i++) {\n var cellData = self.ctx.data[i];\n if (cellData && cellData.data && cellData.data.length > 0) {\n var tvPair = cellData.data[cellData.data.length -\n 1];\n var value = tvPair[1];\n var textValue;\n //toDo -> + IsNumber\n \n if (isNumber(value)) {\n var decimals = self.ctx.decimals;\n var units = self.ctx.units;\n if (cellData.dataKey.decimals || cellData.dataKey.decimals === 0) {\n decimals = cellData.dataKey.decimals;\n }\n if (cellData.dataKey.units) {\n units = cellData.dataKey.units;\n }\n txtValue = self.ctx.utils.formatValue(value, decimals, units, true);\n } else {\n txtValue = value;\n }\n self.ctx.valueCells[i].html(txtValue);\n }\n }\n \n function isNumber(n) {\n return !isNaN(parseFloat(n)) && isFinite(n);\n }\n}\n\nself.onResize = function() {\n var datasourceTitleFontSize = self.ctx.height/8;\n if (self.ctx.width/self.ctx.height <= 1.5) {\n datasourceTitleFontSize = self.ctx.width/12;\n }\n datasourceTitleFontSize = Math.min(datasourceTitleFontSize, 20);\n for (var i = 0; i < self.ctx.datasourceTitleCells.length; i++) {\n self.ctx.datasourceTitleCells[i].css('font-size', datasourceTitleFontSize+'px');\n }\n var valueFontSize = self.ctx.height/9;\n var labelFontSize = self.ctx.height/9;\n if (self.ctx.width/self.ctx.height <= 1.5) {\n valueFontSize = self.ctx.width/15;\n labelFontSize = self.ctx.width/15;\n }\n valueFontSize = Math.min(valueFontSize, 18);\n labelFontSize = Math.min(labelFontSize, 18);\n\n for (i = 0; i < self.ctx.valueCells; i++) {\n self.ctx.valueCells[i].css('font-size', valueFontSize+'px');\n self.ctx.valueCells[i].css('height', valueFontSize*2.5+'px');\n self.ctx.valueCells[i].css('padding', '0px ' + valueFontSize + 'px');\n self.ctx.labelCells[i].css('font-size', labelFontSize+'px');\n self.ctx.labelCells[i].css('height', labelFontSize*2.5+'px');\n self.ctx.labelCells[i].css('padding', '0px ' + labelFontSize + 'px');\n } \n}\n\nself.onDestroy = function() {\n}\n", + "controllerScript": "self.onInit = function() {\n\n self.ctx.datasourceTitleCells = [];\n self.ctx.valueCells = [];\n self.ctx.labelCells = [];\n\n for (var i = 0; i < self.ctx.datasources\n .length; i++) {\n var tbDatasource = self.ctx.datasources[i];\n\n var datasourceId = 'tbDatasource' + i;\n self.ctx.$container.append(\n \"
\"\n );\n\n var datasourceContainer = $('#' + datasourceId,\n self.ctx.$container);\n\n datasourceContainer.append(\n \"
\" +\n tbDatasource.name + \"
\"\n );\n\n var datasourceTitleCell = $(\n '.tbDatasource-title',\n datasourceContainer);\n self.ctx.datasourceTitleCells.push(\n datasourceTitleCell);\n\n var tableId = 'table' + i;\n datasourceContainer.append(\n \"
\"\n );\n var table = $('#' + tableId, self.ctx\n .$container);\n\n for (var a = 0; a < tbDatasource.dataKeys\n .length; a++) {\n var dataKey = tbDatasource.dataKeys[a];\n var labelCellId = 'labelCell' + a;\n var cellId = 'cell' + a;\n table.append(\"\" + dataKey.label +\n \"\");\n var labelCell = $('#' + labelCellId, table);\n self.ctx.labelCells.push(labelCell);\n var valueCell = $('#' + cellId, table);\n self.ctx.valueCells.push(valueCell);\n }\n }\n\n self.onResize();\n}\n\nself.onDataUpdated = function() {\n for (var i = 0; i < self.ctx.valueCells\n .length; i++) {\n var cellData = self.ctx.data[i];\n if (cellData && cellData.data && cellData.data\n .length > 0) {\n var tvPair = cellData.data[cellData.data\n .length -\n 1];\n var value = tvPair[1];\n var textValue;\n //toDo -> + IsNumber\n\n if (isNumber(value)) {\n var decimals = self.ctx.decimals;\n var units = self.ctx.units;\n if (cellData.dataKey.decimals ||\n cellData.dataKey.decimals === 0) {\n decimals = cellData.dataKey\n .decimals;\n }\n if (cellData.dataKey.units) {\n units = cellData.dataKey.units;\n }\n txtValue = self.ctx.utils.formatValue(\n value, decimals, units, true);\n } else {\n txtValue = self.ctx.utilsService\n .customTranslation(value);\n }\n self.ctx.valueCells[i].html(txtValue);\n }\n }\n\n function isNumber(n) {\n return !isNaN(parseFloat(n)) && isFinite(n);\n }\n}\n\nself.onResize = function() {\n var datasourceTitleFontSize = self.ctx.height / 8;\n if (self.ctx.width / self.ctx.height <= 1.5) {\n datasourceTitleFontSize = self.ctx.width / 12;\n }\n datasourceTitleFontSize = Math.min(\n datasourceTitleFontSize, 20);\n for (var i = 0; i < self.ctx.datasourceTitleCells\n .length; i++) {\n self.ctx.datasourceTitleCells[i].css(\n 'font-size', datasourceTitleFontSize +\n 'px');\n }\n var valueFontSize = self.ctx.height / 9;\n var labelFontSize = self.ctx.height / 9;\n if (self.ctx.width / self.ctx.height <= 1.5) {\n valueFontSize = self.ctx.width / 15;\n labelFontSize = self.ctx.width / 15;\n }\n valueFontSize = Math.min(valueFontSize, 18);\n labelFontSize = Math.min(labelFontSize, 18);\n\n for (i = 0; i < self.ctx.valueCells; i++) {\n self.ctx.valueCells[i].css('font-size',\n valueFontSize + 'px');\n self.ctx.valueCells[i].css('height',\n valueFontSize * 2.5 + 'px');\n self.ctx.valueCells[i].css('padding', '0px ' +\n valueFontSize + 'px');\n self.ctx.labelCells[i].css('font-size',\n labelFontSize + 'px');\n self.ctx.labelCells[i].css('height',\n labelFontSize * 2.5 + 'px');\n self.ctx.labelCells[i].css('padding', '0px ' +\n labelFontSize + 'px');\n }\n}\n\nself.onDestroy = function() {}", "settingsSchema": "{}", "dataKeySettingsSchema": "{}\n", "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Random\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.15479322438769105,\"funcBody\":\"var value = prevValue + Math.random() * 100 - 50;\\nvar multiplier = Math.pow(10, 2 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < -1000) {\\n\\tvalue = -1000;\\n} else if (value > 1000) {\\n\\tvalue = 1000;\\n}\\nreturn value;\"}]}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":true,\"backgroundColor\":\"#fff\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"8px\",\"settings\":{},\"title\":\"Attributes card\",\"decimals\":null}" @@ -29,4 +29,4 @@ "public": true } ] -} \ No newline at end of file +} diff --git a/application/src/main/java/org/thingsboard/server/actors/calculatedField/CalculatedFieldEntityMessageProcessor.java b/application/src/main/java/org/thingsboard/server/actors/calculatedField/CalculatedFieldEntityMessageProcessor.java index 35539834c3..257e9d8565 100644 --- a/application/src/main/java/org/thingsboard/server/actors/calculatedField/CalculatedFieldEntityMessageProcessor.java +++ b/application/src/main/java/org/thingsboard/server/actors/calculatedField/CalculatedFieldEntityMessageProcessor.java @@ -36,6 +36,7 @@ import org.thingsboard.server.common.data.msg.TbMsgType; import org.thingsboard.server.common.msg.cf.CalculatedFieldPartitionChangeMsg; import org.thingsboard.server.common.msg.queue.ServiceType; import org.thingsboard.server.common.msg.queue.TbCallback; +import org.thingsboard.server.common.util.ProtoUtils; import org.thingsboard.server.gen.transport.TransportProtos.AttributeScopeProto; import org.thingsboard.server.gen.transport.TransportProtos.AttributeValueProto; import org.thingsboard.server.gen.transport.TransportProtos.CalculatedFieldTelemetryMsgProto; @@ -48,6 +49,7 @@ import org.thingsboard.server.service.cf.ctx.state.ArgumentEntry; import org.thingsboard.server.service.cf.ctx.state.CalculatedFieldCtx; import org.thingsboard.server.service.cf.ctx.state.CalculatedFieldState; import org.thingsboard.server.service.cf.ctx.state.SingleValueArgumentEntry; +import org.thingsboard.server.service.cf.ctx.state.TsRollingArgumentEntry; import java.util.ArrayList; import java.util.Collection; @@ -62,6 +64,8 @@ import java.util.UUID; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; +import static org.thingsboard.server.service.cf.ctx.state.TsRollingArgumentEntry.getValueForTsRecord; + /** * @author Andrew Shvayka @@ -112,6 +116,7 @@ public class CalculatedFieldEntityMessageProcessor extends AbstractContextAwareM } else { states.remove(cfId); } + msg.getCallback().onSuccess(); } public void process(EntityInitCalculatedFieldMsg msg) throws CalculatedFieldException { @@ -346,21 +351,48 @@ public class CalculatedFieldEntityMessageProcessor extends AbstractContextAwareM return mapToArguments(argNames, data); } - private Map mapToArguments(Map argNames, List data) { - if (argNames.isEmpty()) { + private Map mapToArguments(Map> args, List data) { + if (args.isEmpty()) { return Collections.emptyMap(); } Map arguments = new HashMap<>(); for (TsKvProto item : data) { ReferencedEntityKey key = new ReferencedEntityKey(item.getKv().getKey(), ArgumentType.TS_LATEST, null); - String argName = argNames.get(key); - if (argName != null) { - arguments.put(argName, new SingleValueArgumentEntry(item)); + Set argNames = args.get(key); + if (argNames != null) { + SingleValueArgumentEntry incoming = new SingleValueArgumentEntry(item); + argNames.forEach(argName -> arguments.compute(argName, (name, existing) -> { + if (existing == null) { + return incoming; + } + existing.updateEntry(incoming); + return existing; + })); } + key = new ReferencedEntityKey(item.getKv().getKey(), ArgumentType.TS_ROLLING, null); - argName = argNames.get(key); - if (argName != null) { - arguments.put(argName, new SingleValueArgumentEntry(item)); + argNames = args.get(key); + if (argNames != null) { + Double recordValue = getValueForTsRecord(ProtoUtils.fromProto(item.getKv())); + argNames.forEach(argName -> arguments.compute(argName, (name, existing) -> { + if (existing instanceof TsRollingArgumentEntry rolling) { + if (recordValue != null) { + rolling.getTsRecords().put(item.getTs(), recordValue); + } + return rolling; + } + TsRollingArgumentEntry rolling = new TsRollingArgumentEntry(); + if (recordValue != null) { + rolling.getTsRecords().put(item.getTs(), recordValue); + } + if (existing instanceof SingleValueArgumentEntry single) { + Double existingValue = getValueForTsRecord(single.getKvEntryValue()); + if (existingValue != null) { + rolling.getTsRecords().put(single.getTs(), existingValue); + } + } + return rolling; + })); } } return arguments; @@ -378,13 +410,13 @@ public class CalculatedFieldEntityMessageProcessor extends AbstractContextAwareM return mapToArguments(argNames, scope, attrDataList); } - private Map mapToArguments(Map argNames, AttributeScopeProto scope, List attrDataList) { + private Map mapToArguments(Map> args, AttributeScopeProto scope, List attrDataList) { Map arguments = new HashMap<>(); for (AttributeValueProto item : attrDataList) { ReferencedEntityKey key = new ReferencedEntityKey(item.getKey(), ArgumentType.ATTRIBUTE, AttributeScope.valueOf(scope.name())); - String argName = argNames.get(key); - if (argName != null) { - arguments.put(argName, new SingleValueArgumentEntry(item)); + Set argNames = args.get(key); + if (argNames != null) { + argNames.forEach(argName -> arguments.put(argName, new SingleValueArgumentEntry(item))); } } return arguments; @@ -402,18 +434,19 @@ public class CalculatedFieldEntityMessageProcessor extends AbstractContextAwareM return mapToArgumentsWithDefaultValue(ctx.getMainEntityArguments(), ctx.getArguments(), scope, removedAttrKeys); } - private Map mapToArgumentsWithDefaultValue(Map argNames, Map configArguments, AttributeScopeProto scope, List removedAttrKeys) { + private Map mapToArgumentsWithDefaultValue(Map> args, Map configArguments, AttributeScopeProto scope, List removedAttrKeys) { Map arguments = new HashMap<>(); for (String removedKey : removedAttrKeys) { ReferencedEntityKey key = new ReferencedEntityKey(removedKey, ArgumentType.ATTRIBUTE, AttributeScope.valueOf(scope.name())); - String argName = argNames.get(key); - if (argName != null) { - Argument argument = configArguments.get(argName); - String defaultValue = (argument != null) ? argument.getDefaultValue() : null; - arguments.put(argName, StringUtils.isNotEmpty(defaultValue) - ? new SingleValueArgumentEntry(System.currentTimeMillis(), new StringDataEntry(removedKey, defaultValue), null) - : new SingleValueArgumentEntry()); - + Set argNames = args.get(key); + if (argNames != null) { + argNames.forEach(argName -> { + Argument argument = configArguments.get(argName); + String defaultValue = (argument != null) ? argument.getDefaultValue() : null; + arguments.put(argName, StringUtils.isNotEmpty(defaultValue) + ? new SingleValueArgumentEntry(System.currentTimeMillis(), new StringDataEntry(removedKey, defaultValue), null) + : new SingleValueArgumentEntry()); + }); } } return arguments; diff --git a/application/src/main/java/org/thingsboard/server/actors/calculatedField/CalculatedFieldManagerMessageProcessor.java b/application/src/main/java/org/thingsboard/server/actors/calculatedField/CalculatedFieldManagerMessageProcessor.java index 590e097928..b8bc74db7a 100644 --- a/application/src/main/java/org/thingsboard/server/actors/calculatedField/CalculatedFieldManagerMessageProcessor.java +++ b/application/src/main/java/org/thingsboard/server/actors/calculatedField/CalculatedFieldManagerMessageProcessor.java @@ -125,10 +125,13 @@ public class CalculatedFieldManagerMessageProcessor extends AbstractContextAware if (msg.getState() != null) { msg.getState().setRequiredArguments(calculatedField.getArgNames()); } - log.debug("Pushing CF state restore msg to specific actor [{}]", msg.getId().entityId()); + log.debug("[{}] Pushing CF state restore msg to specific actor [{}]", tenantId, msg.getId().entityId()); getOrCreateActor(msg.getId().entityId()).tell(msg); - } else { + } else if (msg.getState() != null) { + log.debug("[{}] Received CF state restore msg for non-existing CF [{}]. Removing state", tenantId, cfId); cfStateService.removeState(msg.getId(), msg.getCallback()); + } else { + msg.getCallback().onSuccess(); } } diff --git a/application/src/main/java/org/thingsboard/server/actors/calculatedField/CalculatedFieldStateRestoreMsg.java b/application/src/main/java/org/thingsboard/server/actors/calculatedField/CalculatedFieldStateRestoreMsg.java index 19be7c02fa..fbe666c662 100644 --- a/application/src/main/java/org/thingsboard/server/actors/calculatedField/CalculatedFieldStateRestoreMsg.java +++ b/application/src/main/java/org/thingsboard/server/actors/calculatedField/CalculatedFieldStateRestoreMsg.java @@ -19,6 +19,7 @@ import lombok.Data; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.msg.MsgType; import org.thingsboard.server.common.msg.ToCalculatedFieldSystemMsg; +import org.thingsboard.server.common.msg.queue.TbCallback; import org.thingsboard.server.service.cf.ctx.CalculatedFieldEntityCtxId; import org.thingsboard.server.service.cf.ctx.state.CalculatedFieldState; @@ -27,6 +28,7 @@ public class CalculatedFieldStateRestoreMsg implements ToCalculatedFieldSystemMs private final CalculatedFieldEntityCtxId id; private final CalculatedFieldState state; + private final TbCallback callback; @Override public MsgType getMsgType() { diff --git a/application/src/main/java/org/thingsboard/server/actors/device/DeviceActorMessageProcessor.java b/application/src/main/java/org/thingsboard/server/actors/device/DeviceActorMessageProcessor.java index c143214e2b..b24b803950 100644 --- a/application/src/main/java/org/thingsboard/server/actors/device/DeviceActorMessageProcessor.java +++ b/application/src/main/java/org/thingsboard/server/actors/device/DeviceActorMessageProcessor.java @@ -115,14 +115,9 @@ import java.util.concurrent.TimeUnit; import java.util.function.Consumer; import java.util.stream.Collectors; - -/** - * @author Andrew Shvayka - */ @Slf4j public class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { - static final String SESSION_TIMEOUT_MESSAGE = "session timeout!"; final TenantId tenantId; final DeviceId deviceId; final LinkedHashMapRemoveEldest sessions; @@ -178,7 +173,7 @@ public class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcesso private EdgeId findRelatedEdgeId() { List result = systemContext.getRelationService().findByToAndType(tenantId, deviceId, EntityRelation.CONTAINS_TYPE, RelationTypeGroup.EDGE); - if (result != null && result.size() > 0) { + if (result != null && !result.isEmpty()) { EntityRelation relationToEdge = result.get(0); if (relationToEdge.getFrom() != null && relationToEdge.getFrom().getId() != null) { log.trace("[{}][{}] found edge [{}] for device", tenantId, deviceId, relationToEdge.getFrom().getId()); @@ -501,7 +496,7 @@ public class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcesso UUID sessionId = getSessionId(sessionInfo); DeviceId deviceId = new DeviceId(new UUID(msg.getDeviceIdMSB(), msg.getDeviceIdLSB())); ListenableFuture registrationFuture = systemContext.getClaimDevicesService() - .registerClaimingInfo(tenantId, deviceId, msg.getSecretKey(), msg.getDurationMs()); + .registerClaimingInfo(tenantId, deviceId, msg.getSecretKey(), msg.getDurationMs()); Futures.addCallback(registrationFuture, new FutureCallback<>() { @Override public void onSuccess(Void result) { @@ -723,7 +718,7 @@ public class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcesso toDeviceRpcPendingMap.remove(requestId); status = RpcStatus.FAILED; response = JacksonUtil.newObjectNode().put("error", "There was a Timeout and all retry " + - "attempts have been exhausted. Retry attempts set: " + maxRpcRetries); + "attempts have been exhausted. Retry attempts set: " + maxRpcRetries); } } else { md.setRetries(md.getRetries() + 1); diff --git a/application/src/main/java/org/thingsboard/server/actors/tenant/TenantActor.java b/application/src/main/java/org/thingsboard/server/actors/tenant/TenantActor.java index 91d25a633b..fa17c0ca2c 100644 --- a/application/src/main/java/org/thingsboard/server/actors/tenant/TenantActor.java +++ b/application/src/main/java/org/thingsboard/server/actors/tenant/TenantActor.java @@ -43,7 +43,6 @@ import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent; import org.thingsboard.server.common.data.rule.RuleChain; import org.thingsboard.server.common.data.rule.RuleChainType; -import org.thingsboard.server.common.msg.MsgType; import org.thingsboard.server.common.msg.TbActorMsg; import org.thingsboard.server.common.msg.TbActorStopReason; import org.thingsboard.server.common.msg.TbMsg; @@ -138,13 +137,22 @@ public class TenantActor extends RuleChainManagerActor { @Override protected boolean doProcess(TbActorMsg msg) { if (cantFindTenant) { - log.info("[{}] Processing missing Tenant msg: {}", tenantId, msg); - if (msg.getMsgType().equals(MsgType.QUEUE_TO_RULE_ENGINE_MSG)) { - QueueToRuleEngineMsg queueMsg = (QueueToRuleEngineMsg) msg; - queueMsg.getMsg().getCallback().onSuccess(); - } else if (msg.getMsgType().equals(MsgType.TRANSPORT_TO_DEVICE_ACTOR_MSG)) { - TransportToDeviceActorMsgWrapper transportMsg = (TransportToDeviceActorMsgWrapper) msg; - transportMsg.getCallback().onSuccess(); + log.debug("[{}] Processing message for non-existing tenant: {}", tenantId, msg); + switch (msg.getMsgType()) { + case QUEUE_TO_RULE_ENGINE_MSG -> { + ((QueueToRuleEngineMsg) msg).getMsg().getCallback().onSuccess(); + } + case TRANSPORT_TO_DEVICE_ACTOR_MSG -> { + ((TransportToDeviceActorMsgWrapper) msg).getCallback().onSuccess(); + } + case CF_STATE_RESTORE_MSG -> { + ((CalculatedFieldStateRestoreMsg) msg).getCallback().onSuccess(); + } + default -> { + if (!log.isDebugEnabled()) { + log.info("[{}] Processing message for non-existing tenant: {}", tenantId, msg); + } + } } return true; } @@ -390,6 +398,7 @@ public class TenantActor extends RuleChainManagerActor { public TbActor createActor() { return new TenantActor(context, tenantId); } + } } diff --git a/application/src/main/java/org/thingsboard/server/controller/UserController.java b/application/src/main/java/org/thingsboard/server/controller/UserController.java index b9cb0c88b3..a2a7c993e9 100644 --- a/application/src/main/java/org/thingsboard/server/controller/UserController.java +++ b/application/src/main/java/org/thingsboard/server/controller/UserController.java @@ -266,6 +266,9 @@ public class UserController extends BaseController { if (user.getAuthority() == Authority.SYS_ADMIN && getCurrentUser().getId().equals(userId)) { throw new ThingsboardException("Sysadmin is not allowed to delete himself", ThingsboardErrorCode.PERMISSION_DENIED); } + if (user.getAuthority() == Authority.TENANT_ADMIN && userService.countTenantAdmins(user.getTenantId()) == 1) { + throw new ThingsboardException("At least one tenant administrator must remain!", ThingsboardErrorCode.BAD_REQUEST_PARAMS); + } tbUserService.delete(getTenantId(), getCurrentUser().getCustomerId(), user, getCurrentUser()); } diff --git a/application/src/main/java/org/thingsboard/server/service/ai/AiChatModelServiceImpl.java b/application/src/main/java/org/thingsboard/server/service/ai/AiChatModelServiceImpl.java index c1829cbf84..639e2025fe 100644 --- a/application/src/main/java/org/thingsboard/server/service/ai/AiChatModelServiceImpl.java +++ b/application/src/main/java/org/thingsboard/server/service/ai/AiChatModelServiceImpl.java @@ -15,6 +15,7 @@ */ package org.thingsboard.server.service.ai; +import com.fasterxml.jackson.core.io.JsonStringEncoder; import com.google.common.util.concurrent.FluentFuture; import dev.langchain4j.data.message.ChatMessage; import dev.langchain4j.data.message.Content; @@ -32,8 +33,6 @@ import org.thingsboard.server.common.data.ai.model.chat.Langchain4jChatModelConf import java.util.List; import java.util.stream.Collectors; -import static org.thingsboard.server.common.data.StringUtils.escapeControlChars; - @Service @RequiredArgsConstructor class AiChatModelServiceImpl implements AiChatModelService { @@ -74,7 +73,7 @@ class AiChatModelServiceImpl implements AiChatModelService { private Content prepareContent(Content content) { if (content instanceof TextContent txt) { - return new TextContent(escapeControlChars(txt.text())); + return new TextContent(new String(JsonStringEncoder.getInstance().quoteAsString(txt.text()))); } return content; } diff --git a/application/src/main/java/org/thingsboard/server/service/cf/AbstractCalculatedFieldStateService.java b/application/src/main/java/org/thingsboard/server/service/cf/AbstractCalculatedFieldStateService.java index 70b41f069e..87bdda2b30 100644 --- a/application/src/main/java/org/thingsboard/server/service/cf/AbstractCalculatedFieldStateService.java +++ b/application/src/main/java/org/thingsboard/server/service/cf/AbstractCalculatedFieldStateService.java @@ -62,14 +62,14 @@ public abstract class AbstractCalculatedFieldStateService implements CalculatedF protected abstract void doRemove(CalculatedFieldEntityCtxId stateId, TbCallback callback); - protected void processRestoredState(CalculatedFieldStateProto stateMsg) { + protected void processRestoredState(CalculatedFieldStateProto stateMsg, TbCallback callback) { var id = fromProto(stateMsg.getId()); var state = fromProto(stateMsg); - processRestoredState(id, state); + processRestoredState(id, state, callback); } - protected void processRestoredState(CalculatedFieldEntityCtxId id, CalculatedFieldState state) { - actorSystemContext.tell(new CalculatedFieldStateRestoreMsg(id, state)); + protected void processRestoredState(CalculatedFieldEntityCtxId id, CalculatedFieldState state, TbCallback callback) { + actorSystemContext.tell(new CalculatedFieldStateRestoreMsg(id, state, callback)); } @Override diff --git a/application/src/main/java/org/thingsboard/server/service/cf/DefaultCalculatedFieldProcessingService.java b/application/src/main/java/org/thingsboard/server/service/cf/DefaultCalculatedFieldProcessingService.java index f2a6916751..b6e1193cfb 100644 --- a/application/src/main/java/org/thingsboard/server/service/cf/DefaultCalculatedFieldProcessingService.java +++ b/application/src/main/java/org/thingsboard/server/service/cf/DefaultCalculatedFieldProcessingService.java @@ -23,7 +23,6 @@ import jakarta.annotation.PostConstruct; import jakarta.annotation.PreDestroy; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.apache.commons.lang3.math.NumberUtils; import org.springframework.stereotype.Service; import org.thingsboard.common.util.ThingsBoardExecutors; import org.thingsboard.server.actors.calculatedField.CalculatedFieldTelemetryMsg; @@ -31,21 +30,14 @@ import org.thingsboard.server.actors.calculatedField.MultipleTbCallback; import org.thingsboard.server.cluster.TbClusterService; import org.thingsboard.server.common.data.DataConstants; import org.thingsboard.server.common.data.EntityType; -import org.thingsboard.server.common.data.StringUtils; import org.thingsboard.server.common.data.cf.configuration.Argument; import org.thingsboard.server.common.data.cf.configuration.OutputType; import org.thingsboard.server.common.data.id.CalculatedFieldId; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.kv.Aggregation; -import org.thingsboard.server.common.data.kv.BaseAttributeKvEntry; import org.thingsboard.server.common.data.kv.BaseReadTsKvQuery; -import org.thingsboard.server.common.data.kv.BasicTsKvEntry; -import org.thingsboard.server.common.data.kv.BooleanDataEntry; -import org.thingsboard.server.common.data.kv.DoubleDataEntry; -import org.thingsboard.server.common.data.kv.KvEntry; import org.thingsboard.server.common.data.kv.ReadTsKvQuery; -import org.thingsboard.server.common.data.kv.StringDataEntry; import org.thingsboard.server.common.data.kv.TsKvEntry; import org.thingsboard.server.common.data.msg.TbMsgType; import org.thingsboard.server.common.data.tenant.profile.DefaultTenantProfileConfiguration; @@ -70,9 +62,6 @@ import org.thingsboard.server.service.cf.ctx.CalculatedFieldEntityCtxId; import org.thingsboard.server.service.cf.ctx.state.ArgumentEntry; import org.thingsboard.server.service.cf.ctx.state.CalculatedFieldCtx; import org.thingsboard.server.service.cf.ctx.state.CalculatedFieldState; -import org.thingsboard.server.service.cf.ctx.state.ScriptCalculatedFieldState; -import org.thingsboard.server.service.cf.ctx.state.SimpleCalculatedFieldState; -import org.thingsboard.server.service.cf.ctx.state.SingleValueArgumentEntry; import org.thingsboard.server.service.cf.ctx.state.TsRollingArgumentEntry; import java.util.ArrayList; @@ -80,12 +69,15 @@ import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; -import java.util.Optional; import java.util.UUID; import java.util.concurrent.ExecutionException; import java.util.stream.Collectors; import static org.thingsboard.server.common.data.DataConstants.SCOPE; +import static org.thingsboard.server.utils.CalculatedFieldArgumentUtils.createDefaultAttributeEntry; +import static org.thingsboard.server.utils.CalculatedFieldArgumentUtils.createDefaultTsKvEntry; +import static org.thingsboard.server.utils.CalculatedFieldArgumentUtils.createStateByType; +import static org.thingsboard.server.utils.CalculatedFieldArgumentUtils.transformSingleValueArgument; import static org.thingsboard.server.utils.CalculatedFieldUtils.toProto; @TbRuleEngineComponent @@ -244,30 +236,17 @@ public class DefaultCalculatedFieldProcessingService implements CalculatedFieldP private ListenableFuture fetchKvEntry(TenantId tenantId, EntityId entityId, Argument argument) { return switch (argument.getRefEntityKey().getType()) { case TS_ROLLING -> fetchTsRolling(tenantId, entityId, argument); - case ATTRIBUTE -> transformSingleValueArgument( - Futures.transform( - attributesService.find(tenantId, entityId, argument.getRefEntityKey().getScope(), argument.getRefEntityKey().getKey()), - result -> result.or(() -> Optional.of(new BaseAttributeKvEntry(createDefaultKvEntry(argument), System.currentTimeMillis(), 0L))), - calculatedFieldCallbackExecutor) - ); - case TS_LATEST -> transformSingleValueArgument( - Futures.transform( - timeseriesService.findLatest(tenantId, entityId, argument.getRefEntityKey().getKey()), - result -> result.or(() -> Optional.of(new BasicTsKvEntry(System.currentTimeMillis(), createDefaultKvEntry(argument), 0L))), - calculatedFieldCallbackExecutor)); + case ATTRIBUTE -> Futures.transform( + attributesService.find(tenantId, entityId, argument.getRefEntityKey().getScope(), argument.getRefEntityKey().getKey()), + result -> transformSingleValueArgument(result.orElseGet(() -> createDefaultAttributeEntry(argument, System.currentTimeMillis()))), + calculatedFieldCallbackExecutor); + case TS_LATEST -> Futures.transform( + timeseriesService.findLatest(tenantId, entityId, argument.getRefEntityKey().getKey()), + result -> transformSingleValueArgument(result.orElseGet(() -> createDefaultTsKvEntry(argument, System.currentTimeMillis()))), + calculatedFieldCallbackExecutor); }; } - private ListenableFuture transformSingleValueArgument(ListenableFuture> kvEntryFuture) { - return Futures.transform(kvEntryFuture, kvEntry -> { - if (kvEntry.isPresent() && kvEntry.get().getValue() != null) { - return ArgumentEntry.createSingleValueArgument(kvEntry.get()); - } else { - return new SingleValueArgumentEntry(); - } - }, calculatedFieldCallbackExecutor); - } - private ListenableFuture fetchTsRolling(TenantId tenantId, EntityId entityId, Argument argument) { long currentTime = System.currentTimeMillis(); long timeWindow = argument.getTimeWindow() == 0 ? System.currentTimeMillis() : argument.getTimeWindow(); @@ -282,28 +261,6 @@ public class DefaultCalculatedFieldProcessingService implements CalculatedFieldP return Futures.transform(tsRollingFuture, tsRolling -> tsRolling == null ? new TsRollingArgumentEntry(limit, timeWindow) : ArgumentEntry.createTsRollingArgument(tsRolling, limit, timeWindow), calculatedFieldCallbackExecutor); } - private KvEntry createDefaultKvEntry(Argument argument) { - String key = argument.getRefEntityKey().getKey(); - String defaultValue = argument.getDefaultValue(); - if (StringUtils.isBlank(defaultValue)) { - return new StringDataEntry(key, null); - } - if (NumberUtils.isParsable(defaultValue)) { - return new DoubleDataEntry(key, Double.parseDouble(defaultValue)); - } - if ("true".equalsIgnoreCase(defaultValue) || "false".equalsIgnoreCase(defaultValue)) { - return new BooleanDataEntry(key, Boolean.parseBoolean(defaultValue)); - } - return new StringDataEntry(key, defaultValue); - } - - private CalculatedFieldState createStateByType(CalculatedFieldCtx ctx) { - return switch (ctx.getCfType()) { - case SIMPLE -> new SimpleCalculatedFieldState(ctx.getArgNames()); - case SCRIPT -> new ScriptCalculatedFieldState(ctx.getArgNames()); - }; - } - private static class TbCallbackWrapper implements TbQueueCallback { private final TbCallback callback; diff --git a/application/src/main/java/org/thingsboard/server/service/cf/ctx/state/BaseCalculatedFieldState.java b/application/src/main/java/org/thingsboard/server/service/cf/ctx/state/BaseCalculatedFieldState.java index e21d56b6d2..14370aa68c 100644 --- a/application/src/main/java/org/thingsboard/server/service/cf/ctx/state/BaseCalculatedFieldState.java +++ b/application/src/main/java/org/thingsboard/server/service/cf/ctx/state/BaseCalculatedFieldState.java @@ -31,19 +31,19 @@ import static org.thingsboard.server.utils.CalculatedFieldUtils.toSingleValueArg @AllArgsConstructor public abstract class BaseCalculatedFieldState implements CalculatedFieldState { + static final long DEFAULT_LAST_UPDATE_TS = -1L; + protected List requiredArguments; protected Map arguments; protected boolean sizeExceedsLimit; - protected long latestTimestamp = -1; - public BaseCalculatedFieldState(List requiredArguments) { this.requiredArguments = requiredArguments; this.arguments = new HashMap<>(); } public BaseCalculatedFieldState() { - this(new ArrayList<>(), new HashMap<>(), false, -1); + this(new ArrayList<>(), new HashMap<>(), false); } @Override @@ -73,7 +73,6 @@ public abstract class BaseCalculatedFieldState implements CalculatedFieldState { if (entryUpdated) { stateUpdated = true; - updateLastUpdateTimestamp(newEntry); } } @@ -109,15 +108,29 @@ public abstract class BaseCalculatedFieldState implements CalculatedFieldState { protected abstract void validateNewEntry(ArgumentEntry newEntry); - private void updateLastUpdateTimestamp(ArgumentEntry entry) { - long newTs = this.latestTimestamp; - if (entry instanceof SingleValueArgumentEntry singleValueArgumentEntry) { - newTs = singleValueArgumentEntry.getTs(); - } else if (entry instanceof TsRollingArgumentEntry tsRollingArgumentEntry) { - Map.Entry lastEntry = tsRollingArgumentEntry.getTsRecords().lastEntry(); - newTs = (lastEntry != null) ? lastEntry.getKey() : System.currentTimeMillis(); + public long getLatestTimestamp() { + long latestTs = DEFAULT_LAST_UPDATE_TS; + + boolean allDefault = arguments.values().stream().allMatch(entry -> { + if (entry instanceof SingleValueArgumentEntry single) { + return single.isDefaultValue(); + } + return false; + }); + + for (ArgumentEntry entry : arguments.values()) { + if (entry instanceof SingleValueArgumentEntry single) { + if (allDefault) { + latestTs = Math.max(latestTs, single.getTs()); + } else if (!single.isDefaultValue()) { + latestTs = Math.max(latestTs, single.getTs()); + } + } else if (entry instanceof TsRollingArgumentEntry rolling) { + latestTs = Math.max(latestTs, rolling.getLatestTs()); + } } - this.latestTimestamp = Math.max(this.latestTimestamp, newTs); + + return latestTs; } } diff --git a/application/src/main/java/org/thingsboard/server/service/cf/ctx/state/CalculatedFieldCtx.java b/application/src/main/java/org/thingsboard/server/service/cf/ctx/state/CalculatedFieldCtx.java index c9eaaef19a..9ef5a8c2a9 100644 --- a/application/src/main/java/org/thingsboard/server/service/cf/ctx/state/CalculatedFieldCtx.java +++ b/application/src/main/java/org/thingsboard/server/service/cf/ctx/state/CalculatedFieldCtx.java @@ -35,6 +35,7 @@ import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.kv.AttributeKvEntry; import org.thingsboard.server.common.data.kv.TsKvEntry; import org.thingsboard.server.common.data.tenant.profile.DefaultTenantProfileConfiguration; +import org.thingsboard.server.common.data.util.CollectionsUtil; import org.thingsboard.server.common.util.ProtoUtils; import org.thingsboard.server.dao.usagerecord.ApiLimitService; import org.thingsboard.server.gen.transport.TransportProtos.CalculatedFieldTelemetryMsgProto; @@ -44,6 +45,7 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Set; import static org.thingsboard.common.util.ExpressionFunctionsUtil.userDefinedFunctions; @@ -57,8 +59,8 @@ public class CalculatedFieldCtx { private EntityId entityId; private CalculatedFieldType cfType; private final Map arguments; - private final Map mainEntityArguments; - private final Map> linkedEntityArguments; + private final Map> mainEntityArguments; + private final Map>> linkedEntityArguments; private final List argNames; private Output output; private String expression; @@ -88,9 +90,10 @@ public class CalculatedFieldCtx { var refId = entry.getValue().getRefEntityId(); var refKey = entry.getValue().getRefEntityKey(); if (refId == null || refId.equals(calculatedField.getEntityId())) { - mainEntityArguments.put(refKey, entry.getKey()); + mainEntityArguments.compute(refKey, (key, existingNames) -> CollectionsUtil.addToSet(existingNames, entry.getKey())); } else { - linkedEntityArguments.computeIfAbsent(refId, key -> new HashMap<>()).put(refKey, entry.getKey()); + linkedEntityArguments.computeIfAbsent(refId, key -> new HashMap<>()) + .compute(refKey, (key, existingNames) -> CollectionsUtil.addToSet(existingNames, entry.getKey())); } } this.argNames = new ArrayList<>(arguments.keySet()); @@ -182,7 +185,7 @@ public class CalculatedFieldCtx { return map != null && matchesTimeSeries(map, values); } - private boolean matchesAttributes(Map argMap, List values, AttributeScope scope) { + private boolean matchesAttributes(Map> argMap, List values, AttributeScope scope) { if (argMap.isEmpty() || values.isEmpty()) { return false; } @@ -196,7 +199,7 @@ public class CalculatedFieldCtx { return false; } - private boolean matchesTimeSeries(Map argMap, List values) { + private boolean matchesTimeSeries(Map> argMap, List values) { if (argMap.isEmpty() || values.isEmpty()) { return false; } @@ -225,7 +228,7 @@ public class CalculatedFieldCtx { return matchesTimeSeriesKeys(mainEntityArguments, keys); } - private boolean matchesAttributesKeys(Map argMap, List keys, AttributeScope scope) { + private boolean matchesAttributesKeys(Map> argMap, List keys, AttributeScope scope) { if (argMap.isEmpty() || keys.isEmpty()) { return false; } @@ -240,7 +243,7 @@ public class CalculatedFieldCtx { return false; } - private boolean matchesTimeSeriesKeys(Map argMap, List keys) { + private boolean matchesTimeSeriesKeys(Map> argMap, List keys) { if (argMap.isEmpty() || keys.isEmpty()) { return false; } diff --git a/application/src/main/java/org/thingsboard/server/service/cf/ctx/state/KafkaCalculatedFieldStateService.java b/application/src/main/java/org/thingsboard/server/service/cf/ctx/state/KafkaCalculatedFieldStateService.java index 2b52892744..2773e13fa3 100644 --- a/application/src/main/java/org/thingsboard/server/service/cf/ctx/state/KafkaCalculatedFieldStateService.java +++ b/application/src/main/java/org/thingsboard/server/service/cf/ctx/state/KafkaCalculatedFieldStateService.java @@ -43,6 +43,8 @@ import org.thingsboard.server.queue.provider.TbRuleEngineQueueFactory; import org.thingsboard.server.service.cf.AbstractCalculatedFieldStateService; import org.thingsboard.server.service.cf.ctx.CalculatedFieldEntityCtxId; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import static org.thingsboard.server.queue.common.AbstractTbQueueTemplate.bytesToString; @@ -61,6 +63,8 @@ public class KafkaCalculatedFieldStateService extends AbstractCalculatedFieldSta @Value("${queue.calculated_fields.poll_interval:25}") private long pollInterval; + @Value("${queue.calculated_fields.pack_processing_timeout:60000}") + private long packProcessingTimeout; private TbKafkaProducerTemplate> stateProducer; @@ -74,21 +78,39 @@ public class KafkaCalculatedFieldStateService extends AbstractCalculatedFieldSta .topic(partitionService.getTopic(queueKey)) .pollInterval(pollInterval) .msgPackProcessor((msgs, consumer, consumerKey, config) -> { + CountDownLatch completionLatch = new CountDownLatch(msgs.size()); for (TbProtoQueueMsg msg : msgs) { + TbCallback callback = new TbCallback() { + @Override + public void onSuccess() { + int processedMsgCount = counter.incrementAndGet(); + if (processedMsgCount % 10000 == 0) { + log.info("Processed {} CF state messages", processedMsgCount); + } + completionLatch.countDown(); + } + + @Override + public void onFailure(Throwable t) { + log.error("Failed to process CF state message: {}", msg, t); + completionLatch.countDown(); + } + }; + try { if (msg.getValue() != null) { - processRestoredState(msg.getValue()); + processRestoredState(msg.getValue(), callback); } else { - processRestoredState(getStateId(msg.getHeaders()), null); + processRestoredState(getStateId(msg.getHeaders()), null, callback); } } catch (Throwable t) { - log.error("Failed to process state message: {}", msg, t); + callback.onFailure(t); } + } - int processedMsgCount = counter.incrementAndGet(); - if (processedMsgCount % 10000 == 0) { - log.info("Processed {} calculated field state msgs", processedMsgCount); - } + boolean success = completionLatch.await(packProcessingTimeout, TimeUnit.MILLISECONDS); + if (!success) { + log.error("Timeout to process CF state messages pack of size {}", msgs.size()); } }) .consumerCreator((queueConfig, tpi) -> queueFactory.createCalculatedFieldStateConsumer()) diff --git a/application/src/main/java/org/thingsboard/server/service/cf/ctx/state/RocksDBCalculatedFieldStateService.java b/application/src/main/java/org/thingsboard/server/service/cf/ctx/state/RocksDBCalculatedFieldStateService.java index 9dc6139ca5..d17060d093 100644 --- a/application/src/main/java/org/thingsboard/server/service/cf/ctx/state/RocksDBCalculatedFieldStateService.java +++ b/application/src/main/java/org/thingsboard/server/service/cf/ctx/state/RocksDBCalculatedFieldStateService.java @@ -15,7 +15,6 @@ */ package org.thingsboard.server.service.cf.ctx.state; -import com.google.protobuf.InvalidProtocolBufferException; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; @@ -63,11 +62,22 @@ public class RocksDBCalculatedFieldStateService extends AbstractCalculatedFieldS public void restore(QueueKey queueKey, Set partitions) { if (stateService.getPartitions().isEmpty()) { cfRocksDb.forEach((key, value) -> { + CalculatedFieldStateProto stateMsg; try { - processRestoredState(CalculatedFieldStateProto.parseFrom(value)); - } catch (InvalidProtocolBufferException e) { - log.error("[{}] Failed to process restored state", key, e); + stateMsg = CalculatedFieldStateProto.parseFrom(value); + } catch (Exception e) { + log.error("Failed to parse CalculatedFieldStateProto for key {}", key, e); + return; } + processRestoredState(stateMsg, new TbCallback() { + @Override + public void onSuccess() {} + + @Override + public void onFailure(Throwable t) { + log.error("Failed to process CF state message: {}", stateMsg, t); + } + }); }); } super.restore(queueKey, partitions); diff --git a/application/src/main/java/org/thingsboard/server/service/cf/ctx/state/SimpleCalculatedFieldState.java b/application/src/main/java/org/thingsboard/server/service/cf/ctx/state/SimpleCalculatedFieldState.java index 577ff80219..80f5964582 100644 --- a/application/src/main/java/org/thingsboard/server/service/cf/ctx/state/SimpleCalculatedFieldState.java +++ b/application/src/main/java/org/thingsboard/server/service/cf/ctx/state/SimpleCalculatedFieldState.java @@ -100,7 +100,7 @@ public class SimpleCalculatedFieldState extends BaseCalculatedFieldState { } long latestTs = getLatestTimestamp(); - if (useLatestTs && latestTs != -1) { + if (useLatestTs && latestTs != DEFAULT_LAST_UPDATE_TS) { ObjectNode resultNode = JacksonUtil.newObjectNode(); resultNode.put("ts", latestTs); resultNode.set("values", valuesNode); diff --git a/application/src/main/java/org/thingsboard/server/service/cf/ctx/state/SingleValueArgumentEntry.java b/application/src/main/java/org/thingsboard/server/service/cf/ctx/state/SingleValueArgumentEntry.java index 1ceea2c621..2f9a7de940 100644 --- a/application/src/main/java/org/thingsboard/server/service/cf/ctx/state/SingleValueArgumentEntry.java +++ b/application/src/main/java/org/thingsboard/server/service/cf/ctx/state/SingleValueArgumentEntry.java @@ -19,7 +19,6 @@ import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.core.type.TypeReference; import lombok.AllArgsConstructor; import lombok.Data; -import lombok.NoArgsConstructor; import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.script.api.tbel.TbelCfArg; import org.thingsboard.script.api.tbel.TbelCfSingleValueArg; @@ -32,17 +31,25 @@ import org.thingsboard.server.common.util.ProtoUtils; import org.thingsboard.server.gen.transport.TransportProtos.AttributeValueProto; import org.thingsboard.server.gen.transport.TransportProtos.TsKvProto; +import static org.thingsboard.server.service.cf.ctx.state.BaseCalculatedFieldState.DEFAULT_LAST_UPDATE_TS; + @Data -@NoArgsConstructor @AllArgsConstructor public class SingleValueArgumentEntry implements ArgumentEntry { + public static final Long DEFAULT_VERSION = -1L; + private long ts; private BasicKvEntry kvEntryValue; private Long version; private boolean forceResetPrevious; + public SingleValueArgumentEntry() { + this.ts = DEFAULT_LAST_UPDATE_TS; + this.version = DEFAULT_VERSION; + } + public SingleValueArgumentEntry(TsKvProto entry) { this.ts = entry.getTs(); if (entry.hasVersion()) { @@ -112,7 +119,7 @@ public class SingleValueArgumentEntry implements ArgumentEntry { @Override public boolean updateEntry(ArgumentEntry entry) { if (entry instanceof SingleValueArgumentEntry singleValueEntry) { - if (singleValueEntry.getTs() <= this.ts) { + if (singleValueEntry.getTs() < this.ts) { return false; } @@ -128,4 +135,9 @@ public class SingleValueArgumentEntry implements ArgumentEntry { } return false; } + + public boolean isDefaultValue() { + return DEFAULT_VERSION.equals(this.version); + } + } diff --git a/application/src/main/java/org/thingsboard/server/service/cf/ctx/state/TsRollingArgumentEntry.java b/application/src/main/java/org/thingsboard/server/service/cf/ctx/state/TsRollingArgumentEntry.java index b5a680a072..9f9ad5db73 100644 --- a/application/src/main/java/org/thingsboard/server/service/cf/ctx/state/TsRollingArgumentEntry.java +++ b/application/src/main/java/org/thingsboard/server/service/cf/ctx/state/TsRollingArgumentEntry.java @@ -31,6 +31,8 @@ import java.util.List; import java.util.Map; import java.util.TreeMap; +import static org.thingsboard.server.service.cf.ctx.state.BaseCalculatedFieldState.DEFAULT_LAST_UPDATE_TS; + @Data @NoArgsConstructor @AllArgsConstructor @@ -83,6 +85,11 @@ public class TsRollingArgumentEntry implements ArgumentEntry { return tsRecords; } + public long getLatestTs() { + var lastEntry = tsRecords.lastEntry(); + return (lastEntry != null) ? lastEntry.getKey() : DEFAULT_LAST_UPDATE_TS; + } + @Override public TbelCfArg toTbelCfArg() { List values = new ArrayList<>(tsRecords.size()); @@ -115,20 +122,11 @@ public class TsRollingArgumentEntry implements ArgumentEntry { } private void addTsRecord(Long ts, KvEntry value) { - try { - switch (value.getDataType()) { - case LONG -> value.getLongValue().ifPresent(aLong -> tsRecords.put(ts, aLong.doubleValue())); - case DOUBLE -> value.getDoubleValue().ifPresent(aDouble -> tsRecords.put(ts, aDouble)); - case BOOLEAN -> value.getBooleanValue().ifPresent(aBoolean -> tsRecords.put(ts, aBoolean ? 1.0 : 0.0)); - case STRING -> value.getStrValue().ifPresent(aString -> tsRecords.put(ts, Double.parseDouble(aString))); - case JSON -> value.getJsonValue().ifPresent(aString -> tsRecords.put(ts, Double.parseDouble(aString))); - } - } catch (Exception e) { - tsRecords.put(ts, Double.NaN); - log.debug("Invalid value '{}' for time series rolling arguments. Only numeric values are supported.", value.getValue()); - } finally { - cleanupExpiredRecords(); + Double recordValue = getValueForTsRecord(value); + if (recordValue != null) { + tsRecords.put(ts, recordValue); } + cleanupExpiredRecords(); } private void addTsRecord(Long ts, double value) { @@ -143,4 +141,19 @@ public class TsRollingArgumentEntry implements ArgumentEntry { tsRecords.entrySet().removeIf(tsRecord -> tsRecord.getKey() < System.currentTimeMillis() - timeWindow); } + public static Double getValueForTsRecord(KvEntry value) { + try { + return switch (value.getDataType()) { + case LONG -> value.getLongValue().map(Long::doubleValue).orElse(null); + case DOUBLE -> value.getDoubleValue().orElse(null); + case BOOLEAN -> value.getBooleanValue().map(b -> b ? 1.0 : 0.0).orElse(null); + case STRING -> value.getStrValue().map(Double::parseDouble).orElse(null); + case JSON -> value.getJsonValue().map(Double::parseDouble).orElse(null); + }; + } catch (Exception e) { + log.debug("Invalid value '{}' for time series rolling arguments. Only numeric values are supported.", value.getValue()); + return Double.NaN; + } + } + } diff --git a/application/src/main/java/org/thingsboard/server/service/device/DeviceBulkImportService.java b/application/src/main/java/org/thingsboard/server/service/device/DeviceBulkImportService.java index d042fb2657..c8925f9ee9 100644 --- a/application/src/main/java/org/thingsboard/server/service/device/DeviceBulkImportService.java +++ b/application/src/main/java/org/thingsboard/server/service/device/DeviceBulkImportService.java @@ -258,8 +258,7 @@ public class DeviceBulkImportService extends AbstractBulkImportService { Lwm2mDeviceProfileTransportConfiguration transportConfiguration = new Lwm2mDeviceProfileTransportConfiguration(); transportConfiguration.setBootstrap(Collections.emptyList()); - transportConfiguration.setClientLwM2mSettings(new OtherConfiguration(false,1, 1, 1, PowerMode.DRX, null, null, null, null, null, V1_0.toString())); - transportConfiguration.setObserveAttr(new TelemetryMappingConfiguration(Collections.emptyMap(), Collections.emptySet(), Collections.emptySet(), Collections.emptySet(), Collections.emptyMap(), SINGLE)); + transportConfiguration.setClientLwM2mSettings(new OtherConfiguration()); DeviceProfileData deviceProfileData = new DeviceProfileData(); DefaultDeviceProfileConfiguration configuration = new DefaultDeviceProfileConfiguration(); diff --git a/application/src/main/java/org/thingsboard/server/service/device/DeviceProvisionServiceImpl.java b/application/src/main/java/org/thingsboard/server/service/device/DeviceProvisionServiceImpl.java index 0778d61ee7..ffd16c1287 100644 --- a/application/src/main/java/org/thingsboard/server/service/device/DeviceProvisionServiceImpl.java +++ b/application/src/main/java/org/thingsboard/server/service/device/DeviceProvisionServiceImpl.java @@ -186,9 +186,14 @@ public class DeviceProvisionServiceImpl implements DeviceProvisionService { try { Optional provisionState = attributesService.find(device.getTenantId(), device.getId(), AttributeScope.SERVER_SCOPE, DEVICE_PROVISION_STATE).get(); - if (provisionState != null && provisionState.isPresent() && !provisionState.get().getValueAsString().equals(PROVISIONED_STATE)) { - notify(device, provisionRequest, TbMsgType.PROVISION_FAILURE, false); - throw new ProvisionFailedException(ProvisionResponseStatus.FAILURE.name()); + if (provisionState != null && provisionState.isPresent()) { + if (provisionState.get().getValueAsString().equals(PROVISIONED_STATE)) { + notify(device, provisionRequest, TbMsgType.PROVISION_FAILURE, false); + throw new ProvisionFailedException(ProvisionResponseStatus.FAILURE.name()); + } else { + log.error("[{}][{}] Unknown provision state: {}!", device.getName(), DEVICE_PROVISION_STATE, provisionState.get().getValueAsString()); + throw new ProvisionFailedException(ProvisionResponseStatus.FAILURE.name()); + } } else { saveProvisionStateAttribute(device).get(); notify(device, provisionRequest, TbMsgType.PROVISION_SUCCESS, true); diff --git a/application/src/main/java/org/thingsboard/server/service/edge/instructions/BaseEdgeInstallUpgradeInstructionsService.java b/application/src/main/java/org/thingsboard/server/service/edge/instructions/BaseEdgeInstallUpgradeInstructionsService.java index e8910492a3..abce90c253 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/instructions/BaseEdgeInstallUpgradeInstructionsService.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/instructions/BaseEdgeInstallUpgradeInstructionsService.java @@ -18,7 +18,6 @@ package org.thingsboard.server.service.edge.instructions; import lombok.RequiredArgsConstructor; import lombok.Setter; import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.annotation.Value; import org.thingsboard.server.service.install.InstallScripts; import java.io.IOException; @@ -26,6 +25,8 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; +import static org.thingsboard.edge.rpc.EdgeGrpcClient.getNewestEdgeVersion; + @Slf4j @RequiredArgsConstructor public abstract class BaseEdgeInstallUpgradeInstructionsService { @@ -35,9 +36,12 @@ public abstract class BaseEdgeInstallUpgradeInstructionsService { private final InstallScripts installScripts; - @Value("${app.version:unknown}") @Setter - protected String appVersion; + protected String platformEdgeVersion = convertEdgeVersionToDocsFormat(getNewestEdgeVersion().name()); + + protected String convertEdgeVersionToDocsFormat(String edgeVersion) { + return edgeVersion.replace("_", ".").substring(2); + } protected String readFile(Path file) { try { diff --git a/application/src/main/java/org/thingsboard/server/service/edge/instructions/DefaultEdgeInstallInstructionsService.java b/application/src/main/java/org/thingsboard/server/service/edge/instructions/DefaultEdgeInstallInstructionsService.java index e16a8be5b5..ce37bba290 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/instructions/DefaultEdgeInstallInstructionsService.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/instructions/DefaultEdgeInstallInstructionsService.java @@ -65,9 +65,7 @@ public class DefaultEdgeInstallInstructionsService extends BaseEdgeInstallUpgrad dockerInstallInstructions = dockerInstallInstructions.replace("${EXTRA_HOSTS}", ""); dockerInstallInstructions = dockerInstallInstructions.replace("${BASE_URL}", baseUrl); } - String edgeVersion = appVersion + "EDGE"; - edgeVersion = edgeVersion.replace("-SNAPSHOT", ""); - dockerInstallInstructions = dockerInstallInstructions.replace("${TB_EDGE_VERSION}", edgeVersion); + dockerInstallInstructions = dockerInstallInstructions.replace("${TB_EDGE_VERSION}", platformEdgeVersion + "EDGE"); dockerInstallInstructions = replacePlaceholders(dockerInstallInstructions, edge); return new EdgeInstructions(dockerInstallInstructions); } @@ -76,9 +74,8 @@ public class DefaultEdgeInstallInstructionsService extends BaseEdgeInstallUpgrad String ubuntuInstallInstructions = readFile(resolveFile(os, "instructions.md")); ubuntuInstallInstructions = replacePlaceholders(ubuntuInstallInstructions, edge); ubuntuInstallInstructions = ubuntuInstallInstructions.replace("${BASE_URL}", request.getServerName()); - String edgeVersion = appVersion.replace("-SNAPSHOT", ""); - ubuntuInstallInstructions = ubuntuInstallInstructions.replace("${TB_EDGE_VERSION}", edgeVersion); - ubuntuInstallInstructions = ubuntuInstallInstructions.replace("${TB_EDGE_TAG}", getTagVersion(edgeVersion)); + ubuntuInstallInstructions = ubuntuInstallInstructions.replace("${TB_EDGE_VERSION}", platformEdgeVersion); + ubuntuInstallInstructions = ubuntuInstallInstructions.replace("${TB_EDGE_TAG}", getTagVersion(platformEdgeVersion)); return new EdgeInstructions(ubuntuInstallInstructions); } diff --git a/application/src/main/java/org/thingsboard/server/service/edge/instructions/DefaultEdgeUpgradeInstructionsService.java b/application/src/main/java/org/thingsboard/server/service/edge/instructions/DefaultEdgeUpgradeInstructionsService.java index 2df75d603b..8855e78683 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/instructions/DefaultEdgeUpgradeInstructionsService.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/instructions/DefaultEdgeUpgradeInstructionsService.java @@ -52,12 +52,11 @@ public class DefaultEdgeUpgradeInstructionsService extends BaseEdgeInstallUpgrad @Override public EdgeInstructions getUpgradeInstructions(String edgeVersion, String upgradeMethod) { - String tbVersion = appVersion.replace("-SNAPSHOT", ""); String currentEdgeVersion = convertEdgeVersionToDocsFormat(edgeVersion); return switch (upgradeMethod.toLowerCase()) { - case "docker" -> getDockerUpgradeInstructions(tbVersion, currentEdgeVersion); + case "docker" -> getDockerUpgradeInstructions(this.platformEdgeVersion, currentEdgeVersion); case "ubuntu", "centos" -> - getLinuxUpgradeInstructions(tbVersion, currentEdgeVersion, upgradeMethod.toLowerCase()); + getLinuxUpgradeInstructions(this.platformEdgeVersion, currentEdgeVersion, upgradeMethod.toLowerCase()); default -> throw new IllegalArgumentException("Unsupported upgrade method for Edge: " + upgradeMethod); }; } @@ -74,8 +73,7 @@ public class DefaultEdgeUpgradeInstructionsService extends BaseEdgeInstallUpgrad Optional attributeKvEntryOpt = attributesService.find(tenantId, edgeId, AttributeScope.SERVER_SCOPE, DataConstants.EDGE_VERSION_ATTR_KEY).get(); if (attributeKvEntryOpt.isPresent()) { String edgeVersionFormatted = convertEdgeVersionToDocsFormat(attributeKvEntryOpt.get().getValueAsString()); - String appVersionFormatted = appVersion.replace("-SNAPSHOT", ""); - return isVersionGreaterOrEqualsThan(edgeVersionFormatted, "3.6.0") && !isVersionGreaterOrEqualsThan(edgeVersionFormatted, appVersionFormatted); + return isVersionGreaterOrEqualsThan(edgeVersionFormatted, "3.6.0") && !isVersionGreaterOrEqualsThan(edgeVersionFormatted, platformEdgeVersion); } return false; } @@ -98,13 +96,13 @@ public class DefaultEdgeUpgradeInstructionsService extends BaseEdgeInstallUpgrad return true; } - private EdgeInstructions getDockerUpgradeInstructions(String tbVersion, String currentEdgeVersion) { + private EdgeInstructions getDockerUpgradeInstructions(String platformEdgeVersion, String currentEdgeVersion) { EdgeUpgradeInfo edgeUpgradeInfo = upgradeVersionHashMap.get(currentEdgeVersion); - if (edgeUpgradeInfo == null || edgeUpgradeInfo.getNextEdgeVersion() == null || tbVersion.equals(currentEdgeVersion)) { + if (edgeUpgradeInfo == null || edgeUpgradeInfo.getNextEdgeVersion() == null || platformEdgeVersion.equals(currentEdgeVersion)) { return new EdgeInstructions("Edge upgrade instruction for " + currentEdgeVersion + "EDGE is not available."); } StringBuilder result = new StringBuilder(readFile(resolveFile("docker", "upgrade_preparing.md"))); - while (edgeUpgradeInfo.getNextEdgeVersion() != null && !tbVersion.equals(currentEdgeVersion)) { + while (edgeUpgradeInfo.getNextEdgeVersion() != null && !platformEdgeVersion.equals(currentEdgeVersion)) { String edgeVersion = edgeUpgradeInfo.getNextEdgeVersion(); String dockerUpgradeInstructions = readFile(resolveFile("docker", "instructions.md")); if (edgeUpgradeInfo.isRequiresUpdateDb()) { @@ -125,15 +123,15 @@ public class DefaultEdgeUpgradeInstructionsService extends BaseEdgeInstallUpgrad return new EdgeInstructions(result.toString()); } - private EdgeInstructions getLinuxUpgradeInstructions(String tbVersion, String currentEdgeVersion, String os) { + private EdgeInstructions getLinuxUpgradeInstructions(String platformEdgeVersion, String currentEdgeVersion, String os) { EdgeUpgradeInfo edgeUpgradeInfo = upgradeVersionHashMap.get(currentEdgeVersion); - if (edgeUpgradeInfo == null || edgeUpgradeInfo.getNextEdgeVersion() == null || tbVersion.equals(currentEdgeVersion)) { + if (edgeUpgradeInfo == null || edgeUpgradeInfo.getNextEdgeVersion() == null || platformEdgeVersion.equals(currentEdgeVersion)) { return new EdgeInstructions("Edge upgrade instruction for " + currentEdgeVersion + "EDGE is not available."); } String upgrade_preparing = readFile(resolveFile("upgrade_preparing.md")); upgrade_preparing = upgrade_preparing.replace("${OS}", os.equals("centos") ? "RHEL/CentOS 7/8" : "Ubuntu"); StringBuilder result = new StringBuilder(upgrade_preparing); - while (edgeUpgradeInfo.getNextEdgeVersion() != null && !tbVersion.equals(currentEdgeVersion)) { + while (edgeUpgradeInfo.getNextEdgeVersion() != null && !platformEdgeVersion.equals(currentEdgeVersion)) { String edgeVersion = edgeUpgradeInfo.getNextEdgeVersion(); String linuxUpgradeInstructions = readFile(resolveFile(os, "instructions.md")); if (edgeUpgradeInfo.isRequiresUpdateDb()) { @@ -155,10 +153,6 @@ public class DefaultEdgeUpgradeInstructionsService extends BaseEdgeInstallUpgrad return new EdgeInstructions(result.toString()); } - private String convertEdgeVersionToDocsFormat(String edgeVersion) { - return edgeVersion.replace("_", ".").substring(2); - } - @Override protected String getBaseDirName() { return UPGRADE_DIR; diff --git a/application/src/main/java/org/thingsboard/server/service/edge/instructions/EdgeInstallInstructionsService.java b/application/src/main/java/org/thingsboard/server/service/edge/instructions/EdgeInstallInstructionsService.java index d1719422ce..c2f2d51a2a 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/instructions/EdgeInstallInstructionsService.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/instructions/EdgeInstallInstructionsService.java @@ -23,6 +23,6 @@ public interface EdgeInstallInstructionsService { EdgeInstructions getInstallInstructions(Edge edge, String installationMethod, HttpServletRequest request); - void setAppVersion(String version); + void setPlatformEdgeVersion(String version); } diff --git a/application/src/main/java/org/thingsboard/server/service/edge/instructions/EdgeUpgradeInstructionsService.java b/application/src/main/java/org/thingsboard/server/service/edge/instructions/EdgeUpgradeInstructionsService.java index 9ae68ab2d0..83a8da281d 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/instructions/EdgeUpgradeInstructionsService.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/instructions/EdgeUpgradeInstructionsService.java @@ -28,7 +28,7 @@ public interface EdgeUpgradeInstructionsService { void updateInstructionMap(Map upgradeVersions); - void setAppVersion(String version); + void setPlatformEdgeVersion(String version); boolean isUpgradeAvailable(TenantId tenantId, EdgeId edgeId) throws Exception; diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeGrpcService.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeGrpcService.java index ec3f839cb3..c8b2c564ff 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeGrpcService.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeGrpcService.java @@ -69,6 +69,7 @@ import org.thingsboard.server.service.telemetry.TelemetrySubscriptionService; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; +import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -82,6 +83,7 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; import java.util.function.Consumer; +import java.util.function.Function; import static org.thingsboard.server.service.state.DefaultDeviceStateService.ACTIVITY_STATE; import static org.thingsboard.server.service.state.DefaultDeviceStateService.LAST_CONNECT_TIME; @@ -94,6 +96,7 @@ import static org.thingsboard.server.service.state.DefaultDeviceStateService.LAS public class EdgeGrpcService extends EdgeRpcServiceGrpc.EdgeRpcServiceImplBase implements EdgeRpcService { private final ConcurrentMap sessions = new ConcurrentHashMap<>(); + private final ConcurrentMap sessionsById = new ConcurrentHashMap<>(); private final ConcurrentMap sessionNewEventsLocks = new ConcurrentHashMap<>(); private final Map sessionNewEvents = new HashMap<>(); private final ConcurrentMap> sessionEdgeEventChecks = new ConcurrentHashMap<>(); @@ -283,6 +286,7 @@ public class EdgeGrpcService extends EdgeRpcServiceGrpc.EdgeRpcServiceImplBase i destroySession(session); session.cleanUp(); sessions.remove(edgeId); + sessionsById.remove(session.getSessionId()); final Lock newEventLock = sessionNewEventsLocks.computeIfAbsent(edgeId, id -> new ReentrantLock()); newEventLock.lock(); try { @@ -332,9 +336,15 @@ public class EdgeGrpcService extends EdgeRpcServiceGrpc.EdgeRpcServiceImplBase i TenantId tenantId = edge.getTenantId(); log.info("[{}][{}] edge [{}] connected successfully.", tenantId, edgeGrpcSession.getSessionId(), edgeId); if (sessions.containsKey(edgeId)) { - destroySession(sessions.get(edgeId)); + EdgeGrpcSession existing = sessions.get(edgeId); + if (existing != null) { + log.info("[{}][{}] Replacing existing session [{}] for edge [{}]", tenantId, edgeGrpcSession.getSessionId(), existing.getSessionId(), edgeId); + destroySession(existing); + sessionsById.remove(existing.getSessionId()); + } } sessions.put(edgeId, edgeGrpcSession); + sessionsById.put(edgeGrpcSession.getSessionId(), edgeGrpcSession); final Lock newEventLock = sessionNewEventsLocks.computeIfAbsent(edgeId, id -> new ReentrantLock()); newEventLock.lock(); try { @@ -492,9 +502,9 @@ public class EdgeGrpcService extends EdgeRpcServiceGrpc.EdgeRpcServiceImplBase i private void onEdgeDisconnect(Edge edge, UUID sessionId) { EdgeId edgeId = edge.getId(); log.info("[{}][{}] edge disconnected!", edgeId, sessionId); - EdgeGrpcSession toRemove = sessions.get(edgeId); - if (toRemove.getSessionId().equals(sessionId)) { - toRemove = sessions.remove(edgeId); + EdgeGrpcSession current = sessions.get(edgeId); + if (current != null && current.getSessionId().equals(sessionId)) { + EdgeGrpcSession toRemove = sessions.remove(edgeId); final Lock newEventLock = sessionNewEventsLocks.computeIfAbsent(edgeId, id -> new ReentrantLock()); newEventLock.lock(); try { @@ -503,6 +513,7 @@ public class EdgeGrpcService extends EdgeRpcServiceGrpc.EdgeRpcServiceImplBase i newEventLock.unlock(); } destroySession(toRemove); + sessionsById.remove(sessionId); TenantId tenantId = toRemove.getEdge().getTenantId(); save(tenantId, edgeId, ACTIVITY_STATE, false); long lastDisconnectTs = System.currentTimeMillis(); @@ -510,7 +521,18 @@ public class EdgeGrpcService extends EdgeRpcServiceGrpc.EdgeRpcServiceImplBase i pushRuleEngineMessage(toRemove.getEdge().getTenantId(), edge, lastDisconnectTs, TbMsgType.DISCONNECT_EVENT); cancelScheduleEdgeEventsCheck(edgeId); } else { - log.debug("[{}] edge session [{}] is not available anymore, nothing to remove. most probably this session is already outdated!", edgeId, sessionId); + log.info("[{}] edge session [{}] is not current anymore. Attempting to destroy it by sessionId.", edgeId, sessionId); + EdgeGrpcSession stale = sessionsById.remove(sessionId); + if (stale != null) { + try { + destroySession(stale); + log.info("[{}][{}] Successfully destroyed stale session for edge [{}]", stale.getTenantId(), sessionId, edgeId); + } catch (Exception e) { + log.warn("[{}][{}] Failed to destroy stale session for edge [{}]", stale.getTenantId(), sessionId, edgeId, e); + } + } else { + log.debug("[{}] No session found by sessionId [{}] to destroy", edgeId, sessionId); + } } edgeIdServiceIdCache.evict(edgeId); } @@ -522,6 +544,9 @@ public class EdgeGrpcService extends EdgeRpcServiceGrpc.EdgeRpcServiceImplBase i session.getTenantId(), session.getEdge().getId(), session.getEdge().getName(), session.getSessionId()); zombieSessions.add(session); } + } catch (Exception e) { + log.warn("[{}][{}] Exception during session destroy for edge [{}] with session id [{}]", + session.getTenantId(), session.getEdge().getId(), session.getEdge().getName(), session.getSessionId(), e); } } @@ -631,25 +656,9 @@ public class EdgeGrpcService extends EdgeRpcServiceGrpc.EdgeRpcServiceImplBase i private void cleanupZombieSessions() { try { - List toRemove = new ArrayList<>(); - for (EdgeGrpcSession session : sessions.values()) { - if (session instanceof KafkaEdgeGrpcSession kafkaSession && - !kafkaSession.isConnected() && - kafkaSession.getConsumer() != null && - kafkaSession.getConsumer().getConsumer() != null && - !kafkaSession.getConsumer().getConsumer().isStopped()) { - toRemove.add(kafkaSession.getEdge().getId()); - } - } - for (EdgeId edgeId : toRemove) { - log.info("[{}] Destroying session for edge because edge is not connected", edgeId); - EdgeGrpcSession removed = sessions.get(edgeId); - if (removed instanceof KafkaEdgeGrpcSession kafkaSession) { - if (kafkaSession.destroy()) { - sessions.remove(edgeId); - } - } - } + tryToDestroyZombieSessions(getZombieSessions(sessions.values()), s -> sessions.remove(s.getEdge().getId())); + tryToDestroyZombieSessions(getZombieSessions(sessionsById.values()), s -> sessionsById.remove(s.getSessionId())); + zombieSessions.removeIf(zombie -> { if (zombie.destroy()) { log.info("[{}][{}] Successfully cleaned up zombie session [{}] for edge [{}].", @@ -666,4 +675,38 @@ public class EdgeGrpcService extends EdgeRpcServiceGrpc.EdgeRpcServiceImplBase i } } + private List getZombieSessions(Collection sessions) { + List result = new ArrayList<>(); + for (EdgeGrpcSession session : sessions) { + if (isKafkaSessionAndZombie(session)) { + result.add(session); + } + } + return result; + } + + private void tryToDestroyZombieSessions(List sessionsToRemove, Function removeFunc) { + for (EdgeGrpcSession toRemove : sessionsToRemove) { + log.info("[{}] Destroying session for edge because edge is not connected", toRemove.getEdge().getId()); + if (toRemove.destroy()) { + removeFunc.apply(toRemove); + } + } + } + + private boolean isKafkaSessionAndZombie(EdgeGrpcSession session) { + if (session instanceof KafkaEdgeGrpcSession kafkaSession) { + log.debug("[{}] kafkaSession.isConnected() = {}, kafkaSession.getConsumer().getConsumer().isStopped() = {}", + kafkaSession.getEdge().getId(), + kafkaSession.isConnected(), + kafkaSession.getConsumer() != null ? kafkaSession.getConsumer().getConsumer() != null ? kafkaSession.getConsumer().getConsumer().isStopped() : null : null); + return !kafkaSession.isConnected() && + kafkaSession.getConsumer() != null && + kafkaSession.getConsumer().getConsumer() != null && + !kafkaSession.getConsumer().getConsumer().isStopped(); + } + return false; + + } + } diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeGrpcSession.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeGrpcSession.java index 521730741f..c7c27ae4d0 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeGrpcSession.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeGrpcSession.java @@ -113,7 +113,7 @@ public abstract class EdgeGrpcSession implements Closeable { private static final int MAX_DOWNLINK_ATTEMPTS = 3; private static final String RATE_LIMIT_REACHED = "Rate limit reached"; - protected static final ConcurrentLinkedQueue highPriorityQueue = new ConcurrentLinkedQueue<>(); + protected final ConcurrentLinkedQueue highPriorityQueue = new ConcurrentLinkedQueue<>(); protected UUID sessionId; private BiConsumer sessionOpenListener; diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/KafkaEdgeGrpcSession.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/KafkaEdgeGrpcSession.java index d165be33d4..e6eaec23e4 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/KafkaEdgeGrpcSession.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/KafkaEdgeGrpcSession.java @@ -82,16 +82,18 @@ public class KafkaEdgeGrpcSession extends EdgeGrpcSession { edgeEvents.add(edgeEvent); } List downlinkMsgsPack = convertToDownlinkMsgsPack(edgeEvents); + boolean isInterrupted = true; try { - boolean isInterrupted = sendDownlinkMsgsPack(downlinkMsgsPack).get(); + isInterrupted = sendDownlinkMsgsPack(downlinkMsgsPack).get(); if (isInterrupted) { log.debug("[{}][{}] Send downlink messages task was interrupted", tenantId, edge.getId()); - } else { - consumer.commit(); } } catch (Exception e) { log.error("[{}][{}] Failed to process downlink messages", tenantId, edge.getId(), e); } + if (!isInterrupted) { + consumer.commit(); + } } @Override @@ -101,8 +103,21 @@ public class KafkaEdgeGrpcSession extends EdgeGrpcSession { @Override public ListenableFuture processEdgeEvents() { + if (!isConnected() || isSyncInProgress() || isHighPriorityProcessing) { + log.warn("[{}][{}] Session is not ready (connected={}, syncInProgress={}, highPriority={}), skip starting edge event consumer", + tenantId, edge != null ? edge.getId() : null, isConnected(), isSyncInProgress(), isHighPriorityProcessing); + return Futures.immediateFuture(Boolean.FALSE); + } if (consumer == null || (consumer.getConsumer() != null && consumer.getConsumer().isStopped())) { try { + if (consumerExecutor != null && !consumerExecutor.isShutdown()) { + try { + consumerExecutor.shutdown(); + awaitConsumerTermination(); + } catch (Exception e) { + log.warn("[{}][{}] Failed to shutdown previous consumer executor", tenantId, edge.getId(), e); + } + } this.consumerExecutor = Executors.newSingleThreadExecutor(ThingsBoardThreadFactory.forName("edge-event-consumer")); this.consumer = QueueConsumerManager.>builder() .name("TB Edge events [" + edge.getId() + "]") @@ -133,6 +148,7 @@ public class KafkaEdgeGrpcSession extends EdgeGrpcSession { public boolean destroy() { try { if (consumer != null) { + log.info("[{}][{}] Stopping edge event consumer...", tenantId, edge != null ? edge.getId() : null); consumer.stop(); } } catch (Exception e) { @@ -141,16 +157,25 @@ public class KafkaEdgeGrpcSession extends EdgeGrpcSession { } consumer = null; try { - if (consumerExecutor != null) { + if (consumerExecutor != null && !consumerExecutor.isShutdown()) { consumerExecutor.shutdown(); + awaitConsumerTermination(); } } catch (Exception e) { - log.warn("[{}][{}] Failed to shutdown consumer executor", tenantId, edge.getId(), e); + log.warn("[{}][{}] Failed to shutdown edge event consumer executor", tenantId, edge.getId(), e); return false; } return true; } + private void awaitConsumerTermination() { + try { + consumerExecutor.awaitTermination(5, java.util.concurrent.TimeUnit.SECONDS); + } catch (InterruptedException ie) { + log.warn("[{}][{}] Interrupted while awaiting consumer executor termination", tenantId, edge.getId()); + } + } + @Override public void cleanUp() { String topic = topicService.buildEdgeEventNotificationsTopicPartitionInfo(tenantId, edge.getId()).getTopic(); diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/dashboard/BaseDashboardProcessor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/dashboard/BaseDashboardProcessor.java index 56efb9157e..a1ac38138b 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/dashboard/BaseDashboardProcessor.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/dashboard/BaseDashboardProcessor.java @@ -63,12 +63,12 @@ public abstract class BaseDashboardProcessor extends BaseEdgeProcessor { Dashboard savedDashboard = edgeCtx.getDashboardService().saveDashboard(dashboard, false); - updateDashboardAssignments(tenantId, dashboardById, savedDashboard, newAssignedCustomers); + updateDashboardAssignments(tenantId, customerId, dashboardById, savedDashboard, newAssignedCustomers); return created; } - private void updateDashboardAssignments(TenantId tenantId, Dashboard dashboardById, Dashboard savedDashboard, Set newAssignedCustomers) { + private void updateDashboardAssignments(TenantId tenantId, CustomerId edgeCustomerId, Dashboard dashboardById, Dashboard savedDashboard, Set newAssignedCustomers) { Set currentAssignedCustomers = new HashSet<>(); if (dashboardById != null) { if (dashboardById.getAssignedCustomers() != null) { @@ -76,7 +76,7 @@ public abstract class BaseDashboardProcessor extends BaseEdgeProcessor { } } - newAssignedCustomers = filterNonExistingCustomers(tenantId, currentAssignedCustomers, newAssignedCustomers); + newAssignedCustomers = filterNonExistingCustomers(tenantId, edgeCustomerId, currentAssignedCustomers, newAssignedCustomers); Set addedCustomerIds = new HashSet<>(); Set removedCustomerIds = new HashSet<>(); @@ -100,6 +100,6 @@ public abstract class BaseDashboardProcessor extends BaseEdgeProcessor { } } - protected abstract Set filterNonExistingCustomers(TenantId tenantId, Set currentAssignedCustomers, Set newAssignedCustomers); + protected abstract Set filterNonExistingCustomers(TenantId tenantId, CustomerId customerId, Set currentAssignedCustomers, Set newAssignedCustomers); } diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/dashboard/DashboardEdgeProcessor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/dashboard/DashboardEdgeProcessor.java index e1259a7e0e..d517b53303 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/dashboard/DashboardEdgeProcessor.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/dashboard/DashboardEdgeProcessor.java @@ -26,6 +26,7 @@ import org.thingsboard.server.common.data.ShortCustomerInfo; import org.thingsboard.server.common.data.edge.Edge; import org.thingsboard.server.common.data.edge.EdgeEvent; import org.thingsboard.server.common.data.edge.EdgeEventType; +import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.DashboardId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.msg.TbMsgType; @@ -38,8 +39,10 @@ import org.thingsboard.server.gen.edge.v1.UpdateMsgType; import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.service.edge.EdgeMsgConstructorUtils; +import java.util.HashSet; import java.util.Set; import java.util.UUID; +import java.util.stream.Collectors; @Slf4j @Component @@ -127,14 +130,24 @@ public class DashboardEdgeProcessor extends BaseDashboardProcessor implements Da } @Override - protected Set filterNonExistingCustomers(TenantId tenantId, Set currentAssignedCustomers, Set newAssignedCustomers) { - newAssignedCustomers.addAll(currentAssignedCustomers); - return newAssignedCustomers; + protected Set filterNonExistingCustomers(TenantId tenantId, CustomerId edgeCustomerId, Set currentAssignedCustomers, Set newAssignedCustomers) { + boolean edgeCustomerPresentInNewAssignments = newAssignedCustomers.stream() + .map(ShortCustomerInfo::getCustomerId) + .anyMatch(edgeCustomerId::equals); + + if (edgeCustomerPresentInNewAssignments) { + Set result = new HashSet<>(newAssignedCustomers); + result.addAll(currentAssignedCustomers); + return result; + } else { + return currentAssignedCustomers.stream() + .filter(info -> !edgeCustomerId.equals(info.getCustomerId())) + .collect(Collectors.toSet()); + } } @Override public EdgeEventType getEdgeEventType() { return EdgeEventType.DASHBOARD; } - } diff --git a/application/src/main/java/org/thingsboard/server/service/install/DefaultDatabaseSchemaSettingsService.java b/application/src/main/java/org/thingsboard/server/service/install/DefaultDatabaseSchemaSettingsService.java index f41a530630..44aa14b782 100644 --- a/application/src/main/java/org/thingsboard/server/service/install/DefaultDatabaseSchemaSettingsService.java +++ b/application/src/main/java/org/thingsboard/server/service/install/DefaultDatabaseSchemaSettingsService.java @@ -17,7 +17,6 @@ package org.thingsboard.server.service.install; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.springframework.context.annotation.Profile; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Service; import org.thingsboard.server.service.install.update.DefaultDataUpdateService; @@ -25,14 +24,13 @@ import org.thingsboard.server.service.install.update.DefaultDataUpdateService; import java.util.List; @Service -@Profile("install") @Slf4j @RequiredArgsConstructor public class DefaultDatabaseSchemaSettingsService implements DatabaseSchemaSettingsService { - // This list should include all versions which are compatible for the upgrade. - // The compatibility cycle usually breaks when we have some scripts written in Java that may not work after new release. - private static final List SUPPORTED_VERSIONS_FOR_UPGRADE = List.of("4.2.0"); + // This list should include all versions that are compatible for the upgrade in 4 digits format (like 4.2.0.0, etc.). + // The compatibility cycle usually breaks when we have some scripts written in Java that may not work after a new release. + private static final List SUPPORTED_VERSIONS_FOR_UPGRADE = List.of("4.2.0.0", "4.2.1.0"); private final ProjectInfo projectInfo; private final JdbcTemplate jdbcTemplate; @@ -80,7 +78,7 @@ public class DefaultDatabaseSchemaSettingsService implements DatabaseSchemaSetti @Override public String getPackageSchemaVersion() { if (packageSchemaVersion == null) { - packageSchemaVersion = projectInfo.getProjectVersion(); + packageSchemaVersion = normalizeVersion(projectInfo.getProjectVersion()); } return packageSchemaVersion; } @@ -88,17 +86,28 @@ public class DefaultDatabaseSchemaSettingsService implements DatabaseSchemaSetti @Override public String getDbSchemaVersion() { if (schemaVersionFromDb == null) { - Long version = getSchemaVersionFromDb(); - if (version == null) { + Long dbVersion = getSchemaVersionFromDb(); + if (dbVersion == null) { onSchemaSettingsError("Upgrade failed: the database schema version is missing."); } @SuppressWarnings("DataFlowIssue") - long major = version / 1000000; - long minor = (version % 1000000) / 1000; - long patch = version % 1000; - - schemaVersionFromDb = major + "." + minor + "." + patch; + long version = dbVersion; + + if (version < 1_000_000_000) { + // Old format: MMM mmm ppp (e.g., 4002001 = 4.2.1) + long major = version / 1_000_000; + long minor = (version % 1_000_000) / 1000; + long maintenance = version % 1000; + schemaVersionFromDb = major + "." + minor + "." + maintenance + ".0"; + } else { + // New format: MMM mmm mmm ppp (e.g., 4002001001 = 4.2.1.1) + long major = version / 1_000_000_000; + long minor = (version % 1_000_000_000) / 1_000_000; + long maintenance = (version % 1_000_000) / 1000; + long patch = version % 1000; + schemaVersionFromDb = major + "." + minor + "." + maintenance + "." + patch; + } } return schemaVersionFromDb; } @@ -116,13 +125,26 @@ public class DefaultDatabaseSchemaSettingsService implements DatabaseSchemaSetti long major = Integer.parseInt(versionParts[0]); long minor = Integer.parseInt(versionParts[1]); - long patch = versionParts.length > 2 ? Integer.parseInt(versionParts[2]) : 0; + long maintenance = Integer.parseInt(versionParts[2]); + long patch = Integer.parseInt(versionParts[3]); - return major * 1000000 + minor * 1000 + patch; + return major * 1_000_000_000L + minor * 1_000_000L + maintenance * 1000L + patch; } private void onSchemaSettingsError(String message) { Runtime.getRuntime().addShutdownHook(new Thread(() -> log.error(message))); throw new RuntimeException(message); } + + private String normalizeVersion(String version) { + String[] parts = version.split("\\."); + + int major = Integer.parseInt(parts[0]); + int minor = parts.length > 1 ? Integer.parseInt(parts[1]) : 0; + int maintenance = parts.length > 2 ? Integer.parseInt(parts[2]) : 0; + int patch = parts.length > 3 ? Integer.parseInt(parts[3]) : 0; + + return major + "." + minor + "." + maintenance + "." + patch; + } + } diff --git a/application/src/main/java/org/thingsboard/server/service/install/InstallScripts.java b/application/src/main/java/org/thingsboard/server/service/install/InstallScripts.java index 4e44517ca0..f9b5c282a8 100644 --- a/application/src/main/java/org/thingsboard/server/service/install/InstallScripts.java +++ b/application/src/main/java/org/thingsboard/server/service/install/InstallScripts.java @@ -65,9 +65,6 @@ import java.util.stream.Stream; import static org.thingsboard.server.utils.LwM2mObjectModelUtils.toLwm2mResource; -/** - * Created by ashvayka on 18.04.18. - */ @Component @Slf4j public class InstallScripts { @@ -134,6 +131,10 @@ public class InstallScripts { return Paths.get(getDataDir(), JSON_DIR, EDGE_DIR, RULE_CHAINS_DIR); } + public Path getWidgetTypesDir() { + return Paths.get(getDataDir(), JSON_DIR, SYSTEM_DIR, WIDGET_TYPES_DIR); + } + public String getDataDir() { if (!StringUtils.isEmpty(dataDir)) { if (!Paths.get(this.dataDir).toFile().isDirectory()) { @@ -237,7 +238,7 @@ public class InstallScripts { } ); } - Path widgetTypesDir = Paths.get(getDataDir(), JSON_DIR, SYSTEM_DIR, WIDGET_TYPES_DIR); + Path widgetTypesDir = getWidgetTypesDir(); if (Files.exists(widgetTypesDir)) { try (Stream dirStream = listDir(widgetTypesDir).filter(path -> path.toString().endsWith(JSON_EXT))) { dirStream.forEach( diff --git a/application/src/main/java/org/thingsboard/server/service/install/SqlEntityDatabaseSchemaService.java b/application/src/main/java/org/thingsboard/server/service/install/SqlEntityDatabaseSchemaService.java index aa43d77439..a773d0ab23 100644 --- a/application/src/main/java/org/thingsboard/server/service/install/SqlEntityDatabaseSchemaService.java +++ b/application/src/main/java/org/thingsboard/server/service/install/SqlEntityDatabaseSchemaService.java @@ -22,12 +22,13 @@ import org.springframework.stereotype.Service; @Service @Profile("install") @Slf4j -public class SqlEntityDatabaseSchemaService extends SqlAbstractDatabaseSchemaService - implements EntityDatabaseSchemaService { +public class SqlEntityDatabaseSchemaService extends SqlAbstractDatabaseSchemaService implements EntityDatabaseSchemaService { + public static final String SCHEMA_ENTITIES_SQL = "schema-entities.sql"; public static final String SCHEMA_ENTITIES_IDX_SQL = "schema-entities-idx.sql"; public static final String SCHEMA_ENTITIES_IDX_PSQL_ADDON_SQL = "schema-entities-idx-psql-addon.sql"; - public static final String SCHEMA_VIEWS_AND_FUNCTIONS_SQL = "schema-views-and-functions.sql"; + public static final String SCHEMA_VIEWS_SQL = "schema-views.sql"; + public static final String SCHEMA_FUNCTIONS_SQL = "schema-functions.sql"; public SqlEntityDatabaseSchemaService() { super(SCHEMA_ENTITIES_SQL, SCHEMA_ENTITIES_IDX_SQL); @@ -49,8 +50,10 @@ public class SqlEntityDatabaseSchemaService extends SqlAbstractDatabaseSchemaSer @Override public void createOrUpdateViewsAndFunctions() throws Exception { - log.info("Installing SQL DataBase schema views and functions: " + SCHEMA_VIEWS_AND_FUNCTIONS_SQL); - executeQueryFromFile(SCHEMA_VIEWS_AND_FUNCTIONS_SQL); + log.info("Installing SQL DataBase schema views: " + SCHEMA_VIEWS_SQL); + executeQueryFromFile(SCHEMA_VIEWS_SQL); + log.info("Installing SQL DataBase schema functions: " + SCHEMA_FUNCTIONS_SQL); + executeQueryFromFile(SCHEMA_FUNCTIONS_SQL); } } diff --git a/application/src/main/java/org/thingsboard/server/service/ota/DefaultOtaPackageStateService.java b/application/src/main/java/org/thingsboard/server/service/ota/DefaultOtaPackageStateService.java index 4d9e145711..0b4d3bec6f 100644 --- a/application/src/main/java/org/thingsboard/server/service/ota/DefaultOtaPackageStateService.java +++ b/application/src/main/java/org/thingsboard/server/service/ota/DefaultOtaPackageStateService.java @@ -328,7 +328,7 @@ public class DefaultOtaPackageStateService implements OtaPackageStateService { attributes.add(new BaseAttributeKvEntry(ts, new LongDataEntry(getAttributeKey(otaPackageType, SIZE), otaPackage.getDataSize()))); } - if (otaPackage.getChecksumAlgorithm() != null) { + if (otaPackage.getChecksumAlgorithm() == null) { attrToRemove.add(getAttributeKey(otaPackageType, CHECKSUM_ALGORITHM)); } else { attributes.add(new BaseAttributeKvEntry(ts, new StringDataEntry(getAttributeKey(otaPackageType, CHECKSUM_ALGORITHM), otaPackage.getChecksumAlgorithm().name()))); diff --git a/application/src/main/java/org/thingsboard/server/service/subscription/TbAlarmStatusSubCtx.java b/application/src/main/java/org/thingsboard/server/service/subscription/TbAlarmStatusSubCtx.java index b3cd136726..6b3d38e8eb 100644 --- a/application/src/main/java/org/thingsboard/server/service/subscription/TbAlarmStatusSubCtx.java +++ b/application/src/main/java/org/thingsboard/server/service/subscription/TbAlarmStatusSubCtx.java @@ -95,6 +95,9 @@ public class TbAlarmStatusSubCtx extends TbAbstractSubCtx { private void handleAlarmStatusSubscriptionUpdate(TbSubscription sub, AlarmSubscriptionUpdate subscriptionUpdate) { try { AlarmInfo alarm = subscriptionUpdate.getAlarm(); + if (!alarm.getOriginator().equals(subscription.getEntityId())) { + return; + } Set alarmsIds = subscription.getAlarmIds(); if (alarmsIds.contains(alarm.getId().getId())) { if (!subscription.matches(alarm) || subscriptionUpdate.isAlarmDeleted()) { diff --git a/application/src/main/java/org/thingsboard/server/service/sync/ie/importing/csv/AbstractBulkImportService.java b/application/src/main/java/org/thingsboard/server/service/sync/ie/importing/csv/AbstractBulkImportService.java index 9850e2d1a1..63a4f100e1 100644 --- a/application/src/main/java/org/thingsboard/server/service/sync/ie/importing/csv/AbstractBulkImportService.java +++ b/application/src/main/java/org/thingsboard/server/service/sync/ie/importing/csv/AbstractBulkImportService.java @@ -186,7 +186,7 @@ public abstract class AbstractBulkImportService kvs.add(dataEntry.getKey().getKey(), dataEntry.getValue().toJsonPrimitive())); return Map.entry(kvType, kvs); }) - .filter(kvsEntry -> kvsEntry.getValue().entrySet().size() > 0) + .filter(kvsEntry -> !kvsEntry.getValue().entrySet().isEmpty()) .forEach(kvsEntry -> { BulkImportColumnType kvType = kvsEntry.getKey(); if (kvType == BulkImportColumnType.SHARED_ATTRIBUTE || kvType == BulkImportColumnType.SERVER_ATTRIBUTE) { diff --git a/application/src/main/java/org/thingsboard/server/service/system/SystemInfoService.java b/application/src/main/java/org/thingsboard/server/service/system/SystemInfoService.java index faae80a942..e2edd8a9cc 100644 --- a/application/src/main/java/org/thingsboard/server/service/system/SystemInfoService.java +++ b/application/src/main/java/org/thingsboard/server/service/system/SystemInfoService.java @@ -19,7 +19,9 @@ import org.thingsboard.server.common.data.FeaturesInfo; import org.thingsboard.server.common.data.SystemInfo; public interface SystemInfoService { + SystemInfo getSystemInfo(); FeaturesInfo getFeaturesInfo(); + } diff --git a/application/src/main/java/org/thingsboard/server/service/system/SystemPatchApplier.java b/application/src/main/java/org/thingsboard/server/service/system/SystemPatchApplier.java new file mode 100644 index 0000000000..76af940685 --- /dev/null +++ b/application/src/main/java/org/thingsboard/server/service/system/SystemPatchApplier.java @@ -0,0 +1,290 @@ +/** + * Copyright © 2016-2025 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.service.system; + +import com.fasterxml.jackson.databind.JsonNode; +import com.google.common.base.Charsets; +import com.google.common.hash.Hashing; +import com.google.common.io.Resources; +import jakarta.annotation.PostConstruct; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.stereotype.Component; +import org.thingsboard.common.util.JacksonUtil; +import org.thingsboard.common.util.ThingsBoardThreadFactory; +import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.widget.WidgetTypeDetails; +import org.thingsboard.server.dao.widget.WidgetTypeService; +import org.thingsboard.server.queue.util.TbCoreComponent; +import org.thingsboard.server.service.install.DatabaseSchemaSettingsService; +import org.thingsboard.server.service.install.InstallScripts; +import org.thingsboard.server.service.install.update.DefaultDataUpdateService; + +import java.io.IOException; +import java.io.UncheckedIOException; +import java.net.URL; +import java.nio.file.Files; +import java.nio.file.NoSuchFileException; +import java.nio.file.Path; +import java.util.Objects; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.stream.Stream; + +/** + * Runs at application startup and applies no-downtime data updates + * when the package PATCH version increases (e.g., 4.2.1.0 -> 4.2.1.1). + */ +@Slf4j +@Component +@TbCoreComponent +@RequiredArgsConstructor +public class SystemPatchApplier { + + private static final String SCHEMA_VIEWS_SQL = "sql/schema-views.sql"; + + private static final long ADVISORY_LOCK_ID = 7536891047216478431L; + + private final JdbcTemplate jdbcTemplate; + private final InstallScripts installScripts; + private final DatabaseSchemaSettingsService schemaSettingsService; + private final WidgetTypeService widgetTypeService; + + @PostConstruct + private void init() { + ExecutorService executor = Executors.newSingleThreadExecutor(ThingsBoardThreadFactory.forName("system-patch-applier")); + executor.submit(() -> { + try { + applyPatchIfNeeded(); + } catch (Exception e) { + log.error("Failed to apply system data patch updates", e); + } finally { + executor.shutdown(); + } + }); + } + + private void applyPatchIfNeeded() { + boolean skipVersionCheck = DefaultDataUpdateService.getEnv("SKIP_PATCH_VERSION_CHECK", false); + if (!skipVersionCheck && !isVersionChanged()) { + return; + } + + if (!acquireAdvisoryLock()) { + log.trace("Could not acquire advisory lock. Another node is processing patch updates."); + return; + } + + try { + updateSqlViews(); + log.info("Updated sql database views"); + + int updated = updateWidgetTypes(); + log.info("Updated {} widget types", updated); + + schemaSettingsService.updateSchemaVersion(); + log.info("System data patch update completed successfully"); + + } finally { + releaseAdvisoryLock(); + } + } + + private boolean isVersionChanged() { + String packageVersion = schemaSettingsService.getPackageSchemaVersion(); + String dbVersion = schemaSettingsService.getDbSchemaVersion(); + + log.trace("Package version: {}, DB schema version: {}", packageVersion, dbVersion); + + VersionInfo packageVersionInfo = parseVersion(packageVersion); + VersionInfo dbVersionInfo = parseVersion(dbVersion); + + if (packageVersionInfo == null || dbVersionInfo == null) { + log.warn("Unable to parse versions. Package: {}, DB: {}", packageVersion, dbVersion); + return false; + } + + if (!isPatchVersionChanged(packageVersionInfo, dbVersionInfo)) { + return false; + } + + log.info("Patch version increased from {} to {}. Starting system data update.", dbVersion, packageVersion); + return true; + } + + private boolean isPatchVersionChanged(VersionInfo packageVersion, VersionInfo dbVersion) { + return packageVersion.major == dbVersion.major && packageVersion.minor == dbVersion.minor + && packageVersion.maintenance == dbVersion.maintenance && packageVersion.patch > dbVersion.patch; + } + + private void updateSqlViews() { + try { + URL schemaViewsUrl = Resources.getResource(SCHEMA_VIEWS_SQL); + String sql = Resources.toString(schemaViewsUrl, Charsets.UTF_8); + jdbcTemplate.execute(sql); + } catch (IOException e) { + throw new RuntimeException("Unable to update database views from schema-views.sql", e); + } + } + + private int updateWidgetTypes() { + AtomicInteger updated = new AtomicInteger(); + Path widgetTypesDir = installScripts.getWidgetTypesDir(); + + if (!Files.exists(widgetTypesDir)) { + log.trace("Widget types directory does not exist: {}", widgetTypesDir); + return 0; + } + + try (Stream dirStream = listDir(widgetTypesDir).filter(path -> path.toString().endsWith(InstallScripts.JSON_EXT))) { + dirStream.forEach( + path -> { + try { + if (updateWidgetTypeFromFile(path)) { + updated.incrementAndGet(); + } + } catch (Exception e) { + log.error("Unable to update widget type from json: [{}]", path.toString()); + throw new RuntimeException("Unable to update widget type from json", e); + } + } + ); + } + + return updated.get(); + } + + private boolean updateWidgetTypeFromFile(Path filePath) { + JsonNode json = JacksonUtil.toJsonNode(filePath.toFile()); + WidgetTypeDetails fileWidgetType = JacksonUtil.treeToValue(json, WidgetTypeDetails.class); + String fqn = fileWidgetType.getFqn(); + + WidgetTypeDetails existingWidgetType = widgetTypeService.findWidgetTypeDetailsByTenantIdAndFqn(TenantId.SYS_TENANT_ID, fqn); + if (existingWidgetType == null) { + // We expect only update here, so it's probably never happening, but for test purpose leave it like this: + throw new RuntimeException("Widget type not found: " + fqn); + } + if (isWidgetTypeChanged(existingWidgetType, fileWidgetType)) { + existingWidgetType.setDescription(fileWidgetType.getDescription()); + existingWidgetType.setName(fileWidgetType.getName()); + existingWidgetType.setDescriptor(fileWidgetType.getDescriptor()); + widgetTypeService.saveWidgetType(existingWidgetType); + log.trace("Updated widget type: {}", fqn); + return true; + } + + log.trace("Widget type unchanged: {}", fqn); + return false; + } + + private boolean isWidgetTypeChanged(WidgetTypeDetails existing, WidgetTypeDetails file) { + if (!isDescriptorEqual(existing.getDescriptor(), file.getDescriptor())) { + return true; + } + + if (!Objects.equals(existing.getName(), file.getName())) { + return true; + } + + return !Objects.equals(existing.getDescription(), file.getDescription()); + } + + private boolean isDescriptorEqual(JsonNode desc1, JsonNode desc2) { + if (desc1 == null && desc2 == null) { + return true; + } + if (desc1 == null || desc2 == null) { + return false; + } + + try { + String hash1 = computeChecksum(desc1); + String hash2 = computeChecksum(desc2); + return Objects.equals(hash1, hash2); + } catch (Exception e) { + log.warn("Failed to compare descriptors using checksum, falling back to equals", e); + return desc1.equals(desc2); + } + } + + private String computeChecksum(JsonNode node) { + String canonicalString = JacksonUtil.toCanonicalString(node); + if (canonicalString == null) { + return null; + } + return Hashing.sha256().hashBytes(canonicalString.getBytes()).toString(); + } + + private boolean acquireAdvisoryLock() { + try { + Boolean acquired = jdbcTemplate.queryForObject( + "SELECT pg_try_advisory_lock(?)", + Boolean.class, + ADVISORY_LOCK_ID + ); + if (Boolean.TRUE.equals(acquired)) { + log.trace("Acquired advisory lock"); + return true; + } + return false; + } catch (Exception e) { + log.error("Failed to acquire advisory lock", e); + return false; + } + } + + private void releaseAdvisoryLock() { + try { + jdbcTemplate.queryForObject( + "SELECT pg_advisory_unlock(?)", + Boolean.class, + ADVISORY_LOCK_ID + ); + log.debug("Released advisory lock"); + } catch (Exception e) { + log.error("Failed to release advisory lock", e); + } + } + + private VersionInfo parseVersion(String version) { + try { + String[] parts = version.split("\\."); + int major = Integer.parseInt(parts[0]); + int minor = parts.length > 1 ? Integer.parseInt(parts[1]) : 0; + int maintenance = parts.length > 2 ? Integer.parseInt(parts[2]) : 0; + int patch = parts.length > 3 ? Integer.parseInt(parts[3]) : 0; + return new VersionInfo(major, minor, maintenance, patch); + } catch (Exception e) { + log.error("Failed to parse version: {}", version, e); + return null; + } + } + + private Stream listDir(Path dir) { + try { + return Files.list(dir); + } catch (NoSuchFileException e) { + return Stream.empty(); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + + public record VersionInfo(int major, int minor, int maintenance, int patch) {} + +} diff --git a/application/src/main/java/org/thingsboard/server/service/update/DefaultUpdateService.java b/application/src/main/java/org/thingsboard/server/service/update/DefaultUpdateService.java index 3c5ab63cd2..cb82e9b133 100644 --- a/application/src/main/java/org/thingsboard/server/service/update/DefaultUpdateService.java +++ b/application/src/main/java/org/thingsboard/server/service/update/DefaultUpdateService.java @@ -150,10 +150,10 @@ public class DefaultUpdateService implements UpdateService { .build()); } ObjectNode edgeRequest = JacksonUtil.newObjectNode().put(VERSION_PARAM, version); - String edgeInstallVersion = restClient.postForObject(UPDATE_SERVER_BASE_URL + "/api/v1/edge/installMapping", new HttpEntity<>(edgeRequest.toString(), headers), String.class); - if (edgeInstallVersion != null) { - edgeInstallInstructionsService.setAppVersion(edgeInstallVersion); - edgeUpgradeInstructionsService.setAppVersion(edgeInstallVersion); + String edgePlatformVersion = restClient.postForObject(UPDATE_SERVER_BASE_URL + "/api/v1/edge/installMapping", new HttpEntity<>(edgeRequest.toString(), headers), String.class); + if (edgePlatformVersion != null) { + edgeInstallInstructionsService.setPlatformEdgeVersion(edgePlatformVersion); + edgeUpgradeInstructionsService.setPlatformEdgeVersion(edgePlatformVersion); } EdgeUpgradeMessage edgeUpgradeMessage = restClient.postForObject(UPDATE_SERVER_BASE_URL + "/api/v1/edge/upgradeMapping", new HttpEntity<>(edgeRequest.toString(), headers), EdgeUpgradeMessage.class); if (edgeUpgradeMessage != null) { diff --git a/application/src/main/java/org/thingsboard/server/utils/CalculatedFieldArgumentUtils.java b/application/src/main/java/org/thingsboard/server/utils/CalculatedFieldArgumentUtils.java new file mode 100644 index 0000000000..1296df6e87 --- /dev/null +++ b/application/src/main/java/org/thingsboard/server/utils/CalculatedFieldArgumentUtils.java @@ -0,0 +1,75 @@ +/** + * Copyright © 2016-2025 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.utils; + +import lombok.NonNull; +import org.apache.commons.lang3.math.NumberUtils; +import org.thingsboard.server.common.data.StringUtils; +import org.thingsboard.server.common.data.cf.configuration.Argument; +import org.thingsboard.server.common.data.kv.AttributeKvEntry; +import org.thingsboard.server.common.data.kv.BaseAttributeKvEntry; +import org.thingsboard.server.common.data.kv.BasicTsKvEntry; +import org.thingsboard.server.common.data.kv.BooleanDataEntry; +import org.thingsboard.server.common.data.kv.DoubleDataEntry; +import org.thingsboard.server.common.data.kv.KvEntry; +import org.thingsboard.server.common.data.kv.StringDataEntry; +import org.thingsboard.server.common.data.kv.TsKvEntry; +import org.thingsboard.server.service.cf.ctx.state.ArgumentEntry; +import org.thingsboard.server.service.cf.ctx.state.CalculatedFieldCtx; +import org.thingsboard.server.service.cf.ctx.state.CalculatedFieldState; +import org.thingsboard.server.service.cf.ctx.state.ScriptCalculatedFieldState; +import org.thingsboard.server.service.cf.ctx.state.SimpleCalculatedFieldState; +import org.thingsboard.server.service.cf.ctx.state.SingleValueArgumentEntry; + +import static org.thingsboard.server.service.cf.ctx.state.SingleValueArgumentEntry.DEFAULT_VERSION; + +public class CalculatedFieldArgumentUtils { + + public static ArgumentEntry transformSingleValueArgument(@NonNull KvEntry kvEntry) { + return kvEntry.getValue() != null ? ArgumentEntry.createSingleValueArgument(kvEntry) : new SingleValueArgumentEntry(); + } + + public static TsKvEntry createDefaultTsKvEntry(Argument argument, long ts) { + return new BasicTsKvEntry(ts, createDefaultKvEntry(argument), DEFAULT_VERSION); + } + + public static AttributeKvEntry createDefaultAttributeEntry(Argument argument, long ts) { + return new BaseAttributeKvEntry(createDefaultKvEntry(argument), ts, DEFAULT_VERSION); + } + + private static KvEntry createDefaultKvEntry(Argument argument) { + String key = argument.getRefEntityKey().getKey(); + String defaultValue = argument.getDefaultValue(); + if (StringUtils.isBlank(defaultValue)) { + return new StringDataEntry(key, null); + } + if (NumberUtils.isParsable(defaultValue)) { + return new DoubleDataEntry(key, Double.parseDouble(defaultValue)); + } + if ("true".equalsIgnoreCase(defaultValue) || "false".equalsIgnoreCase(defaultValue)) { + return new BooleanDataEntry(key, Boolean.parseBoolean(defaultValue)); + } + return new StringDataEntry(key, defaultValue); + } + + public static CalculatedFieldState createStateByType(CalculatedFieldCtx ctx) { + return switch (ctx.getCfType()) { + case SIMPLE -> new SimpleCalculatedFieldState(ctx.getArgNames()); + case SCRIPT -> new ScriptCalculatedFieldState(ctx.getArgNames()); + }; + } + +} diff --git a/application/src/main/resources/thingsboard.yml b/application/src/main/resources/thingsboard.yml index 7da26fdc81..cda7f5782a 100644 --- a/application/src/main/resources/thingsboard.yml +++ b/application/src/main/resources/thingsboard.yml @@ -1295,6 +1295,8 @@ transport: ignore_type_cast_errors: "${SNMP_RESPONSE_IGNORE_TYPE_CAST_ERRORS:false}" # Thread pool size for scheduler that executes device querying tasks scheduler_thread_pool_size: "${SNMP_SCHEDULER_THREAD_POOL_SIZE:4}" + # Maximum number of retry attempts for a single SNMP devices batch during bootstrap. + batch_retries: "${SNMP_BOOTSTRAP_RETRIES:8}" stats: # Enable/Disable the collection of transport statistics enabled: "${TB_TRANSPORT_STATS_ENABLED:true}" @@ -1718,6 +1720,8 @@ queue: print-interval-ms: "${TB_QUEUE_KAFKA_CONSUMER_STATS_MIN_PRINT_INTERVAL_MS:60000}" # Time to wait for the stats-loading requests to Kafka to finish kafka-response-timeout-ms: "${TB_QUEUE_KAFKA_CONSUMER_STATS_RESPONSE_TIMEOUT_MS:1000}" + # Topics cache TTL in milliseconds. 5 minutes by default + topics_cache_ttl_ms: "${TB_QUEUE_KAFKA_TOPICS_CACHE_TTL_MS:300000}" partitions: hash_function_name: "${TB_QUEUE_PARTITIONS_HASH_FUNCTION_NAME:murmur3_128}" # murmur3_32, murmur3_128 or sha256 transport_api: diff --git a/application/src/test/java/org/thingsboard/server/cf/CalculatedFieldIntegrationTest.java b/application/src/test/java/org/thingsboard/server/cf/CalculatedFieldIntegrationTest.java index da4b5758cc..ffa39d8894 100644 --- a/application/src/test/java/org/thingsboard/server/cf/CalculatedFieldIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/cf/CalculatedFieldIntegrationTest.java @@ -45,6 +45,7 @@ import java.util.concurrent.TimeUnit; import static org.assertj.core.api.Assertions.assertThat; import static org.awaitility.Awaitility.await; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; @DaoSqlTest public class CalculatedFieldIntegrationTest extends CalculatedFieldControllerTest { @@ -570,6 +571,7 @@ public class CalculatedFieldIntegrationTest extends CalculatedFieldControllerTes @Test public void testScriptCalculatedFieldWhenUsedLatestTsInScript() throws Exception { Device testDevice = createDevice("Test device", "1234567890"); + long ts = System.currentTimeMillis() - 300000L; doPost("/api/plugins/telemetry/DEVICE/" + testDevice.getUuidId() + "/timeseries/" + DataConstants.SERVER_SCOPE, JacksonUtil.toJsonNode(String.format("{\"ts\": %s, \"values\": {\"temperature\":30}}", ts))); @@ -606,6 +608,91 @@ public class CalculatedFieldIntegrationTest extends CalculatedFieldControllerTes }); } + @Test + public void testSimpleCalculatedFieldWhenUseLatestTsIsTrueAndDefaultArguments() throws Exception { + Device testDevice = createDevice("Test device", "1234567890"); + + CalculatedField calculatedField = new CalculatedField(); + calculatedField.setEntityId(testDevice.getId()); + calculatedField.setType(CalculatedFieldType.SIMPLE); + calculatedField.setName("a + b + c"); + calculatedField.setDebugSettings(DebugSettings.all()); + calculatedField.setConfigurationVersion(1); + + SimpleCalculatedFieldConfiguration config = new SimpleCalculatedFieldConfiguration(); + + Argument argument1 = new Argument(); + ReferencedEntityKey refEntityKey1 = new ReferencedEntityKey("a", ArgumentType.TS_LATEST, null); + argument1.setRefEntityKey(refEntityKey1); + argument1.setDefaultValue("100"); + Argument argument2 = new Argument(); + ReferencedEntityKey refEntityKey2 = new ReferencedEntityKey("b", ArgumentType.TS_LATEST, null); + argument2.setRefEntityKey(refEntityKey2); + argument2.setDefaultValue("200"); + Argument argument3 = new Argument(); + ReferencedEntityKey refEntityKey3 = new ReferencedEntityKey("c", ArgumentType.TS_LATEST, null); + argument3.setRefEntityKey(refEntityKey3); + argument3.setDefaultValue("300"); + config.setArguments(Map.of("a", argument1, "b", argument2, "c", argument3)); + config.setExpression("a + b + c"); + + Output output = new Output(); + output.setName("d"); + output.setType(OutputType.TIME_SERIES); + output.setDecimalsByDefault(0); + config.setOutput(output); + + config.setUseLatestTs(true); + + calculatedField.setConfiguration(config); + + CalculatedField savedCalculatedField = doPost("/api/calculatedField", calculatedField, CalculatedField.class); + + await().alias("create CF -> perform initial calculation with default arguments").atMost(TIMEOUT, TimeUnit.SECONDS) + .pollInterval(POLL_INTERVAL, TimeUnit.SECONDS) + .untilAsserted(() -> { + ObjectNode d = getLatestTelemetry(testDevice.getId(), "d"); + assertThat(d).isNotNull(); + assertThat(d.get("d").get(0).get("value").asText()).isEqualTo("600"); + }); + + doPost("/api/plugins/telemetry/DEVICE/" + testDevice.getUuidId() + "/timeseries/" + DataConstants.SERVER_SCOPE, JacksonUtil.toJsonNode("{\"a\":10}")); + + await().alias("update telemetry -> save result with ts of 'a' argument").atMost(TIMEOUT, TimeUnit.SECONDS) + .pollInterval(POLL_INTERVAL, TimeUnit.SECONDS) + .untilAsserted(() -> { + ObjectNode keys = getLatestTelemetry(testDevice.getId(), "d", "a"); + assertThat(keys).isNotNull(); + String aTs = keys.get("a").get(0).get("ts").asText(); + assertThat(keys.get("d").get(0).get("ts").asText()).isEqualTo(aTs); + assertThat(keys.get("d").get(0).get("value").asText()).isEqualTo("510"); + }); + + doPost("/api/plugins/telemetry/DEVICE/" + testDevice.getUuidId() + "/timeseries/" + DataConstants.SERVER_SCOPE, JacksonUtil.toJsonNode("{\"b\":20}")); + doPost("/api/plugins/telemetry/DEVICE/" + testDevice.getUuidId() + "/timeseries/" + DataConstants.SERVER_SCOPE, JacksonUtil.toJsonNode("{\"c\":30}")); + + await().alias("update telemetry -> save result with latest ts of updated arguments").atMost(TIMEOUT, TimeUnit.SECONDS) + .pollInterval(POLL_INTERVAL, TimeUnit.SECONDS) + .untilAsserted(() -> { + ObjectNode keys = getLatestTelemetry(testDevice.getId(), "d"); + assertThat(keys).isNotNull(); + assertThat(keys.get("d").get(0).get("value").asText()).isEqualTo("60"); + }); + + String latestTs = getLatestTelemetry(testDevice.getId(), "d").get("d").get(0).get("ts").asText(); + + doDelete("/api/plugins/telemetry/DEVICE/" + testDevice.getId() + "/timeseries/delete?keys=b&deleteAllDataForKeys=true").andExpect(status().isOk()); + + await().alias("delete telemetry -> save result with previous latest ts and default argument").atMost(TIMEOUT, TimeUnit.SECONDS) + .pollInterval(POLL_INTERVAL, TimeUnit.SECONDS) + .untilAsserted(() -> { + ObjectNode keys = getLatestTelemetry(testDevice.getId(), "d"); + assertThat(keys).isNotNull(); + assertThat(keys.get("d").get(0).get("ts").asText()).isEqualTo(latestTs); + assertThat(keys.get("d").get(0).get("value").asText()).isEqualTo("240"); + }); + } + @Test public void testSimpleCalculatedFieldWhenCtxBecameUninitialized() throws Exception { Device testDevice = createDevice("Test device", "1234567890"); @@ -659,6 +746,135 @@ public class CalculatedFieldIntegrationTest extends CalculatedFieldControllerTes }); } + @Test + public void testCalculatedFieldWhenTheSameTelemetryKeysUsed() throws Exception { + Device testDevice = createDevice("Test device", "1234567890"); + doPost("/api/plugins/telemetry/DEVICE/" + testDevice.getUuidId() + "/timeseries/" + DataConstants.SERVER_SCOPE, JacksonUtil.toJsonNode("{\"a\":5}")); + + CalculatedField calculatedField = new CalculatedField(); + calculatedField.setEntityId(testDevice.getId()); + calculatedField.setType(CalculatedFieldType.SIMPLE); + calculatedField.setName("a + b"); + calculatedField.setDebugSettings(DebugSettings.all()); + + SimpleCalculatedFieldConfiguration config = new SimpleCalculatedFieldConfiguration(); + + ReferencedEntityKey refEntityKey = new ReferencedEntityKey("a", ArgumentType.TS_LATEST, null); + Argument argumentA = new Argument(); + argumentA.setRefEntityKey(refEntityKey); + Argument argumentB = new Argument(); + argumentB.setRefEntityKey(refEntityKey); + config.setArguments(Map.of("a", argumentA, "b", argumentB)); + config.setExpression("a + b"); + + Output output = new Output(); + output.setName("c"); + output.setType(OutputType.TIME_SERIES); + output.setDecimalsByDefault(0); + config.setOutput(output); + + calculatedField.setConfiguration(config); + + doPost("/api/calculatedField", calculatedField, CalculatedField.class); + + await().alias("create CF -> perform initial calculation").atMost(TIMEOUT, TimeUnit.SECONDS) + .pollInterval(POLL_INTERVAL, TimeUnit.SECONDS) + .untilAsserted(() -> { + ObjectNode c = getLatestTelemetry(testDevice.getId(), "c"); + assertThat(c).isNotNull(); + assertThat(c.get("c").get(0).get("value").asText()).isEqualTo("10"); + }); + + doPost("/api/plugins/telemetry/DEVICE/" + testDevice.getUuidId() + "/timeseries/" + DataConstants.SERVER_SCOPE, JacksonUtil.toJsonNode("{\"a\":10}")); + + await().alias("update telemetry -> recalculate state").atMost(TIMEOUT, TimeUnit.SECONDS) + .pollInterval(POLL_INTERVAL, TimeUnit.SECONDS) + .untilAsserted(() -> { + ObjectNode c = getLatestTelemetry(testDevice.getId(), "c"); + assertThat(c).isNotNull(); + assertThat(c.get("c").get(0).get("value").asText()).isEqualTo("20"); + }); + } + + @Test + public void testCalculatedFieldWhenBatchOfTelemetrySent() throws Exception { + Device testDevice = createDevice("Test device", "1234567890"); + long now = System.currentTimeMillis(); + doPost("/api/plugins/telemetry/DEVICE/" + testDevice.getUuidId() + "/timeseries/" + DataConstants.SERVER_SCOPE, JacksonUtil.toJsonNode(String.format("{\"ts\": %s, \"values\": {\"a\":5, \"b\":10}}", now - TimeUnit.MINUTES.toMillis(3)))); + doPost("/api/plugins/telemetry/DEVICE/" + testDevice.getUuidId() + "/timeseries/" + DataConstants.SERVER_SCOPE, JacksonUtil.toJsonNode(String.format("{\"ts\": %s, \"values\": {\"b\":20}}", now - TimeUnit.MINUTES.toMillis(1)))); + + CalculatedField calculatedField = new CalculatedField(); + calculatedField.setEntityId(testDevice.getId()); + calculatedField.setType(CalculatedFieldType.SCRIPT); + calculatedField.setName("Script CF"); + calculatedField.setDebugSettings(DebugSettings.all()); + + ScriptCalculatedFieldConfiguration config = new ScriptCalculatedFieldConfiguration(); + + ReferencedEntityKey refEntityKeyA = new ReferencedEntityKey("a", ArgumentType.TS_LATEST, null); + Argument argumentA = new Argument(); + argumentA.setRefEntityKey(refEntityKeyA); + Argument argumentB = new Argument(); + ReferencedEntityKey refEntityKeyB = new ReferencedEntityKey("b", ArgumentType.TS_ROLLING, null); + argumentB.setTimeWindow(TimeUnit.MINUTES.toMillis(10)); + argumentB.setLimit(1000); + argumentB.setRefEntityKey(refEntityKeyB); + config.setArguments(Map.of("a", argumentA, "b", argumentB)); + config.setExpression(""" + return { + "latestA": a, + "avgB": b.avg + }; + """); + + Output output = new Output(); + output.setType(OutputType.TIME_SERIES); + config.setOutput(output); + + calculatedField.setConfiguration(config); + + doPost("/api/calculatedField", calculatedField, CalculatedField.class); + + await().alias("create CF -> perform initial calculation").atMost(TIMEOUT, TimeUnit.SECONDS) + .pollInterval(POLL_INTERVAL, TimeUnit.SECONDS) + .untilAsserted(() -> { + ObjectNode result = getLatestTelemetry(testDevice.getId(), "latestA", "avgB"); + assertThat(result).isNotNull(); + assertThat(result.get("latestA").get(0).get("value").asText()).isEqualTo("5"); + assertThat(result.get("avgB").get(0).get("value").asText()).isEqualTo("15.0"); + }); + + doPost("/api/plugins/telemetry/DEVICE/" + testDevice.getUuidId() + "/timeseries/" + DataConstants.SERVER_SCOPE, JacksonUtil.toJsonNode(String.format(""" + [{ + "ts": %s, + "values": { + "a": 6, + "b": 100 + } + }, { + "ts": %s, + "values": { + "a": 7, + "b": 200 + } + }, { + "ts": %s, + "values": { + "a": 8, + "b": 300 + } + }]""", now - TimeUnit.MINUTES.toMillis(2), now, now - TimeUnit.MINUTES.toMillis(5)))); + + await().alias("update telemetry -> recalculate state").atMost(TIMEOUT, TimeUnit.SECONDS) + .pollInterval(POLL_INTERVAL, TimeUnit.SECONDS) + .untilAsserted(() -> { + ObjectNode result = getLatestTelemetry(testDevice.getId(), "latestA", "avgB"); + assertThat(result).isNotNull(); + assertThat(result.get("latestA").get(0).get("value").asText()).isEqualTo("7"); + assertThat(result.get("avgB").get(0).get("value").asText()).isEqualTo("126.0"); + }); + } + private ObjectNode getLatestTelemetry(EntityId entityId, String... keys) throws Exception { return doGetAsync("/api/plugins/telemetry/" + entityId.getEntityType() + "/" + entityId.getId() + "/values/timeseries?keys=" + String.join(",", keys), ObjectNode.class); } diff --git a/application/src/test/java/org/thingsboard/server/controller/AbstractNotifyEntityTest.java b/application/src/test/java/org/thingsboard/server/controller/AbstractNotifyEntityTest.java index 01c24ad493..d4eec0d648 100644 --- a/application/src/test/java/org/thingsboard/server/controller/AbstractNotifyEntityTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/AbstractNotifyEntityTest.java @@ -128,11 +128,17 @@ public abstract class AbstractNotifyEntityTest extends AbstractWebTest { protected void testNotifyEntityAllOneTimeLogEntityActionEntityEqClass(HasName entity, EntityId entityId, EntityId originatorId, TenantId tenantId, CustomerId customerId, UserId userId, String userName, ActionType actionType, ActionType actionTypeEdge, Object... additionalInfo) { + testNotifyEntityAllOneTimeLogEntityActionEntityEqClass(tenantId, entity, entityId, originatorId, tenantId, customerId, userId, userName, actionType, actionTypeEdge, additionalInfo); + } + + protected void testNotifyEntityAllOneTimeLogEntityActionEntityEqClass(TenantId entityTenantId, HasName entity, EntityId entityId, EntityId originatorId, + TenantId authTenantId, CustomerId customerId, UserId userId, String userName, + ActionType actionType, ActionType actionTypeEdge, Object... additionalInfo) { int cntTime = 1; - testNotificationMsgToEdgeServiceTime(entityId, tenantId, actionTypeEdge, cntTime); - testLogEntityActionEntityEqClass(entity, originatorId, tenantId, customerId, userId, userName, actionType, cntTime, additionalInfo); + testNotificationMsgToEdgeServiceTime(entityId, entityTenantId, actionTypeEdge, cntTime); + testLogEntityActionEntityEqClass(entity, originatorId, authTenantId, customerId, userId, userName, actionType, cntTime, additionalInfo); ArgumentMatcher matcherOriginatorId = argument -> argument.equals(originatorId); - testPushMsgToRuleEngineTime(matcherOriginatorId, tenantId, entity, cntTime); + testPushMsgToRuleEngineTime(matcherOriginatorId, authTenantId, entity, cntTime); Mockito.reset(tbClusterService, auditLogService); } @@ -159,17 +165,26 @@ public abstract class AbstractNotifyEntityTest extends AbstractWebTest { TenantId tenantId, CustomerId customerId, UserId userId, String userName, ActionType actionType, int cntTime, int cntTimeEdge, int cntTimeRuleEngine, Object... additionalInfo) { + testNotifyManyEntityManyTimeMsgToEdgeServiceEntityEqAny(tenantId, entity, originator, tenantId, customerId, userId, userName, actionType, + cntTime, cntTimeEdge, cntTimeRuleEngine, additionalInfo); + } + + protected void testNotifyManyEntityManyTimeMsgToEdgeServiceEntityEqAny(TenantId entityTenantId, HasName entity, HasName originator, + TenantId authTenantId, CustomerId customerId, UserId userId, String userName, + ActionType actionType, + int cntTime, int cntTimeEdge, int cntTimeRuleEngine, Object... additionalInfo) { EntityId originatorId = createEntityId_NULL_UUID(originator); - testSendNotificationMsgToEdgeServiceTimeEntityEqAny(tenantId, actionType, cntTimeEdge); + testSendNotificationMsgToEdgeServiceTimeEntityEqAny(entityTenantId, actionType, cntTimeEdge); ArgumentMatcher matcherEntityClassEquals = argument -> argument.getClass().equals(entity.getClass()); ArgumentMatcher matcherOriginatorId = argument -> argument.getClass().equals(originatorId.getClass()); ArgumentMatcher matcherCustomerId = customerId == null ? argument -> argument.getClass().equals(CustomerId.class) : argument -> argument.equals(customerId); ArgumentMatcher matcherUserId = userId == null ? argument -> argument.getClass().equals(UserId.class) : argument -> argument.equals(userId); - testLogEntityActionAdditionalInfo(matcherEntityClassEquals, matcherOriginatorId, tenantId, matcherCustomerId, matcherUserId, userName, actionType, cntTime, + testLogEntityActionAdditionalInfo(matcherEntityClassEquals, matcherOriginatorId, authTenantId, matcherCustomerId, matcherUserId, userName, actionType, cntTime, extractMatcherAdditionalInfoClass(additionalInfo)); - testPushMsgToRuleEngineTime(matcherOriginatorId, tenantId, entity, cntTimeRuleEngine); + testPushMsgToRuleEngineTime(matcherOriginatorId, authTenantId, entity, cntTimeRuleEngine); + } protected void testNotifyManyEntityManyTimeMsgToEdgeServiceEntityEqAnyAdditionalInfoAny(HasName entity, HasName originator, diff --git a/application/src/test/java/org/thingsboard/server/controller/AbstractWebTest.java b/application/src/test/java/org/thingsboard/server/controller/AbstractWebTest.java index b93ff0f623..54b2bbf6cf 100644 --- a/application/src/test/java/org/thingsboard/server/controller/AbstractWebTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/AbstractWebTest.java @@ -38,8 +38,6 @@ import org.mockito.Mockito; import org.mockito.invocation.InvocationOnMock; import org.mockito.stubbing.Answer; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.mock.mockito.MockBean; -import org.springframework.boot.test.mock.mockito.SpyBean; import org.springframework.cache.Cache; import org.springframework.cache.CacheManager; import org.springframework.http.HttpHeaders; @@ -53,6 +51,8 @@ import org.springframework.mock.http.MockHttpInputMessage; import org.springframework.mock.http.MockHttpOutputMessage; import org.springframework.mock.web.MockMultipartFile; import org.springframework.mock.web.MockPart; +import org.springframework.test.context.bean.override.mockito.MockitoBean; +import org.springframework.test.context.bean.override.mockito.MockitoSpyBean; import org.springframework.test.util.ReflectionTestUtils; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.MvcResult; @@ -154,6 +154,7 @@ import org.thingsboard.server.service.entitiy.tenant.profile.TbTenantProfileServ import org.thingsboard.server.service.security.auth.jwt.RefreshTokenRequest; import org.thingsboard.server.service.security.auth.rest.LoginRequest; import org.thingsboard.server.service.security.model.token.JwtTokenFactory; +import org.thingsboard.server.service.system.SystemPatchApplier; import java.io.IOException; import java.nio.charset.StandardCharsets; @@ -278,18 +279,21 @@ public abstract class AbstractWebTest extends AbstractInMemoryStorageTest { @Autowired private JwtTokenFactory jwtTokenFactory; - @SpyBean - protected MailService mailService; - @Autowired protected InMemoryStorage storage; @Autowired protected JdbcTemplate jdbcTemplate; - @MockBean + @MockitoSpyBean + protected MailService mailService; + + @MockitoBean protected CfRocksDb cfRocksDb; + @MockitoBean + protected SystemPatchApplier systemPatchApplier; + @Rule public TestRule watcher = new TestWatcher() { protected void starting(Description description) { @@ -1274,7 +1278,7 @@ public abstract class AbstractWebTest extends AbstractInMemoryStorageTest { protected List findJobs(List types, List entities) throws Exception { return doGetTypedWithPageLink("/api/jobs?types=" + types.stream().map(Enum::name).collect(Collectors.joining(",")) + - "&entities=" + entities.stream().map(UUID::toString).collect(Collectors.joining(",")) + "&", + "&entities=" + entities.stream().map(UUID::toString).collect(Collectors.joining(",")) + "&", new TypeReference>() {}, new PageLink(100, 0, null, new SortOrder("createdTime", SortOrder.Direction.DESC))).getData(); } diff --git a/application/src/test/java/org/thingsboard/server/controller/DeviceControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/DeviceControllerTest.java index 36cede9e84..4551e530d2 100644 --- a/application/src/test/java/org/thingsboard/server/controller/DeviceControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/DeviceControllerTest.java @@ -81,6 +81,7 @@ import org.thingsboard.server.service.state.DeviceStateService; import java.util.ArrayList; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.concurrent.TimeUnit; import static org.assertj.core.api.Assertions.assertThat; @@ -387,6 +388,48 @@ public class DeviceControllerTest extends AbstractControllerTest { .andExpect(statusReason(containsString("Device can`t be referencing to device profile from different tenant!"))); } + @Test + public void testSaveDeviceWithFirmware() throws Exception { + loginTenantAdmin(); + DeviceProfile profile = createDeviceProfile("Profile to test ota updates"); + profile = doPost("/api/deviceProfile", profile, DeviceProfile.class); + + SaveOtaPackageInfoRequest firmwareInfo = new SaveOtaPackageInfoRequest(); + firmwareInfo.setDeviceProfileId(profile.getId()); + firmwareInfo.setType(FIRMWARE); + String title = "title"; + firmwareInfo.setTitle(title); + String fwVersion = "1.0"; + firmwareInfo.setVersion(fwVersion); + String url = "test.url"; + firmwareInfo.setUrl(url); + firmwareInfo.setUsesUrl(true); + OtaPackageInfo savedFw = doPost("/api/otaPackage", firmwareInfo, OtaPackageInfo.class); + + Device device = new Device(); + device.setName("My ota device"); + device.setDeviceProfileId(profile.getId()); + device.setFirmwareId(savedFw.getId()); + device = doPost("/api/device", device, Device.class); + + //check shared attributes + Device finalDevice = device; + await().atMost(TIMEOUT, TimeUnit.SECONDS).until(() -> { + List> attributes = doGetAsyncTyped("/api/plugins/telemetry/DEVICE/" + finalDevice.getId() + + "/values/attributes/SHARED_SCOPE", new TypeReference>>() { + }); + return findAttrValue("fw_version", attributes).equals(fwVersion) && + findAttrValue("fw_title", attributes).equals(title) && + findAttrValue("fw_url", attributes).equals(url); + }); + } + + private static Object findAttrValue(String key, List> attributes) { + Optional> attr = attributes.stream() + .filter(att -> att.get("key").equals(key)).findFirst(); + return attr.isPresent() ? attr.get().get("value") : ""; + } + @Test public void testSaveDeviceWithFirmwareFromDifferentTenant() throws Exception { loginDifferentTenant(); diff --git a/application/src/test/java/org/thingsboard/server/controller/EdgeControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/EdgeControllerTest.java index faefab4cb4..f1d3ef1d52 100644 --- a/application/src/test/java/org/thingsboard/server/controller/EdgeControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/EdgeControllerTest.java @@ -1278,7 +1278,7 @@ public class EdgeControllerTest extends AbstractControllerTest { @Test public void testGetEdgeUpgradeInstructions() throws Exception { - // UpdateInfo config is updating from Thingsboard Update server + // UpdateInfo config is updating from the Thingsboard Update server HashMap upgradeInfoHashMap = new HashMap<>(); upgradeInfoHashMap.put("3.6.0", new EdgeUpgradeInfo(true, "3.6.1")); upgradeInfoHashMap.put("3.6.1", new EdgeUpgradeInfo(true, "3.6.2")); @@ -1301,35 +1301,31 @@ public class EdgeControllerTest extends AbstractControllerTest { // Test 3.5.0 Edge - upgrade not available String body = "{\"edgeVersion\": \"V_3_5_0\"}"; doPostAsync("/api/plugins/telemetry/EDGE/" + savedEdge.getId().getId() + "/attributes/SERVER_SCOPE", body, String.class, status().isOk()); - edgeUpgradeInstructionsService.setAppVersion("3.6.0"); + edgeUpgradeInstructionsService.setPlatformEdgeVersion("3.6.0"); Assert.assertFalse(edgeUpgradeInstructionsService.isUpgradeAvailable(savedEdge.getTenantId(), savedEdge.getId())); - edgeUpgradeInstructionsService.setAppVersion("3.6.2"); + edgeUpgradeInstructionsService.setPlatformEdgeVersion("3.6.2"); Assert.assertFalse(edgeUpgradeInstructionsService.isUpgradeAvailable(savedEdge.getTenantId(), savedEdge.getId())); - edgeUpgradeInstructionsService.setAppVersion("3.6.2.7"); + edgeUpgradeInstructionsService.setPlatformEdgeVersion("3.6.2.7"); Assert.assertFalse(edgeUpgradeInstructionsService.isUpgradeAvailable(savedEdge.getTenantId(), savedEdge.getId())); // Test 3.6.0 Edge - upgrade available body = "{\"edgeVersion\": \"V_3_6_0\"}"; doPostAsync("/api/plugins/telemetry/EDGE/" + savedEdge.getId().getId() + "/attributes/SERVER_SCOPE", body, String.class, status().isOk()); - edgeUpgradeInstructionsService.setAppVersion("3.6.0"); + edgeUpgradeInstructionsService.setPlatformEdgeVersion("3.6.0"); Assert.assertFalse(edgeUpgradeInstructionsService.isUpgradeAvailable(savedEdge.getTenantId(), savedEdge.getId())); - edgeUpgradeInstructionsService.setAppVersion("3.6.1.5"); + edgeUpgradeInstructionsService.setPlatformEdgeVersion("3.6.1.5"); Assert.assertTrue(edgeUpgradeInstructionsService.isUpgradeAvailable(savedEdge.getTenantId(), savedEdge.getId())); - edgeUpgradeInstructionsService.setAppVersion("3.6.1.6-SNAPSHOT"); - Assert.assertTrue(edgeUpgradeInstructionsService.isUpgradeAvailable(savedEdge.getTenantId(), savedEdge.getId())); - edgeUpgradeInstructionsService.setAppVersion("3.6.2"); + edgeUpgradeInstructionsService.setPlatformEdgeVersion("3.6.2"); Assert.assertTrue(edgeUpgradeInstructionsService.isUpgradeAvailable(savedEdge.getTenantId(), savedEdge.getId())); // Test 3.6.1 Edge - upgrade available body = "{\"edgeVersion\": \"V_3_6_1\"}"; doPostAsync("/api/plugins/telemetry/EDGE/" + savedEdge.getId().getId() + "/attributes/SERVER_SCOPE", body, String.class, status().isOk()); - edgeUpgradeInstructionsService.setAppVersion("3.6.1"); + edgeUpgradeInstructionsService.setPlatformEdgeVersion("3.6.1"); Assert.assertFalse(edgeUpgradeInstructionsService.isUpgradeAvailable(savedEdge.getTenantId(), savedEdge.getId())); - edgeUpgradeInstructionsService.setAppVersion("3.6.2"); - Assert.assertTrue(edgeUpgradeInstructionsService.isUpgradeAvailable(savedEdge.getTenantId(), savedEdge.getId())); - edgeUpgradeInstructionsService.setAppVersion("3.6.2-SNAPSHOT"); + edgeUpgradeInstructionsService.setPlatformEdgeVersion("3.6.2"); Assert.assertTrue(edgeUpgradeInstructionsService.isUpgradeAvailable(savedEdge.getTenantId(), savedEdge.getId())); - edgeUpgradeInstructionsService.setAppVersion("3.6.2.6"); + edgeUpgradeInstructionsService.setPlatformEdgeVersion("3.6.2.6"); Assert.assertTrue(edgeUpgradeInstructionsService.isUpgradeAvailable(savedEdge.getTenantId(), savedEdge.getId())); } diff --git a/application/src/test/java/org/thingsboard/server/controller/TbResourceControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/TbResourceControllerTest.java index 352e1fcfeb..d88aaa2756 100644 --- a/application/src/test/java/org/thingsboard/server/controller/TbResourceControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/TbResourceControllerTest.java @@ -943,7 +943,7 @@ public class TbResourceControllerTest extends AbstractControllerTest { private List loadLwm2mResources() throws Exception { - var models = List.of("1", "2", "3", "5", "6", "9", "19", "3303"); + var models = List.of("1", "2", "3-1_2", "5", "6", "9", "19", "3303"); List resources = new ArrayList<>(models.size()); diff --git a/application/src/test/java/org/thingsboard/server/controller/UserControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/UserControllerTest.java index d7aa6f5770..28d43699fd 100644 --- a/application/src/test/java/org/thingsboard/server/controller/UserControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/UserControllerTest.java @@ -116,7 +116,7 @@ public class UserControllerTest extends AbstractControllerTest { foundUser.setAdditionalInfo(savedUser.getAdditionalInfo()); Assert.assertEquals(foundUser, savedUser); - testNotifyManyEntityManyTimeMsgToEdgeServiceEntityEqAny(foundUser, foundUser, + testNotifyManyEntityManyTimeMsgToEdgeServiceEntityEqAny(user.getTenantId(), foundUser, foundUser, SYSTEM_TENANT, customerNUULId, null, SYS_ADMIN_EMAIL, ActionType.ADDED, 1, 1, 1); Mockito.reset(tbClusterService, auditLogService); @@ -155,7 +155,7 @@ public class UserControllerTest extends AbstractControllerTest { doDelete("/api/user/" + savedUser.getId().getId().toString()) .andExpect(status().isOk()); - testNotifyEntityAllOneTimeLogEntityActionEntityEqClass(foundUser, foundUser.getId(), foundUser.getId(), + testNotifyEntityAllOneTimeLogEntityActionEntityEqClass(user.getTenantId(), foundUser, foundUser.getId(), foundUser.getId(), SYSTEM_TENANT, customerNUULId, null, SYS_ADMIN_EMAIL, ActionType.DELETED, ActionType.DELETED, SYSTEM_TENANT.getId().toString()); } @@ -284,6 +284,26 @@ public class UserControllerTest extends AbstractControllerTest { ActionType.ADDED, new DataValidationException(msgError)); } + @Test + public void testShouldNotDeleteLastTenantAdmin() throws Exception { + loginSysAdmin(); + + User tenantAdmin2 = new User(); + tenantAdmin2.setAuthority(Authority.TENANT_ADMIN); + tenantAdmin2.setTenantId(tenantId); + tenantAdmin2.setEmail("tenant2@thingsboard.io"); + tenantAdmin2 = doPost("/api/user", tenantAdmin2, User.class); + + // delete second tenant admin - ok + doDelete("/api/user/" + tenantAdmin2.getId().getId().toString()) + .andExpect(status().isOk()); + + // delete last tenant admin - forbidden + doDelete("/api/user/" + tenantAdminUser.getId().getId().toString()) + .andExpect(status().isBadRequest()) + .andExpect(statusReason(containsString("At least one tenant administrator must remain!"))); + } + @Test public void testSaveUserWithInvalidEmail() throws Exception { loginSysAdmin(); @@ -394,7 +414,7 @@ public class UserControllerTest extends AbstractControllerTest { User testManyUser = new User(); testManyUser.setTenantId(tenantId); - testNotifyManyEntityManyTimeMsgToEdgeServiceEntityEqAny(testManyUser, testManyUser, + testNotifyManyEntityManyTimeMsgToEdgeServiceEntityEqAny(tenantId, testManyUser, testManyUser, SYSTEM_TENANT, customerNUULId, null, SYS_ADMIN_EMAIL, ActionType.ADDED, cntEntity, cntEntity, cntEntity); @@ -506,7 +526,7 @@ public class UserControllerTest extends AbstractControllerTest { } User testManyUser = new User(); testManyUser.setTenantId(tenantId); - testNotifyManyEntityManyTimeMsgToEdgeServiceEntityEqAny(testManyUser, testManyUser, + testNotifyManyEntityManyTimeMsgToEdgeServiceEntityEqAny(tenantId, testManyUser, testManyUser, SYSTEM_TENANT, customerNUULId, null, SYS_ADMIN_EMAIL, ActionType.DELETED, cntEntity, NUMBER_OF_USERS, cntEntity, ""); diff --git a/application/src/test/java/org/thingsboard/server/controller/WebsocketApiTest.java b/application/src/test/java/org/thingsboard/server/controller/WebsocketApiTest.java index bebdd5ecb9..6dacf50592 100644 --- a/application/src/test/java/org/thingsboard/server/controller/WebsocketApiTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/WebsocketApiTest.java @@ -34,6 +34,7 @@ import org.thingsboard.rule.engine.api.TimeseriesSaveRequest; import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.alarm.Alarm; import org.thingsboard.server.common.data.alarm.AlarmSeverity; +import org.thingsboard.server.common.data.asset.Asset; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.kv.AttributeKvEntry; @@ -58,6 +59,7 @@ import org.thingsboard.server.common.data.query.KeyFilter; import org.thingsboard.server.common.data.query.NumericFilterPredicate; import org.thingsboard.server.common.data.query.SingleEntityFilter; import org.thingsboard.server.common.data.query.TsValue; +import org.thingsboard.server.common.data.relation.EntityRelation; import org.thingsboard.server.dao.service.DaoSqlTest; import org.thingsboard.server.service.subscription.SubscriptionErrorCode; import org.thingsboard.server.service.subscription.TbAttributeSubscriptionScope; @@ -478,6 +480,56 @@ public class WebsocketApiTest extends AbstractControllerTest { Assert.assertFalse(alarmStatusUpdate5.isActive()); } + @Test + public void testAlarmStatusWsCmdForPropagatedAlarms() throws Exception { + loginTenantAdmin(); + Device device = new Device(); + device.setName("Test device"); + device.setLabel("Label"); + device.setType("default"); + device = doPost("/api/device", device, Device.class); + + Asset asset = new Asset(); + asset.setName("My asset"); + asset.setType("default"); + asset = doPost("/api/asset", asset, Asset.class); + + EntityRelation entityRelation = new EntityRelation(asset.getId(), device.getId(), "CONTAINS"); + doPost("/api/relation", entityRelation); + + AlarmStatusCmd cmd = new AlarmStatusCmd(1, asset.getId(), null, List.of(AlarmSeverity.CRITICAL)); + getWsClient().send(cmd); + + AlarmStatusUpdate update = JacksonUtil.fromString(getWsClient().waitForReply(), AlarmStatusUpdate.class); + Assert.assertEquals(1, update.getCmdId()); + Assert.assertFalse(update.isActive()); + + //create alarm + getWsClient().registerWaitForUpdate(); + + Alarm alarm = Alarm.builder() + .originator(device.getId()) + .severity(AlarmSeverity.CRITICAL) + .type("test_type") + .propagate(true) + .build(); + + alarm = doPost("/api/alarm", alarm, Alarm.class); + Assert.assertNotNull(alarm); + + // check no update for asset + String msg = getWsClient().waitForUpdate(TimeUnit.SECONDS.toMillis(1)); + Assert.assertNull(msg); + + // check device + AlarmStatusCmd deviceCmd = new AlarmStatusCmd(2, device.getId(), null, List.of(AlarmSeverity.CRITICAL)); + getWsClient().send(deviceCmd); + + AlarmStatusUpdate deviceUpdate = JacksonUtil.fromString(getWsClient().waitForReply(), AlarmStatusUpdate.class); + Assert.assertEquals(2, deviceUpdate.getCmdId()); + Assert.assertTrue(deviceUpdate.isActive()); + } + @Test public void testAlarmStatusWsCmdWithMaxAlarmsCacheSize() throws Exception { loginTenantAdmin(); diff --git a/application/src/test/java/org/thingsboard/server/edge/DashboardEdgeTest.java b/application/src/test/java/org/thingsboard/server/edge/DashboardEdgeTest.java index bbf3d17f0d..0730907c26 100644 --- a/application/src/test/java/org/thingsboard/server/edge/DashboardEdgeTest.java +++ b/application/src/test/java/org/thingsboard/server/edge/DashboardEdgeTest.java @@ -27,11 +27,15 @@ import org.thingsboard.server.common.data.DashboardInfo; import org.thingsboard.server.common.data.ShortCustomerInfo; import org.thingsboard.server.common.data.StringUtils; import org.thingsboard.server.common.data.edge.Edge; +import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.DashboardId; +import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.dao.service.DaoSqlTest; +import org.thingsboard.server.gen.edge.v1.CustomerUpdateMsg; import org.thingsboard.server.gen.edge.v1.DashboardUpdateMsg; +import org.thingsboard.server.gen.edge.v1.EdgeConfiguration; import org.thingsboard.server.gen.edge.v1.ResourceUpdateMsg; import org.thingsboard.server.gen.edge.v1.UpdateMsgType; import org.thingsboard.server.gen.edge.v1.UplinkMsg; @@ -182,6 +186,22 @@ public class DashboardEdgeTest extends AbstractEdgeTest { customer.setTitle("Edge Customer"); Customer savedCustomer = doPost("/api/customer", customer, Customer.class); + // assign edge to customer + edgeImitator.expectMessageAmount(2); + doPost("/api/customer/" + savedCustomer.getUuidId() + "/edge/" + edge.getUuidId(), Edge.class); + Assert.assertTrue(edgeImitator.waitForMessages()); + Optional edgeConfigurationOpt = edgeImitator.findMessageByType(EdgeConfiguration.class); + Assert.assertTrue(edgeConfigurationOpt.isPresent()); + EdgeConfiguration edgeConfiguration = edgeConfigurationOpt.get(); + Assert.assertEquals(savedCustomer.getUuidId().getMostSignificantBits(), edgeConfiguration.getCustomerIdMSB()); + Assert.assertEquals(savedCustomer.getUuidId().getLeastSignificantBits(), edgeConfiguration.getCustomerIdLSB()); + Optional customerUpdateOpt = edgeImitator.findMessageByType(CustomerUpdateMsg.class); + Assert.assertTrue(customerUpdateOpt.isPresent()); + CustomerUpdateMsg customerUpdateMsg = customerUpdateOpt.get(); + Customer customerMsg = JacksonUtil.fromString(customerUpdateMsg.getEntity(), Customer.class, true); + Assert.assertEquals(UpdateMsgType.ENTITY_CREATED_RPC_MESSAGE, customerUpdateMsg.getMsgType()); + Assert.assertEquals(savedCustomer, customerMsg); + Dashboard dashboard = buildDashboardForUplinkMsg(savedCustomer); // create dashboard on edge @@ -224,6 +244,23 @@ public class DashboardEdgeTest extends AbstractEdgeTest { foundDashboard = doGet("/api/dashboard/" + dashboard.getUuidId(), Dashboard.class); Assert.assertEquals(DASHBOARD_TITLE + " Updated", foundDashboard.getName()); + + // unassign edge from customer + edgeImitator.expectMessageAmount(2); + doDelete("/api/customer/edge/" + edge.getUuidId(), Edge.class); + Assert.assertTrue(edgeImitator.waitForMessages()); + edgeConfigurationOpt = edgeImitator.findMessageByType(EdgeConfiguration.class); + Assert.assertTrue(edgeConfigurationOpt.isPresent()); + edgeConfiguration = edgeConfigurationOpt.get(); + Assert.assertEquals( + new CustomerId(EntityId.NULL_UUID), + new CustomerId(new UUID(edgeConfiguration.getCustomerIdMSB(), edgeConfiguration.getCustomerIdLSB()))); + customerUpdateOpt = edgeImitator.findMessageByType(CustomerUpdateMsg.class); + Assert.assertTrue(customerUpdateOpt.isPresent()); + customerUpdateMsg = customerUpdateOpt.get(); + Assert.assertEquals(UpdateMsgType.ENTITY_DELETED_RPC_MESSAGE, customerUpdateMsg.getMsgType()); + Assert.assertEquals(savedCustomer.getUuidId().getMostSignificantBits(), customerUpdateMsg.getIdMSB()); + Assert.assertEquals(savedCustomer.getUuidId().getLeastSignificantBits(), customerUpdateMsg.getIdLSB()); } @Test diff --git a/application/src/test/java/org/thingsboard/server/service/job/JobManagerTest.java b/application/src/test/java/org/thingsboard/server/service/job/JobManagerTest.java index 0069310b5d..7806215a51 100644 --- a/application/src/test/java/org/thingsboard/server/service/job/JobManagerTest.java +++ b/application/src/test/java/org/thingsboard/server/service/job/JobManagerTest.java @@ -98,7 +98,7 @@ public class JobManagerTest extends AbstractControllerTest { await().atMost(TIMEOUT, TimeUnit.SECONDS).untilAsserted(() -> { Job job = findJobById(jobId); assertThat(job.getStatus()).isEqualTo(JobStatus.RUNNING); - assertThat(job.getResult().getSuccessfulCount()).isBetween(1, tasksCount - 1); + assertThat(job.getResult().getSuccessfulCount()).isBetween(0, tasksCount - 1); assertThat(job.getResult().getTotalCount()).isEqualTo(tasksCount); }); await().atMost(TIMEOUT, TimeUnit.SECONDS).untilAsserted(() -> { diff --git a/application/src/test/java/org/thingsboard/server/service/job/JobManagerTest_EntityPartitioningStrategy.java b/application/src/test/java/org/thingsboard/server/service/job/JobManagerTest_EntityPartitioningStrategy.java index 59093ad802..c1b8f911ff 100644 --- a/application/src/test/java/org/thingsboard/server/service/job/JobManagerTest_EntityPartitioningStrategy.java +++ b/application/src/test/java/org/thingsboard/server/service/job/JobManagerTest_EntityPartitioningStrategy.java @@ -27,17 +27,16 @@ import org.thingsboard.server.dao.service.DaoSqlTest; public class JobManagerTest_EntityPartitioningStrategy extends JobManagerTest { /* - * Some tests are overridden because they are based on - * tenant partitioning strategy (subsequent tasks processing within a tenant) - * */ + * Some tests are overridden because they are based on + * tenant partitioning strategy (subsequent tasks processing within a tenant) + * */ @Override - public void testCancelJob_simulateTaskProcessorRestart() throws Exception { + public void testCancelJob_simulateTaskProcessorRestart() { } @Override public void testSubmitJob_generalError() { - } } diff --git a/application/src/test/java/org/thingsboard/server/system/BaseHttpDeviceApiTest.java b/application/src/test/java/org/thingsboard/server/system/BaseHttpDeviceApiTest.java index dbfca2e9f1..65633c6bd9 100644 --- a/application/src/test/java/org/thingsboard/server/system/BaseHttpDeviceApiTest.java +++ b/application/src/test/java/org/thingsboard/server/system/BaseHttpDeviceApiTest.java @@ -37,9 +37,6 @@ import static org.springframework.test.web.servlet.request.MockMvcRequestBuilder import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.request; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; -/** - * @author Andrew Shvayka - */ @TestPropertySource(properties = { "transport.http.enabled=true", "transport.http.max_payload_size=/api/v1/*/rpc/**=10000;/api/v1/**=20000" diff --git a/application/src/test/java/org/thingsboard/server/system/BaseRestApiLimitsTest.java b/application/src/test/java/org/thingsboard/server/system/BaseRestApiLimitsTest.java index 84a366b139..fea9d5086c 100644 --- a/application/src/test/java/org/thingsboard/server/system/BaseRestApiLimitsTest.java +++ b/application/src/test/java/org/thingsboard/server/system/BaseRestApiLimitsTest.java @@ -45,10 +45,6 @@ import java.util.concurrent.TimeoutException; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; -/** - * @author Illia Barkov - */ - @Slf4j public abstract class BaseRestApiLimitsTest extends AbstractControllerTest { diff --git a/application/src/test/java/org/thingsboard/server/system/RestTemplateConvertersTest.java b/application/src/test/java/org/thingsboard/server/system/RestTemplateConvertersTest.java index 6ff57a7ee0..f976156a86 100644 --- a/application/src/test/java/org/thingsboard/server/system/RestTemplateConvertersTest.java +++ b/application/src/test/java/org/thingsboard/server/system/RestTemplateConvertersTest.java @@ -29,7 +29,6 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.springframework.test.web.client.match.MockRestRequestMatchers.requestTo; import static org.springframework.test.web.client.response.MockRestResponseCreators.withSuccess; - @Slf4j public class RestTemplateConvertersTest { diff --git a/application/src/test/java/org/thingsboard/server/system/SystemPatchApplierTest.java b/application/src/test/java/org/thingsboard/server/system/SystemPatchApplierTest.java new file mode 100644 index 0000000000..3c65f19d65 --- /dev/null +++ b/application/src/test/java/org/thingsboard/server/system/SystemPatchApplierTest.java @@ -0,0 +1,410 @@ +/** + * Copyright © 2016-2025 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.system; + +import com.fasterxml.jackson.databind.JsonNode; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.api.io.TempDir; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.CsvSource; +import org.junit.jupiter.params.provider.MethodSource; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.test.util.ReflectionTestUtils; +import org.thingsboard.common.util.JacksonUtil; +import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.id.WidgetTypeId; +import org.thingsboard.server.common.data.widget.WidgetTypeDetails; +import org.thingsboard.server.dao.widget.WidgetTypeService; +import org.thingsboard.server.service.install.InstallScripts; +import org.thingsboard.server.service.system.SystemPatchApplier; + +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.UUID; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.stream.Stream; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.argThat; +import static org.mockito.ArgumentMatchers.contains; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +@ExtendWith(MockitoExtension.class) +public class SystemPatchApplierTest { + + @Mock + private JdbcTemplate jdbcTemplate; + + @Mock + private InstallScripts installScripts; + + @Mock + private WidgetTypeService widgetTypeService; + + @InjectMocks + private SystemPatchApplier reconciler; + + @TempDir + Path tempDir; + + @ParameterizedTest(name = "Parse version {0} should return major={1}, minor={2}, patch={3}") + @CsvSource({ + "4.2.1, 4, 2, 1, 0", + "4.2.0, 4, 2, 0, 0", + "4.2, 4, 2, 0, 0", + "4.0.1.2, 4, 0, 1, 2", + "4, 4, 0, 0, 0", + "1.0.5.7, 1, 0, 5, 7", + "10.20.30.40, 10, 20, 30, 40", + "0.0.1, 0, 0, 1, 0" + }) + void testParseVersion(String versionString, int expectedMajor, int expectedMinor, int expectedMaintenance, int expectedPatch) { + SystemPatchApplier.VersionInfo version = ReflectionTestUtils.invokeMethod(reconciler, "parseVersion", versionString); + + assertNotNull(version, "Version should not be null for: " + versionString); + assertEquals(expectedMajor, version.major(), "Major version mismatch"); + assertEquals(expectedMinor, version.minor(), "Minor version mismatch"); + assertEquals(expectedMaintenance, version.maintenance(), "Maintenance version mismatch"); + assertEquals(expectedPatch, version.patch(), "Patch version mismatch"); + } + + @ParameterizedTest(name = "Parse invalid version: {0}") + @CsvSource({ + "invalid", + "a.b.c", + "1.2.y.x", + "''", + "1.x.3" + }) + void testParseInvalidVersion(String invalidVersion) { + SystemPatchApplier.VersionInfo version = ReflectionTestUtils.invokeMethod(reconciler, "parseVersion", invalidVersion); + assertNull(version, "Version should be null for invalid input: " + invalidVersion); + } + + @Test + void whenLockIsNotAcquired_thenAcquiredIsSuccess() { + when(jdbcTemplate.queryForObject(anyString(), eq(Boolean.class), anyLong())).thenReturn(true); + + Boolean acquired = ReflectionTestUtils.invokeMethod(reconciler, "acquireAdvisoryLock"); + + assertEquals(Boolean.TRUE, acquired); + verify(jdbcTemplate).queryForObject(contains("pg_try_advisory_lock"), eq(Boolean.class), anyLong()); + } + + @Test + void whenLockIsAlreadyAcquired_thenAcquiredIsFailed() { + when(jdbcTemplate.queryForObject(anyString(), eq(Boolean.class), anyLong())).thenReturn(false); + + Boolean acquired = ReflectionTestUtils.invokeMethod(reconciler, "acquireAdvisoryLock"); + + assertNotEquals(Boolean.TRUE, acquired); + } + + @Test + void testReleaseAdvisoryLock() { + when(jdbcTemplate.queryForObject(anyString(), eq(Boolean.class), anyLong())) + .thenReturn(true); + + ReflectionTestUtils.invokeMethod(reconciler, "releaseAdvisoryLock"); + + verify(jdbcTemplate).queryForObject( + contains("pg_advisory_unlock"), eq(Boolean.class), anyLong()); + } + + @Test + void whenWidgetNotFound_thenThrowException() throws Exception { + Path widgetTypesDir = tempDir.resolve("widget_types"); + Files.createDirectories(widgetTypesDir); + when(installScripts.getWidgetTypesDir()).thenReturn(widgetTypesDir); + + WidgetTypeDetails testWidget = createTestWidgetType("test_widget", "Test Widget"); + String json = JacksonUtil.toString(testWidget); + assertNotNull(json); + Files.writeString(widgetTypesDir.resolve("test_widget.json"), json); + + when(widgetTypeService.findWidgetTypeDetailsByTenantIdAndFqn(TenantId.SYS_TENANT_ID, "test_widget")).thenReturn(null); + + assertThrows(RuntimeException.class, () -> ReflectionTestUtils.invokeMethod(reconciler, "updateWidgetTypes")); + } + + @Test + void whenDescriptorChanged_thenUpdateTheExistingWidget() throws Exception { + Path widgetTypesDir = tempDir.resolve("widget_types"); + Files.createDirectories(widgetTypesDir); + when(installScripts.getWidgetTypesDir()).thenReturn(widgetTypesDir); + + WidgetTypeDetails fileWidget = createTestWidgetType("test_widget", "Test Widget"); + fileWidget.setDescriptor(JacksonUtil.toJsonNode("{\"type\":\"latest\",\"version\":2}")); + String json = JacksonUtil.toString(fileWidget); + assertNotNull(json); + Files.writeString(widgetTypesDir.resolve("test_widget.json"), json); + + WidgetTypeDetails existingWidget = createTestWidgetType("test_widget", "Test Widget"); + existingWidget.setId(new WidgetTypeId(UUID.randomUUID())); + existingWidget.setDescriptor(JacksonUtil.toJsonNode("{\"type\":\"latest\",\"version\":1}")); + + when(widgetTypeService.findWidgetTypeDetailsByTenantIdAndFqn(TenantId.SYS_TENANT_ID, "test_widget")) + .thenReturn(existingWidget); + + Integer updated = ReflectionTestUtils.invokeMethod(reconciler, "updateWidgetTypes"); + + assertEquals(1, updated); + verify(widgetTypeService).saveWidgetType(argThat(w -> + w.getDescriptor().get("version").asInt() == 2 + )); + } + + @Test + void whenNameChanged_thenUpdateTheExistingWidget() throws Exception { + Path widgetTypesDir = tempDir.resolve("widget_types"); + Files.createDirectories(widgetTypesDir); + when(installScripts.getWidgetTypesDir()).thenReturn(widgetTypesDir); + + WidgetTypeDetails fileWidget = createTestWidgetType("test_widget", "New Name"); + String json = JacksonUtil.toString(fileWidget); + assertNotNull(json); + Files.writeString(widgetTypesDir.resolve("test_widget.json"), json); + + WidgetTypeDetails existingWidget = createTestWidgetType("test_widget", "Old Name"); + existingWidget.setId(new WidgetTypeId(UUID.randomUUID())); + + when(widgetTypeService.findWidgetTypeDetailsByTenantIdAndFqn(TenantId.SYS_TENANT_ID, "test_widget")) + .thenReturn(existingWidget); + + Integer updated = ReflectionTestUtils.invokeMethod(reconciler, "updateWidgetTypes"); + + assertEquals(1, updated); + verify(widgetTypeService).saveWidgetType(argThat(w -> "New Name".equals(w.getName()))); + } + + @Test + void whenNothingChanged_thenSkipTheUpdateOfTheExistingWidget() throws Exception { + Path widgetTypesDir = tempDir.resolve("widget_types"); + Files.createDirectories(widgetTypesDir); + when(installScripts.getWidgetTypesDir()).thenReturn(widgetTypesDir); + + WidgetTypeDetails fileWidget = createTestWidgetType("test_widget", "Test Widget"); + String json = JacksonUtil.toString(fileWidget); + assertNotNull(json); + Files.writeString(widgetTypesDir.resolve("test_widget.json"), json); + + WidgetTypeDetails existingWidget = createTestWidgetType("test_widget", "Test Widget"); + existingWidget.setId(new WidgetTypeId(UUID.randomUUID())); + + when(widgetTypeService.findWidgetTypeDetailsByTenantIdAndFqn(TenantId.SYS_TENANT_ID, "test_widget")) + .thenReturn(existingWidget); + + Integer updated = ReflectionTestUtils.invokeMethod(reconciler, "updateWidgetTypes"); + + assertEquals(0, updated); + verify(widgetTypeService, never()).saveWidgetType(any()); + } + + @ParameterizedTest(name = "{0}") + @MethodSource("provideDescriptorComparisonTestCases") + void testIfDescriptorsAreEqual(String testName, JsonNode desc1, JsonNode desc2, boolean expectedEqual) { + Boolean result = ReflectionTestUtils.invokeMethod(reconciler, "isDescriptorEqual", desc1, desc2); + assertEquals(expectedEqual, result, testName); + } + + @Test + void whenDescriptorChanged_thenReturnWidgetTypeChanged() { + WidgetTypeDetails existing = createTestWidgetType("test", "Test"); + existing.setDescriptor(JacksonUtil.toJsonNode("{\"version\":1}")); + + WidgetTypeDetails file = createTestWidgetType("test", "Test"); + file.setDescriptor(JacksonUtil.toJsonNode("{\"version\":2}")); + + boolean result = Boolean.TRUE.equals(ReflectionTestUtils.invokeMethod(reconciler, "isWidgetTypeChanged", existing, file)); + assertTrue(result); + } + + @Test + void whenNameChanged_thenReturnWidgetTypeChanged() { + WidgetTypeDetails existing = createTestWidgetType("test", "Old Name"); + WidgetTypeDetails file = createTestWidgetType("test", "New Name"); + + boolean result = Boolean.TRUE.equals(ReflectionTestUtils.invokeMethod(reconciler, "isWidgetTypeChanged", existing, file)); + assertTrue(result); + } + + @Test + void whenDescriptionChanged_thenReturnWidgetTypeChanged() { + WidgetTypeDetails existing = createTestWidgetType("test", "Test"); + existing.setDescription("Old description"); + + WidgetTypeDetails file = createTestWidgetType("test", "Test"); + file.setDescription("New description"); + + boolean result = Boolean.TRUE.equals(ReflectionTestUtils.invokeMethod(reconciler, "isWidgetTypeChanged", existing, file)); + assertTrue(result); + } + + @Test + void whenWidgetTypeAreIdentical_thenNoUpdateIsPerformed() { + WidgetTypeDetails existing = createTestWidgetType("test", "Test"); + WidgetTypeDetails file = createTestWidgetType("test", "Test"); + + boolean result = Boolean.TRUE.equals(ReflectionTestUtils.invokeMethod(reconciler, "isWidgetTypeChanged", existing, file)); + assertFalse(result); + } + + @Test + void whenLockIsHeldByOneThread_thenSecondThreadCannotAcquireLock() throws Exception { + CountDownLatch lockAcquired = new CountDownLatch(1); + CountDownLatch startSecondThread = new CountDownLatch(1); + CountDownLatch testComplete = new CountDownLatch(1); + + AtomicBoolean firstThreadAcquiredLock = new AtomicBoolean(false); + AtomicBoolean secondThreadAcquiredLock = new AtomicBoolean(false); + AtomicBoolean firstThreadSavedWidget = new AtomicBoolean(false); + AtomicBoolean secondThreadSavedWidget = new AtomicBoolean(false); + + Path widgetTypesDir = tempDir.resolve("widget_types"); + Files.createDirectories(widgetTypesDir); + when(installScripts.getWidgetTypesDir()).thenReturn(widgetTypesDir); + + WidgetTypeDetails fileWidget = createTestWidgetType("test_widget", "Test Widget"); + fileWidget.setDescriptor(JacksonUtil.toJsonNode("{\"type\":\"latest\",\"version\":2}")); + String toString = JacksonUtil.toCanonicalString(fileWidget); + assertNotNull(toString); + Files.writeString(widgetTypesDir.resolve("test_widget.json"), toString); + + WidgetTypeDetails existingWidget = createTestWidgetType("test_widget", "Test Widget"); + existingWidget.setId(new WidgetTypeId(UUID.randomUUID())); + existingWidget.setDescriptor(JacksonUtil.toJsonNode("{\"type\":\"latest\",\"version\":1}")); + + when(widgetTypeService.findWidgetTypeDetailsByTenantIdAndFqn(TenantId.SYS_TENANT_ID, "test_widget")).thenReturn(existingWidget); + + when(jdbcTemplate.queryForObject(contains("pg_try_advisory_lock"), eq(Boolean.class), anyLong())) + .thenReturn(true) + .thenReturn(false); + + when(jdbcTemplate.queryForObject(contains("pg_advisory_unlock"), eq(Boolean.class), anyLong())) + .thenReturn(true); + + // The first thread-acquires lock and performs update + Thread firstThread = new Thread(() -> { + try { + Boolean acquired = ReflectionTestUtils.invokeMethod(reconciler, "acquireAdvisoryLock"); + firstThreadAcquiredLock.set(Boolean.TRUE.equals(acquired)); + + if (firstThreadAcquiredLock.get()) { + lockAcquired.countDown(); + startSecondThread.await(5, TimeUnit.SECONDS); + + // Simulate work while holding lock + Thread.sleep(100); + + Integer updated = ReflectionTestUtils.invokeMethod(reconciler, "updateWidgetTypes"); + firstThreadSavedWidget.set(updated != null && updated > 0); + + ReflectionTestUtils.invokeMethod(reconciler, "releaseAdvisoryLock"); + } + } catch (Exception ignored) { + } finally { + testComplete.countDown(); + } + }); + + // Second thread - attempts to acquire lock but fails + Thread secondThread = new Thread(() -> { + try { + lockAcquired.await(5, TimeUnit.SECONDS); + startSecondThread.countDown(); + + Boolean acquired = ReflectionTestUtils.invokeMethod(reconciler, "acquireAdvisoryLock"); + secondThreadAcquiredLock.set(Boolean.TRUE.equals(acquired)); + + if (secondThreadAcquiredLock.get()) { + Integer updated = ReflectionTestUtils.invokeMethod(reconciler, "updateWidgetTypes"); + secondThreadSavedWidget.set(updated != null && updated > 0); + + ReflectionTestUtils.invokeMethod(reconciler, "releaseAdvisoryLock"); + } + } catch (Exception ignored) {} + }); + + firstThread.start(); + secondThread.start(); + + assertTrue(testComplete.await(10, TimeUnit.SECONDS), "Test should complete within timeout"); + firstThread.join(1000); + secondThread.join(1000); + + assertTrue(firstThreadAcquiredLock.get(), "First thread should acquire lock"); + assertFalse(secondThreadAcquiredLock.get(), "Second thread should NOT acquire lock"); + assertTrue(firstThreadSavedWidget.get(), "First thread should save widget"); + assertFalse(secondThreadSavedWidget.get(), "Second thread should NOT save widget"); + + verify(widgetTypeService, times(1)).saveWidgetType(any()); + } + + private static Stream provideDescriptorComparisonTestCases() { + return Stream.of( + Arguments.of("Both null", null, null, true), + Arguments.of("First null", null, JacksonUtil.newObjectNode(), false), + Arguments.of("Second null", JacksonUtil.newObjectNode(), null, false), + Arguments.of("Same content", + JacksonUtil.toJsonNode("{\"type\":\"latest\",\"version\":1}"), + JacksonUtil.toJsonNode("{\"type\":\"latest\",\"version\":1}"), + true), + Arguments.of("Different content", + JacksonUtil.toJsonNode("{\"type\":\"latest\",\"version\":1}"), + JacksonUtil.toJsonNode("{\"type\":\"latest\",\"version\":2}"), + false), + Arguments.of("Different key order but same content", + JacksonUtil.toJsonNode("{\"version\":1,\"type\":\"latest\"}"), + JacksonUtil.toJsonNode("{\"type\":\"latest\",\"version\":1}"), + true), + Arguments.of("Empty objects", + JacksonUtil.toJsonNode("{}"), + JacksonUtil.toJsonNode("{}"), + true) + ); + } + + private WidgetTypeDetails createTestWidgetType(String fqn, String name) { + WidgetTypeDetails widget = new WidgetTypeDetails(); + widget.setFqn(fqn); + widget.setName(name); + widget.setDescription("Test description"); + widget.setTenantId(TenantId.SYS_TENANT_ID); + widget.setDescriptor(JacksonUtil.toJsonNode("{\"type\":\"latest\"}")); + return widget; + } + +} diff --git a/application/src/test/java/org/thingsboard/server/system/sql/DeviceApiSqlTest.java b/application/src/test/java/org/thingsboard/server/system/sql/DeviceApiSqlTest.java index 74f3cbafd9..27e5237fd9 100644 --- a/application/src/test/java/org/thingsboard/server/system/sql/DeviceApiSqlTest.java +++ b/application/src/test/java/org/thingsboard/server/system/sql/DeviceApiSqlTest.java @@ -18,9 +18,6 @@ package org.thingsboard.server.system.sql; import org.thingsboard.server.dao.service.DaoSqlTest; import org.thingsboard.server.system.BaseHttpDeviceApiTest; -/** - * Created by Valerii Sosliuk on 6/27/2017. - */ @DaoSqlTest public class DeviceApiSqlTest extends BaseHttpDeviceApiTest { } diff --git a/application/src/test/java/org/thingsboard/server/system/sql/RestApiLimitsSqlTest.java b/application/src/test/java/org/thingsboard/server/system/sql/RestApiLimitsSqlTest.java index 56c26fb3d3..932fb32328 100644 --- a/application/src/test/java/org/thingsboard/server/system/sql/RestApiLimitsSqlTest.java +++ b/application/src/test/java/org/thingsboard/server/system/sql/RestApiLimitsSqlTest.java @@ -18,7 +18,6 @@ package org.thingsboard.server.system.sql; import org.thingsboard.server.dao.service.DaoSqlTest; import org.thingsboard.server.system.BaseRestApiLimitsTest; - @DaoSqlTest public class RestApiLimitsSqlTest extends BaseRestApiLimitsTest { } diff --git a/application/src/test/java/org/thingsboard/server/transport/coap/security/AbstractCoapSecurityIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/coap/security/AbstractCoapSecurityIntegrationTest.java index 72f8cc5b4f..839b8c7cad 100644 --- a/application/src/test/java/org/thingsboard/server/transport/coap/security/AbstractCoapSecurityIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/coap/security/AbstractCoapSecurityIntegrationTest.java @@ -64,6 +64,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers. "coap.server.enabled=true", "coap.dtls.enabled=true", "coap.dtls.credentials.pem.cert_file=coap/credentials/server/cert.pem", + "coap.dtls.x509.skip_validity_check_for_client_cert=true", "device.connectivity.coaps.enabled=true", "service.integrations.supported=ALL", "transport.coap.enabled=true", diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/AbstractLwM2MIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/AbstractLwM2MIntegrationTest.java index ddf8bca43f..b4c38f57bc 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/AbstractLwM2MIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/AbstractLwM2MIntegrationTest.java @@ -21,6 +21,7 @@ import com.google.gson.JsonArray; import com.google.gson.JsonElement; import lombok.extern.slf4j.Slf4j; import org.apache.commons.io.IOUtils; +import org.awaitility.core.ConditionTimeoutException; import org.eclipse.leshan.client.LeshanClient; import org.eclipse.leshan.client.object.Security; import org.eclipse.leshan.client.servers.LwM2mServer; @@ -94,6 +95,7 @@ import java.util.Map; import java.util.Set; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicLong; import static org.awaitility.Awaitility.await; import static org.eclipse.leshan.client.object.Security.noSec; @@ -118,6 +120,7 @@ import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.LwM2MClient import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.LwM2MClientState.ON_UPDATE_SUCCESS; import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.LwM2MProfileBootstrapConfigType; import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.LwM2MProfileBootstrapConfigType.NONE; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.lwm2mClientResources; import static org.thingsboard.server.transport.lwm2m.ota.AbstractOtaLwM2MIntegrationTest.CLIENT_LWM2M_SETTINGS_19; @TestPropertySource(properties = { @@ -306,7 +309,7 @@ public abstract class AbstractLwM2MIntegrationTest extends AbstractTransportInte protected final Set expectedStatusesRegistrationBsSuccess = new HashSet<>(Arrays.asList(ON_BOOTSTRAP_STARTED, ON_BOOTSTRAP_SUCCESS, ON_REGISTRATION_STARTED, ON_REGISTRATION_SUCCESS)); protected ScheduledExecutorService executor; protected LwM2MTestClient lwM2MTestClient; - private String[] resources; + private String[] resources = lwm2mClientResources; protected String deviceId; protected boolean supportFormatOnly_SenMLJSON_SenMLCBOR = false; @@ -548,7 +551,9 @@ public abstract class AbstractLwM2MIntegrationTest extends AbstractTransportInte } public void setResources(String[] resources) { - this.resources = resources; + if (this.resources == null || !Arrays.equals(this.resources, resources)) { + this.resources = resources; + } } public void createNewClient(Security security, Security securityBs, boolean isRpc, @@ -726,11 +731,19 @@ public abstract class AbstractLwM2MIntegrationTest extends AbstractTransportInte return credentials; } - protected void awaitObserveReadAll(int cntObserve, String deviceIdStr) throws Exception { - await("ObserveReadAll: countObserve " + cntObserve) - .atMost(40, TimeUnit.SECONDS) - .until(() -> cntObserve == getCntObserveAll(deviceIdStr)); + + protected void awaitObserveReadAll(int cntObserve, String deviceIdStr) throws Exception { + try { + await("ObserveReadAll: countObserve " + cntObserve) + .atMost(40, TimeUnit.SECONDS) + .until(() -> cntObserve == getCntObserveAll(deviceIdStr)); + } catch (ConditionTimeoutException e) { + int current = getCntObserveAll(deviceIdStr); + log.error("Condition or device {} with alias 'ObserveReadAll: countObserve {}, but received {}", deviceIdStr, cntObserve, current); + throw e; + } } + protected void awaitDeleteDevice(String deviceIdStr) throws Exception { await("Delete device with id: " + deviceIdStr) .atMost(40, TimeUnit.SECONDS) @@ -741,6 +754,19 @@ public abstract class AbstractLwM2MIntegrationTest extends AbstractTransportInte }); } + protected void updateRegAtLeastOnceAfterAction() { + long initialInvocationCount = countUpdateReg(); + AtomicLong newInvocationCount = new AtomicLong(initialInvocationCount); + log.trace("updateRegAtLeastOnceAfterAction: initialInvocationCount [{}]", initialInvocationCount); + await("Update Registration at-least-once after action") + .atMost(50, TimeUnit.SECONDS) + .until(() -> { + newInvocationCount.set(countUpdateReg()); + return newInvocationCount.get() > initialInvocationCount; + }); + log.trace("updateRegAtLeastOnceAfterAction: newInvocationCount [{}]", newInvocationCount.get()); + } + protected Integer getCntObserveAll(String deviceIdStr) throws Exception { String actualResult = sendObserveOK("ObserveReadAll", null, deviceIdStr); ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/Lwm2mTestHelper.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/Lwm2mTestHelper.java index 6159400bb6..83a9cd14c5 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/Lwm2mTestHelper.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/Lwm2mTestHelper.java @@ -17,7 +17,7 @@ package org.thingsboard.server.transport.lwm2m; public class Lwm2mTestHelper { - public static final String[] lwm2mClientResources = new String[]{"3.xml", "5.xml", "6.xml", "9.xml", "19.xml", "3303.xml"}; + public static final String[] lwm2mClientResources = new String[]{"3-1_2.xml", "5.xml", "6.xml", "9.xml", "19.xml", "3303.xml"}; // Models public static final int BINARY_APP_DATA_CONTAINER = 19; diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/FwLwM2MDevice.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/FwLwM2MDevice.java index 051a68c9ab..8e247a8814 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/FwLwM2MDevice.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/FwLwM2MDevice.java @@ -16,6 +16,7 @@ package org.thingsboard.server.transport.lwm2m.client; import lombok.extern.slf4j.Slf4j; +import org.eclipse.leshan.client.LeshanClient; import org.eclipse.leshan.client.resource.BaseInstanceEnabler; import org.eclipse.leshan.client.servers.LwM2mServer; import org.eclipse.leshan.core.model.ObjectModel; @@ -32,6 +33,9 @@ import java.util.List; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicInteger; +import static org.thingsboard.server.dao.service.OtaPackageServiceTest.TARGET_FW_VERSION; +import static org.thingsboard.server.dao.service.OtaPackageServiceTest.TITLE; @Slf4j public class FwLwM2MDevice extends BaseInstanceEnabler implements Destroyable { @@ -44,6 +48,12 @@ public class FwLwM2MDevice extends BaseInstanceEnabler implements Destroyable { private final AtomicInteger updateResult = new AtomicInteger(0); + private LeshanClient leshanClient; + private String pkgNameDef = "firmware"; + private String pkgName; + private String pkgVersionDef = "1.0.0"; + private String pkgVersion; + @Override public ReadResponse read(LwM2mServer identity, int resourceId) { if (!identity.isSystem()) @@ -74,7 +84,7 @@ public class FwLwM2MDevice extends BaseInstanceEnabler implements Destroyable { switch (resourceId) { case 2: - startUpdating(); + startUpdating(identity); return ExecuteResponse.success(); default: return super.execute(identity, resourceId, arguments); @@ -106,11 +116,13 @@ public class FwLwM2MDevice extends BaseInstanceEnabler implements Destroyable { } private String getPkgName() { - return "firmware"; + this.pkgName = this.pkgName == null ? this.pkgNameDef : this.pkgName; + return this.pkgName; } private String getPkgVersion() { - return "1.0.0"; + this.pkgVersion = this.pkgVersion == null ? this.pkgVersionDef : this.pkgVersion; + return this.pkgVersion; } private int getFirmwareUpdateDeliveryMethod() { @@ -140,7 +152,7 @@ public class FwLwM2MDevice extends BaseInstanceEnabler implements Destroyable { }, 100, TimeUnit.MILLISECONDS); } - private void startUpdating() { + private void startUpdating(LwM2mServer identity) { scheduler.schedule(() -> { try { state.set(3); @@ -148,9 +160,25 @@ public class FwLwM2MDevice extends BaseInstanceEnabler implements Destroyable { Thread.sleep(100); updateResult.set(1); fireResourceChange(5); + this.pkgName = TITLE; + fireResourceChange(6); + this.pkgVersion = TARGET_FW_VERSION; + fireResourceChange(7); + if (this.leshanClient != null) { + log.info("Stop/reboot LwM2M client {}", this.leshanClient.getEndpoint(identity)); + this.leshanClient.stop(false); + log.info("Start after update fw LwM2M client {}", this.leshanClient.getEndpoint(identity)); + this.leshanClient.start(); + this.pkgName = this.pkgNameDef; + this.pkgVersion = this.pkgVersionDef; + } } catch (Exception e) { } }, 100, TimeUnit.MILLISECONDS); } + protected void setLeshanClient(LeshanClient leshanClient) { + this.leshanClient = leshanClient; + } + } diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2MTestClient.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2MTestClient.java index 2ae1432cac..3dc87cf245 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2MTestClient.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2MTestClient.java @@ -470,6 +470,7 @@ public class LwM2MTestClient { this.awaitClientAfterStartConnectLw(); } lwM2mTemperatureSensor12.setLeshanClient(leshanClient); + fwLwM2MDevice.setLeshanClient(leshanClient); } } diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/ota/AbstractOtaLwM2MIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/ota/AbstractOtaLwM2MIntegrationTest.java index a67f3cf00f..0681f00d27 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/ota/AbstractOtaLwM2MIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/ota/AbstractOtaLwM2MIntegrationTest.java @@ -16,14 +16,10 @@ package org.thingsboard.server.transport.lwm2m.ota; import com.fasterxml.jackson.core.type.TypeReference; -import com.fasterxml.jackson.databind.node.ObjectNode; -import com.github.dockerjava.zerodep.shaded.org.apache.commons.codec.binary.Hex; import lombok.extern.slf4j.Slf4j; -import org.eclipse.leshan.core.ResponseCode; import org.springframework.mock.web.MockMultipartFile; import org.springframework.test.web.servlet.request.MockMultipartHttpServletRequestBuilder; import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; -import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.OtaPackageInfo; import org.thingsboard.server.common.data.id.DeviceProfileId; @@ -35,30 +31,21 @@ import org.thingsboard.server.transport.lwm2m.AbstractLwM2MIntegrationTest; import java.util.Comparator; import java.util.List; -import java.util.Optional; import java.util.UUID; import java.util.stream.Collectors; -import static org.junit.Assert.assertEquals; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import static org.thingsboard.rest.client.utils.RestJsonConverter.toTimeseries; import static org.thingsboard.server.common.data.ota.OtaPackageType.FIRMWARE; import static org.thingsboard.server.common.data.ota.OtaPackageType.SOFTWARE; -import static org.thingsboard.server.transport.lwm2m.server.ota.DefaultLwM2MOtaUpdateService.OTA_INFO_19_FILE_CHECKSUM256; -import static org.thingsboard.server.transport.lwm2m.server.ota.DefaultLwM2MOtaUpdateService.OTA_INFO_19_FILE_NAME; -import static org.thingsboard.server.transport.lwm2m.server.ota.DefaultLwM2MOtaUpdateService.OTA_INFO_19_FILE_SIZE; -import static org.thingsboard.server.transport.lwm2m.server.ota.DefaultLwM2MOtaUpdateService.OTA_INFO_19_TITLE; -import static org.thingsboard.server.transport.lwm2m.server.ota.DefaultLwM2MOtaUpdateService.OTA_INFO_19_VERSION; @Slf4j @DaoSqlTest public abstract class AbstractOtaLwM2MIntegrationTest extends AbstractLwM2MIntegrationTest { - private final String[] RESOURCES_OTA = new String[]{"3.xml", "5.xml", "9.xml", "19.xml"}; protected static final String CLIENT_ENDPOINT_WITHOUT_FW_INFO = "WithoutFirmwareInfoDevice"; protected static final String CLIENT_ENDPOINT_OTA5 = "Ota5_Device"; protected static final String CLIENT_ENDPOINT_OTA9 = "Ota9_Device"; - protected static final String CLIENT_ENDPOINT_OTA9_19 = "Ota9_Device_19"; protected List expectedStatuses; protected final String OBSERVE_ATTRIBUTES_WITH_PARAMS_OTA5 = @@ -89,37 +76,6 @@ public abstract class AbstractOtaLwM2MIntegrationTest extends AbstractLwM2MInteg " \"attributeLwm2m\": {}\n" + " }"; - protected final String OBSERVE_ATTRIBUTES_WITH_PARAMS_OTA5_19 = - - " {\n" + - " \"keyName\": {\n" + - " \"/5_1.2/0/3\": \"state\",\n" + - " \"/5_1.2/0/5\": \"updateResult\",\n" + - " \"/5_1.2/0/6\": \"pkgname\",\n" + - " \"/5_1.2/0/7\": \"pkgversion\",\n" + - " \"/5_1.2/0/9\": \"firmwareUpdateDeliveryMethod\",\n" + - " \"/19_1.1/0/0\": \"dataRead\"\n" + - " },\n" + - " \"observe\": [\n" + - " \"/5_1.2/0/3\",\n" + - " \"/5_1.2/0/5\",\n" + - " \"/5_1.2/0/6\",\n" + - " \"/5_1.2/0/7\",\n" + - " \"/5_1.2/0/9\",\n" + - " \"/19_1.1/0/0\"\n" + - " ],\n" + - " \"attribute\": [],\n" + - " \"telemetry\": [\n" + - " \"/5_1.2/0/3\",\n" + - " \"/5_1.2/0/5\",\n" + - " \"/5_1.2/0/6\",\n" + - " \"/5_1.2/0/7\",\n" + - " \"/5_1.2/0/9\",\n" + - " \"/19_1.1/0/0\"\n" + - " ],\n" + - " \"attributeLwm2m\": {}\n" + - " }"; - public static final String CLIENT_LWM2M_SETTINGS_19 = " {\n" + " \"useObject19ForOtaInfo\": true,\n" + @@ -186,10 +142,6 @@ public abstract class AbstractOtaLwM2MIntegrationTest extends AbstractLwM2MInteg " \"attributeLwm2m\": {}\n" + " }"; - public AbstractOtaLwM2MIntegrationTest() { - setResources(this.RESOURCES_OTA); - } - protected OtaPackageInfo createFirmware(String version, DeviceProfileId deviceProfileId) throws Exception { String CHECKSUM = "4bf5122f344554c53bde2ebb8cd2b7e3d1600ad631c385a5d7cce23c7785459a"; @@ -252,27 +204,4 @@ public abstract class AbstractOtaLwM2MIntegrationTest extends AbstractLwM2MInteg log.warn("{}", statuses); return statuses.containsAll(expectedStatuses); } - - protected void resultReadOtaParams_19(String resourceIdVer, OtaPackageInfo otaPackageInfo) throws Exception { - String actualResult = sendRPCById(resourceIdVer); - ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); - assertEquals(ResponseCode.CONTENT.getName(), rpcActualResult.get("result").asText()); - String valStr = rpcActualResult.get("value").asText(); - String start = "{ id=0 value="; - String valHexDec = valStr.substring(valStr.indexOf(start) + start.length(), (valStr.indexOf("}"))); - String valNode = new String(Hex.decodeHex((valHexDec).toCharArray())); - ObjectNode actualResultVal = JacksonUtil.fromString(valNode, ObjectNode.class); - assert actualResultVal != null; - assertEquals(otaPackageInfo.getTitle(), actualResultVal.get(OTA_INFO_19_TITLE).asText()); - assertEquals(otaPackageInfo.getVersion(), actualResultVal.get(OTA_INFO_19_VERSION).asText()); - assertEquals(otaPackageInfo.getChecksum(), actualResultVal.get(OTA_INFO_19_FILE_CHECKSUM256).asText()); - assertEquals(otaPackageInfo.getFileName(), actualResultVal.get(OTA_INFO_19_FILE_NAME).asText()); - assertEquals(Optional.of(otaPackageInfo.getDataSize()), Optional.of((long) actualResultVal.get(OTA_INFO_19_FILE_SIZE).asInt())); - } - - private String sendRPCById(String path) throws Exception { - String setRpcRequest = "{\"method\": \"Read\", \"params\": {\"id\": \"" + path + "\"}}"; - return doPostAsync("/api/plugins/rpc/twoway/" + lwM2MTestClient.getDeviceIdStr(), setRpcRequest, String.class, status().isOk()); - } - } diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/ota/sql/Ota5LwM2MIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/ota/sql/Ota5LwM2MIntegrationTest.java index 3065255687..0943491045 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/ota/sql/Ota5LwM2MIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/ota/sql/Ota5LwM2MIntegrationTest.java @@ -21,7 +21,6 @@ import org.junit.Assert; import org.junit.Test; import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.DeviceProfile; -import org.thingsboard.server.common.data.OtaPackageInfo; import org.thingsboard.server.common.data.device.credentials.lwm2m.LwM2MDeviceCredentials; import org.thingsboard.server.common.data.device.profile.Lwm2mDeviceProfileTransportConfiguration; import org.thingsboard.server.common.data.kv.KvEntry; @@ -45,10 +44,8 @@ import static org.thingsboard.server.common.data.ota.OtaPackageUpdateStatus.INIT import static org.thingsboard.server.common.data.ota.OtaPackageUpdateStatus.QUEUED; import static org.thingsboard.server.common.data.ota.OtaPackageUpdateStatus.UPDATED; import static org.thingsboard.server.common.data.ota.OtaPackageUpdateStatus.UPDATING; -import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.BINARY_APP_DATA_CONTAINER; +import static org.thingsboard.server.dao.service.OtaPackageServiceTest.TARGET_FW_VERSION; import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.LwM2MProfileBootstrapConfigType.NONE; -import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.RESOURCE_ID_0; -import static org.thingsboard.server.transport.lwm2m.server.ota.DefaultLwM2MOtaUpdateService.FW_INSTANCE_ID; @Slf4j public class Ota5LwM2MIntegrationTest extends AbstractOtaLwM2MIntegrationTest { @@ -91,13 +88,14 @@ public class Ota5LwM2MIntegrationTest extends AbstractOtaLwM2MIntegrationTest { @Test public void testFirmwareUpdateByObject5_Ok() throws Exception { Lwm2mDeviceProfileTransportConfiguration transportConfiguration = getTransportConfiguration(OBSERVE_ATTRIBUTES_WITH_PARAMS_OTA5, getBootstrapServerCredentialsNoSec(NONE)); - DeviceProfile deviceProfile = createLwm2mDeviceProfile("profileFor" + this.CLIENT_ENDPOINT_OTA5, transportConfiguration); - LwM2MDeviceCredentials deviceCredentials = getDeviceCredentialsNoSec(createNoSecClientCredentials(this.CLIENT_ENDPOINT_OTA5)); - final Device device = createLwm2mDevice(deviceCredentials, this.CLIENT_ENDPOINT_OTA5, deviceProfile.getId()); - createNewClient(SECURITY_NO_SEC, null, false, this.CLIENT_ENDPOINT_OTA5, device.getId().getId().toString()); + DeviceProfile deviceProfile = createLwm2mDeviceProfile("profileFor" + this.CLIENT_ENDPOINT_OTA5 + "Ok", transportConfiguration); + String endpoint = this.CLIENT_ENDPOINT_OTA5 + "Ok"; + LwM2MDeviceCredentials deviceCredentials = getDeviceCredentialsNoSec(createNoSecClientCredentials(endpoint)); + final Device device = createLwm2mDevice(deviceCredentials, endpoint, deviceProfile.getId()); + createNewClient(SECURITY_NO_SEC, null, false, endpoint, device.getId().getId().toString()); awaitObserveReadAll(5, device.getId().getId().toString()); - device.setFirmwareId(createFirmware("fw.v.1.5.0-update", deviceProfile.getId()).getId()); + device.setFirmwareId(createFirmware(TARGET_FW_VERSION, deviceProfile.getId()).getId()); final Device savedDevice = doPost("/api/device", device, Device.class); assertThat(savedDevice).as("saved device").isNotNull(); @@ -109,51 +107,4 @@ public class Ota5LwM2MIntegrationTest extends AbstractOtaLwM2MIntegrationTest { .until(() -> getFwSwStateTelemetryFromAPI(device.getId().getId(), "fw_state"), this::predicateForStatuses); log.warn("Object5: Got the ts: {}", ts); } - - - /** - * ObjectId = 19/65533/0 - * { - * "title" : "My firmware", - * "version" : "fw.v.1.5.0-update", - * "checksum" : "4bf5122f344554c53bde2ebb8cd2b7e3d1600ad631c385a5d7cce23c7785459a", - * "fileSize" : 1, - * "fileName" : "filename.txt" - * } - * to base64 - * /5/0/5 -> Update Result (Res); 5/0/3 -> State; - * => ((Res>=0 && Res<=9) && State=0) - * => Write to Package/Write to Package URI -> DOWNLOADING ((Res>=0 && Res<=9) && State=1) - * => Download Finished -> DOWNLOADED ((Res==0 || Res=8) && State=2) - * => Executable resource Update is triggered / Initiate Firmware Update -> UPDATING (Res=0 && State=3) - * => Update Successful [Res==1] - * => Start / Res=0 -> "IDLE" .... - * @throws Exception - */ - @Test - public void testFirmwareUpdateByObject5WithObject19_Ok() throws Exception { - Lwm2mDeviceProfileTransportConfiguration transportConfiguration = getTransportConfiguration19(OBSERVE_ATTRIBUTES_WITH_PARAMS_OTA5_19, getBootstrapServerCredentialsNoSec(NONE)); - DeviceProfile deviceProfile = createLwm2mDeviceProfile("profileFor" + this.CLIENT_ENDPOINT_OTA5, transportConfiguration); - LwM2MDeviceCredentials deviceCredentials = getDeviceCredentialsNoSec(createNoSecClientCredentials(this.CLIENT_ENDPOINT_OTA5)); - final Device device = createLwm2mDevice(deviceCredentials, this.CLIENT_ENDPOINT_OTA5, deviceProfile.getId()); - createNewClient(SECURITY_NO_SEC, null, false, this.CLIENT_ENDPOINT_OTA5, device.getId().getId().toString()); - awaitObserveReadAll(6, device.getId().getId().toString()); - - OtaPackageInfo otaPackageInfo = createFirmware("fw.v.1.5.0-update", deviceProfile.getId()); - device.setFirmwareId(otaPackageInfo.getId()); - final Device savedDevice = doPost("/api/device", device, Device.class); - - assertThat(savedDevice).as("saved device").isNotNull(); - assertThat(getDeviceFromAPI(device.getId().getId())).as("fetched device").isEqualTo(savedDevice); - - expectedStatuses = Arrays.asList(QUEUED, INITIATED, DOWNLOADING, DOWNLOADED, UPDATING, UPDATED); - List ts = await("await on timeseries for FW") - .atMost(TIMEOUT, TimeUnit.SECONDS) - .until(() -> getFwSwStateTelemetryFromAPI(device.getId().getId(), "fw_state"), this::predicateForStatuses); - - String ver_Id_19 = lwM2MTestClient.getLeshanClient().getObjectTree().getModel().getObjectModel(BINARY_APP_DATA_CONTAINER).version; - String resourceIdVer = "/" + BINARY_APP_DATA_CONTAINER + "_" + ver_Id_19 + "/" + FW_INSTANCE_ID + "/" + RESOURCE_ID_0; - resultReadOtaParams_19(resourceIdVer, otaPackageInfo); - log.warn("Object5: Got the ts: {}", ts); - } } diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/ota/sql/Ota9LwM2MIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/ota/sql/Ota9LwM2MIntegrationTest.java index b2617dd7ba..5371a6a3c0 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/ota/sql/Ota9LwM2MIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/ota/sql/Ota9LwM2MIntegrationTest.java @@ -19,7 +19,6 @@ import lombok.extern.slf4j.Slf4j; import org.junit.Test; import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.DeviceProfile; -import org.thingsboard.server.common.data.OtaPackageInfo; import org.thingsboard.server.common.data.device.credentials.lwm2m.LwM2MDeviceCredentials; import org.thingsboard.server.common.data.device.profile.Lwm2mDeviceProfileTransportConfiguration; import org.thingsboard.server.common.data.kv.TsKvEntry; @@ -36,10 +35,7 @@ import static org.thingsboard.server.common.data.ota.OtaPackageUpdateStatus.INIT import static org.thingsboard.server.common.data.ota.OtaPackageUpdateStatus.QUEUED; import static org.thingsboard.server.common.data.ota.OtaPackageUpdateStatus.UPDATED; import static org.thingsboard.server.common.data.ota.OtaPackageUpdateStatus.VERIFIED; -import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.BINARY_APP_DATA_CONTAINER; import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.LwM2MProfileBootstrapConfigType.NONE; -import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.RESOURCE_ID_0; -import static org.thingsboard.server.transport.lwm2m.server.ota.DefaultLwM2MOtaUpdateService.SW_INSTANCE_ID; @Slf4j public class Ota9LwM2MIntegrationTest extends AbstractOtaLwM2MIntegrationTest { @@ -51,7 +47,8 @@ public class Ota9LwM2MIntegrationTest extends AbstractOtaLwM2MIntegrationTest { * => PKG integrity verified -> DELIVERED (Res=3 (Successfully Downloaded and package integrity verified) && State=3) -> INSTALLED; * => Install -> INSTALLED (Res=2 SW successfully installed) && State=4) -> Start * - * */ + * + */ @Test public void testSoftwareUpdateByObject9() throws Exception { String clientEndpoint = this.CLIENT_ENDPOINT_OTA9; @@ -75,47 +72,4 @@ public class Ota9LwM2MIntegrationTest extends AbstractOtaLwM2MIntegrationTest { .until(() -> getFwSwStateTelemetryFromAPI(device.getId().getId(), "sw_state"), this::predicateForStatuses); log.warn("Object9: Got the ts: {}", ts); } - /** - * ObjectId = 19/65534/0 - * { - * "title" : "My sw", - * "version" : "v1.0.19", - * "checksum" : "4bf5122f344554c53bde2ebb8cd2b7e3d1600ad631c385a5d7cce23c7785459a", - * "fileSize" : 1, - * "fileName" : "filename.txt" - * } - * => Start -> INITIAL (State=0) -> DOWNLOAD STARTED; - * => PKG / URI Write -> DOWNLOAD STARTED (Res=1 (Downloading) && State=1) -> DOWNLOADED - * => PKG Written -> DOWNLOADED (Res=1 Initial && State=2) -> DELIVERED; - * => PKG integrity verified -> DELIVERED (Res=3 (Successfully Downloaded and package integrity verified) && State=3) -> INSTALLED; - * => Install -> INSTALLED (Res=2 SW successfully installed) && State=4) -> Start - * - * */ - @Test - public void testSoftwareUpdateByObject9WithObject19_Ok() throws Exception { - String clientEndpoint = this.CLIENT_ENDPOINT_OTA9_19; - Lwm2mDeviceProfileTransportConfiguration transportConfiguration = getTransportConfiguration19(OBSERVE_ATTRIBUTES_WITH_PARAMS_OTA9_19, getBootstrapServerCredentialsNoSec(NONE)); - DeviceProfile deviceProfile = createLwm2mDeviceProfile("profileFor" + clientEndpoint, transportConfiguration); - LwM2MDeviceCredentials deviceCredentials = getDeviceCredentialsNoSec(createNoSecClientCredentials(clientEndpoint)); - final Device device = createLwm2mDevice(deviceCredentials, clientEndpoint, deviceProfile.getId()); - createNewClient(SECURITY_NO_SEC, null, false, clientEndpoint, device.getId().getId().toString()); - awaitObserveReadAll(5, device.getId().getId().toString()); - OtaPackageInfo otaPackageInfo = createSoftware(deviceProfile.getId(), "v1.0.19"); - device.setSoftwareId(otaPackageInfo.getId()); - final Device savedDevice = doPost("/api/device", device, Device.class); //sync call - - assertThat(savedDevice).as("saved device").isNotNull(); - assertThat(getDeviceFromAPI(device.getId().getId())).as("fetched device").isEqualTo(savedDevice); - - expectedStatuses = List.of( - QUEUED, INITIATED, DOWNLOADING, DOWNLOADING, DOWNLOADING, DOWNLOADED, VERIFIED, UPDATED); - List ts = await("await on timeseries") - .atMost(TIMEOUT, TimeUnit.SECONDS) - .until(() -> getFwSwStateTelemetryFromAPI(device.getId().getId(), "sw_state"), this::predicateForStatuses); - - String ver_Id_19 = lwM2MTestClient.getLeshanClient().getObjectTree().getModel().getObjectModel(BINARY_APP_DATA_CONTAINER).version; - String resourceIdVer = "/" + BINARY_APP_DATA_CONTAINER + "_" + ver_Id_19 + "/" + SW_INSTANCE_ID + "/" + RESOURCE_ID_0; - resultReadOtaParams_19(resourceIdVer, otaPackageInfo); - log.warn("Object9: Got the ts: {}", ts); - } } diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/AbstractRpcLwM2MIntegrationObserve_Ver_1_0_Test.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/AbstractRpcLwM2MIntegrationObserve_Ver_1_0_Test.java index 7e9efbbf75..f333fd012c 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/AbstractRpcLwM2MIntegrationObserve_Ver_1_0_Test.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/AbstractRpcLwM2MIntegrationObserve_Ver_1_0_Test.java @@ -20,9 +20,8 @@ import org.thingsboard.server.dao.service.DaoSqlTest; @DaoSqlTest public abstract class AbstractRpcLwM2MIntegrationObserve_Ver_1_0_Test extends AbstractRpcLwM2MIntegrationTest{ - public AbstractRpcLwM2MIntegrationObserve_Ver_1_0_Test() { - String[] RESOURCES_RPC_VER_1_1 = new String[]{"3-1_0.xml", "5.xml", "6.xml", "9.xml", "19.xml"}; - setResources(RESOURCES_RPC_VER_1_1); + public AbstractRpcLwM2MIntegrationObserve_Ver_1_0_Test() throws Exception { + String[] RESOURCES_RPC_VER_1_0 = new String[]{"3-1_0.xml", "5.xml", "6.xml", "9.xml", "19.xml"}; + setResources(RESOURCES_RPC_VER_1_0); } } - diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/AbstractRpcLwM2MIntegrationObserve_Ver_1_1_Test.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/AbstractRpcLwM2MIntegrationObserve_Ver_1_1_Test.java index f21c857e8a..b39b3d1130 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/AbstractRpcLwM2MIntegrationObserve_Ver_1_1_Test.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/AbstractRpcLwM2MIntegrationObserve_Ver_1_1_Test.java @@ -20,7 +20,7 @@ import org.thingsboard.server.dao.service.DaoSqlTest; @DaoSqlTest public abstract class AbstractRpcLwM2MIntegrationObserve_Ver_1_1_Test extends AbstractRpcLwM2MIntegrationTest{ - public AbstractRpcLwM2MIntegrationObserve_Ver_1_1_Test() { + public AbstractRpcLwM2MIntegrationObserve_Ver_1_1_Test() throws Exception { String[] RESOURCES_RPC_VER_1_1 = new String[]{"3-1_1.xml", "5.xml", "6.xml", "9.xml", "19.xml"}; setResources(RESOURCES_RPC_VER_1_1); } diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/AbstractRpcLwM2MIntegrationObserve_Ver_1_2_Test.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/AbstractRpcLwM2MIntegrationObserve_Ver_1_2_Test.java index 347d04a900..8c07379004 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/AbstractRpcLwM2MIntegrationObserve_Ver_1_2_Test.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/AbstractRpcLwM2MIntegrationObserve_Ver_1_2_Test.java @@ -20,9 +20,9 @@ import org.thingsboard.server.dao.service.DaoSqlTest; @DaoSqlTest public abstract class AbstractRpcLwM2MIntegrationObserve_Ver_1_2_Test extends AbstractRpcLwM2MIntegrationTest{ - public AbstractRpcLwM2MIntegrationObserve_Ver_1_2_Test() { - String[] RESOURCES_RPC_VER_1_1 = new String[]{"3.xml", "5.xml", "6.xml", "9.xml", "19.xml"}; - setResources(RESOURCES_RPC_VER_1_1); + public AbstractRpcLwM2MIntegrationObserve_Ver_1_2_Test() throws Exception { + String[] RESOURCES_RPC_VER_1_2 = new String[]{"3-1_2.xml", "5.xml", "6.xml", "9.xml", "19.xml"}; + setResources(RESOURCES_RPC_VER_1_2); } } diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/AbstractRpcLwM2MIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/AbstractRpcLwM2MIntegrationTest.java index be85294f08..508878d584 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/AbstractRpcLwM2MIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/AbstractRpcLwM2MIntegrationTest.java @@ -15,7 +15,9 @@ */ package org.thingsboard.server.transport.lwm2m.rpc; +import com.fasterxml.jackson.databind.node.ObjectNode; import lombok.extern.slf4j.Slf4j; +import org.eclipse.leshan.core.ResponseCode; import org.eclipse.leshan.core.link.LinkParser; import org.eclipse.leshan.core.link.lwm2m.DefaultLwM2mLinkParser; import org.junit.Before; @@ -40,6 +42,9 @@ import java.util.concurrent.atomic.AtomicLong; import java.util.function.Predicate; import static org.awaitility.Awaitility.await; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import static org.eclipse.leshan.core.LwM2mId.ACCESS_CONTROL; import static org.eclipse.leshan.core.LwM2mId.DEVICE; import static org.eclipse.leshan.core.LwM2mId.FIRMWARE; @@ -102,10 +107,6 @@ public abstract class AbstractRpcLwM2MIntegrationTest extends AbstractLwM2MInteg @SpyBean protected LwM2mTransportServerHelper lwM2mTransportServerHelperTest; - public AbstractRpcLwM2MIntegrationTest() { - setResources(lwm2mClientResources); - } - @Before public void startInitRPC() throws Exception { if (this.getClass().getSimpleName().equals("RpcLwm2mIntegrationWriteCborTest")) { @@ -264,19 +265,6 @@ public abstract class AbstractRpcLwM2MIntegrationTest extends AbstractLwM2MInteg .count(); } - protected void updateRegAtLeastOnceAfterAction() { - long initialInvocationCount = countUpdateReg(); - AtomicLong newInvocationCount = new AtomicLong(initialInvocationCount); - log.trace("updateRegAtLeastOnceAfterAction: initialInvocationCount [{}]", initialInvocationCount); - await("Update Registration at-least-once after action") - .atMost(50, TimeUnit.SECONDS) - .until(() -> { - newInvocationCount.set(countUpdateReg()); - return newInvocationCount.get() > initialInvocationCount; - }); - log.trace("updateRegAtLeastOnceAfterAction: newInvocationCount [{}]", newInvocationCount.get()); - } - protected long countSendParametersOnThingsboardTelemetryResource(String rezName) { return Mockito.mockingDetails(lwM2mTransportServerHelperTest) .getInvocations().stream() @@ -290,4 +278,36 @@ public abstract class AbstractRpcLwM2MIntegrationTest extends AbstractLwM2MInteg ) .count(); } + + protected String sendDiscover(String path) throws Exception { + String setRpcRequest = "{\"method\": \"Discover\", \"params\": {\"id\": \"" + path + "\"}}"; + return doPostAsync("/api/plugins/rpc/twoway/" + lwM2MTestClient.getDeviceIdStr(), setRpcRequest, String.class, status().isOk()); + } + + protected String sendRpcObserveReadAllWithResult() throws Exception { + ObjectNode rpcActualResult = sendRpcObserveWithResult("ObserveReadAll", null); + assertEquals(ResponseCode.CONTENT.getName(), rpcActualResult.get("result").asText()); + return rpcActualResult.get("value").asText(); + } + + protected String sendRpcObserveReadAllWithResult(String params) throws Exception { + sendRpcObserveOk("Observe", params); + ObjectNode rpcActualResult = sendRpcObserveWithResult("ObserveReadAll", null); + assertEquals(ResponseCode.CONTENT.getName(), rpcActualResult.get("result").asText()); + return rpcActualResult.get("value").asText(); + } + + protected void testObserveOneResourceValue_Count_4_CancelAll_Reboot_After_Observe_Count_4(String expectedIdVer) throws Exception { + String expectedIdObserve = "SingleObservation:/3/0/9"; + sendObserveCancelAllWithAwait(lwM2MTestClient.getDeviceIdStr()); + updateRegAtLeastOnceAfterAction(); + lwM2MTestClient.getLeshanClient().stop(false); + lwM2MTestClient.getLeshanClient().start(); + updateRegAtLeastOnceAfterAction(); + awaitObserveReadAll(4,lwM2MTestClient.getDeviceIdStr()); + String actualIdVer = sendDiscover(objectIdVer_3); + assertTrue(actualIdVer.contains(expectedIdVer)); + String actualAllObserve = sendRpcObserveReadAllWithResult(); + assertTrue(actualAllObserve.contains(expectedIdObserve)); + } } diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationDiscoverTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationDiscoverTest.java index dceadfb7b5..77960b1c54 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationDiscoverTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationDiscoverTest.java @@ -192,11 +192,6 @@ public class RpcLwm2mIntegrationDiscoverTest extends AbstractRpcLwM2MIntegration assertTrue(rpcActualResult.get("error").asText().contains(expected)); } - private String sendDiscover(String path) throws Exception { - String setRpcRequest = "{\"method\": \"Discover\", \"params\": {\"id\": \"" + path + "\"}}"; - return doPostAsync("/api/plugins/rpc/twoway/" + lwM2MTestClient.getDeviceIdStr(), setRpcRequest, String.class, status().isOk()); - } - private String convertObjectIdToVerId(String path, String ver) { ver = ver != null ? ver : TbLwM2mVersion.VERSION_1_0.getVersion().toString(); try { diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationDiscoverWriteAttributesTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationDiscoverWriteAttributesTest.java index bd1216eb06..2a4a401107 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationDiscoverWriteAttributesTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationDiscoverWriteAttributesTest.java @@ -166,9 +166,4 @@ public class RpcLwm2mIntegrationDiscoverWriteAttributesTest extends AbstractRpcL String setRpcRequest = "{\"method\": \"WriteAttributes\", \"params\": {\"id\": \"" + path + "\", \"attributes\": " + value + " }}"; return doPostAsync("/api/plugins/rpc/twoway/" + lwM2MTestClient.getDeviceIdStr(), setRpcRequest, String.class, status().isOk()); } - - private String sendDiscover(String path) throws Exception { - String setRpcRequest = "{\"method\": \"Discover\", \"params\": {\"id\": \"" + path + "\"}}"; - return doPostAsync("/api/plugins/rpc/twoway/" + lwM2MTestClient.getDeviceIdStr(), setRpcRequest, String.class, status().isOk()); - } } diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationObserveTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationObserveTest.java index 483442382d..505cebff69 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationObserveTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationObserveTest.java @@ -335,12 +335,5 @@ public class RpcLwm2mIntegrationObserveTest extends AbstractRpcLwM2MIntegrationT sendRpcObserveOk("Observe", expectedId_1); sendRpcObserveOk("Observe", expectedId_2); } - - private String sendRpcObserveReadAllWithResult(String params) throws Exception { - sendRpcObserveOk("Observe", params); - ObjectNode rpcActualResult = sendRpcObserveWithResult("ObserveReadAll", null); - assertEquals(ResponseCode.CONTENT.getName(), rpcActualResult.get("result").asText()); - return rpcActualResult.get("value").asText(); - } } diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationObserve_Ver_1_0_Test.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationObserveVer10Test.java similarity index 71% rename from application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationObserve_Ver_1_0_Test.java rename to application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationObserveVer10Test.java index 3d3640cb2e..e6f035e5cc 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationObserve_Ver_1_0_Test.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationObserveVer10Test.java @@ -19,13 +19,14 @@ import lombok.extern.slf4j.Slf4j; import org.junit.Before; import org.junit.Test; import org.thingsboard.server.transport.lwm2m.rpc.AbstractRpcLwM2MIntegrationObserve_Ver_1_0_Test; -import org.thingsboard.server.transport.lwm2m.rpc.AbstractRpcLwM2MIntegrationObserve_Ver_1_1_Test; - import static org.junit.Assert.assertTrue; import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.RESOURCE_ID_NAME_3_9; @Slf4j -public class RpcLwm2mIntegrationObserve_Ver_1_0_Test extends AbstractRpcLwM2MIntegrationObserve_Ver_1_0_Test { +public class RpcLwm2mIntegrationObserveVer10Test extends AbstractRpcLwM2MIntegrationObserve_Ver_1_0_Test { + + public RpcLwm2mIntegrationObserveVer10Test() throws Exception { + } @Before public void setupObserveTest() throws Exception { @@ -44,5 +45,21 @@ public class RpcLwm2mIntegrationObserve_Ver_1_0_Test extends AbstractRpcLwM2MInt updateRegAtLeastOnceAfterAction(); long lastSendTelemetryAtCount = countSendParametersOnThingsboardTelemetryResource(RESOURCE_ID_NAME_3_9); assertTrue(lastSendTelemetryAtCount > initSendTelemetryAtCount); + awaitObserveReadAll(1,lwM2MTestClient.getDeviceIdStr()); + } + + /** + * "3_1.0/0/9" + * Observe count 4 + * CancelAll Observe + * Reboot + * Observe count 4 contains + * "/3_1.0" - Discover Object - find ver + * @throws Exception + */ + @Test + public void testObserveOneResourceValue_Count_4_CancelAll_Reboot_After_Observe_Count_4_ObjectVer_1_0() throws Exception { + String expectedIdVer = ";ver=1.0"; + testObserveOneResourceValue_Count_4_CancelAll_Reboot_After_Observe_Count_4(expectedIdVer); } } diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationObserve_Ver_1_1_Test.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationObserveVer11Test.java similarity index 72% rename from application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationObserve_Ver_1_1_Test.java rename to application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationObserveVer11Test.java index a4f7727773..a64ff43b92 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationObserve_Ver_1_1_Test.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationObserveVer11Test.java @@ -23,7 +23,10 @@ import static org.junit.Assert.assertTrue; import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.RESOURCE_ID_NAME_3_9; @Slf4j -public class RpcLwm2mIntegrationObserve_Ver_1_1_Test extends AbstractRpcLwM2MIntegrationObserve_Ver_1_1_Test { +public class RpcLwm2mIntegrationObserveVer11Test extends AbstractRpcLwM2MIntegrationObserve_Ver_1_1_Test { + + public RpcLwm2mIntegrationObserveVer11Test() throws Exception { + } @Before public void setupObserveTest() throws Exception { @@ -43,4 +46,19 @@ public class RpcLwm2mIntegrationObserve_Ver_1_1_Test extends AbstractRpcLwM2MInt long lastSendTelemetryAtCount = countSendParametersOnThingsboardTelemetryResource(RESOURCE_ID_NAME_3_9); assertTrue(lastSendTelemetryAtCount > initSendTelemetryAtCount); } + + /** + * "3_1.1/0/9" + * Observe count 4 + * CancelAll Observe + * Reboot + * Observe count 4 contains + * "/3" - Discover Object - find ver (lwm2mVersion == 1.1) + * @throws Exception + */ + @Test + public void testObserveOneResourceValue_Count_4_CancelAll_Reboot_After_Observe_Count_4_ObjectVer_1_1() throws Exception { + String expectedIdVer = ""; + testObserveOneResourceValue_Count_4_CancelAll_Reboot_After_Observe_Count_4(expectedIdVer); + } } diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationObserve_Ver_1_2_Test.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationObserveVer12Test.java similarity index 73% rename from application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationObserve_Ver_1_2_Test.java rename to application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationObserveVer12Test.java index a166e0139b..89062dd303 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationObserve_Ver_1_2_Test.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationObserveVer12Test.java @@ -18,14 +18,16 @@ package org.thingsboard.server.transport.lwm2m.rpc.sql; import lombok.extern.slf4j.Slf4j; import org.junit.Before; import org.junit.Test; -import org.thingsboard.server.transport.lwm2m.rpc.AbstractRpcLwM2MIntegrationObserve_Ver_1_0_Test; import org.thingsboard.server.transport.lwm2m.rpc.AbstractRpcLwM2MIntegrationObserve_Ver_1_2_Test; import static org.junit.Assert.assertTrue; import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.RESOURCE_ID_NAME_3_9; @Slf4j -public class RpcLwm2mIntegrationObserve_Ver_1_2_Test extends AbstractRpcLwM2MIntegrationObserve_Ver_1_2_Test { +public class RpcLwm2mIntegrationObserveVer12Test extends AbstractRpcLwM2MIntegrationObserve_Ver_1_2_Test { + + public RpcLwm2mIntegrationObserveVer12Test() throws Exception { + } @Before public void setupObserveTest() throws Exception { @@ -45,4 +47,19 @@ public class RpcLwm2mIntegrationObserve_Ver_1_2_Test extends AbstractRpcLwM2MInt long lastSendTelemetryAtCount = countSendParametersOnThingsboardTelemetryResource(RESOURCE_ID_NAME_3_9); assertTrue(lastSendTelemetryAtCount > initSendTelemetryAtCount); } + + /** + * "3_1.2/0/9" + * Observe count 4 + * CancelAll Observe + * Reboot + * Observe count 4 contains + * "/3_1.2" - Discover Object - find ver + * @throws Exception + */ + @Test + public void testObserveOneResourceValue_Count_4_CancelAll_Reboot_After_Observe_Count_4_ObjectVer_1_2() throws Exception { + String expectedIdVer = ";ver=1.2"; + testObserveOneResourceValue_Count_4_CancelAll_Reboot_After_Observe_Count_4(expectedIdVer); + } } diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/AbstractSecurityLwM2MIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/AbstractSecurityLwM2MIntegrationTest.java index 6dda2de9fe..60474f7fda 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/AbstractSecurityLwM2MIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/AbstractSecurityLwM2MIntegrationTest.java @@ -22,6 +22,7 @@ import org.eclipse.leshan.client.object.Security; import org.eclipse.leshan.core.ResponseCode; import org.eclipse.leshan.core.util.Hex; import org.junit.Assert; +import org.junit.Before; import org.springframework.test.web.servlet.MvcResult; import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.common.data.Device; @@ -119,7 +120,6 @@ public abstract class AbstractSecurityLwM2MIntegrationTest extends AbstractLwM2M protected final PrivateKey clientPrivateKeyFromCertTrust; // client private key used for X509 and RPK protected final X509Certificate clientX509CertTrustNo; // client certificate signed by intermediate, rootCA with a good CN ("host name") protected final PrivateKey clientPrivateKeyFromCertTrustNo; // client private key used for X509 and RPK - private final String[] RESOURCES_SECURITY = new String[]{"1.xml", "2.xml", "3.xml", "5.xml", "9.xml", "19.xml"}; private final LwM2MBootstrapClientCredentials defaultBootstrapCredentials; @@ -134,7 +134,6 @@ public abstract class AbstractSecurityLwM2MIntegrationTest extends AbstractLwM2M public AbstractSecurityLwM2MIntegrationTest() { // create client credentials - setResources(this.RESOURCES_SECURITY); try { // Get certificates from key store char[] clientKeyStorePwd = CLIENT_STORE_PWD.toCharArray(); @@ -178,11 +177,17 @@ public abstract class AbstractSecurityLwM2MIntegrationTest extends AbstractLwM2M defaultBootstrapCredentials.setLwm2mServer(serverCredentials); } - public void basicTestConnectionBefore(String clientEndpoint, - String awaitAlias, - LwM2MProfileBootstrapConfigType type, - Set expectedStatuses, - LwM2MClientState finishState) throws Exception { + @Before + public void init() throws Exception { + String[] RESOURCES_SECURITY = new String[]{"3-1_2.xml", "5.xml", "6.xml", "9.xml", "19.xml"}; + setResources(RESOURCES_SECURITY); + } + + public void basicTestConnectionStartBS(String clientEndpoint, + String awaitAlias, + LwM2MProfileBootstrapConfigType type, + Set expectedStatuses, + LwM2MClientState finishState) throws Exception { Lwm2mDeviceProfileTransportConfiguration transportConfiguration = getTransportConfiguration(OBSERVE_ATTRIBUTES_WITHOUT_PARAMS, getBootstrapServerCredentialsNoSec(type)); LwM2MDeviceCredentials deviceCredentials = getDeviceCredentialsNoSec(createNoSecClientCredentials(clientEndpoint)); this.basicTestConnection(null , SECURITY_NO_SEC_BS, diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/NoSecLwM2MIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/NoSecLwM2MIntegrationTest.java index d4a464b9c6..6690e6cd7b 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/NoSecLwM2MIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/NoSecLwM2MIntegrationTest.java @@ -40,14 +40,14 @@ public class NoSecLwM2MIntegrationTest extends AbstractSecurityLwM2MIntegrationT public void testWithNoSecConnectBsSuccess_UpdateTwoSectionsBootstrapAndLm2m_ConnectLwm2mSuccess() throws Exception { String clientEndpoint = CLIENT_ENDPOINT_NO_SEC_BS + BOTH.name(); String awaitAlias = "await on client state (NoSecBS two section)"; - basicTestConnectionBefore(clientEndpoint, awaitAlias, BOTH, expectedStatusesRegistrationBsSuccess, ON_REGISTRATION_SUCCESS); + basicTestConnectionStartBS(clientEndpoint, awaitAlias, BOTH, expectedStatusesRegistrationBsSuccess, ON_REGISTRATION_SUCCESS); } @Test public void testWithNoSecConnectBsSuccess_UpdateLwm2mSectionAndLm2m_ConnectLwm2mSuccess() throws Exception { String clientEndpoint = CLIENT_ENDPOINT_NO_SEC_BS + LWM2M_ONLY.name(); String awaitAlias = "await on client state (NoSecBS Lwm2m section)"; - basicTestConnectionBefore(clientEndpoint, awaitAlias, LWM2M_ONLY, expectedStatusesRegistrationBsSuccess, ON_REGISTRATION_SUCCESS); + basicTestConnectionStartBS(clientEndpoint, awaitAlias, LWM2M_ONLY, expectedStatusesRegistrationBsSuccess, ON_REGISTRATION_SUCCESS); } // Bs trigger diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/PskLwm2mIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/PskLwm2mIntegrationTest.java index 3b61dfe49f..f2a22939f4 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/PskLwm2mIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/PskLwm2mIntegrationTest.java @@ -69,10 +69,12 @@ public class PskLwm2mIntegrationTest extends AbstractSecurityLwM2MIntegrationTes ON_REGISTRATION_SUCCESS, true); } + @Test public void testWithPskConnectLwm2mOneObserveSuccessUpdateProfileManyObserveUpdateRegistrationSuccess() throws Exception { - String clientEndpoint = CLIENT_ENDPOINT_PSK; - String identity = CLIENT_PSK_IDENTITY; + String suf = "UpdateReg"; + String clientEndpoint = CLIENT_ENDPOINT_PSK + "_" + suf; + String identity = CLIENT_PSK_IDENTITY + "_" + suf; String keyPsk = CLIENT_PSK_KEY; PSKClientCredential clientCredentials = new PSKClientCredential(); clientCredentials.setEndpoint(clientEndpoint); @@ -105,10 +107,12 @@ public class PskLwm2mIntegrationTest extends AbstractSecurityLwM2MIntegrationTes awaitObserveReadAll(2, lwm2mDevice.getId().getId().toString()); awaitUpdateReg(3); } + @Test public void testWithPskConnectLwm2mSuccessObserveSuccessUnRegClientUpdateProfileObserveConnectLwm2mSuccessOWithNewObserve() throws Exception { - String clientEndpoint = CLIENT_ENDPOINT_PSK; - String identity = CLIENT_PSK_IDENTITY; + String suf = "UnReg"; + String clientEndpoint = CLIENT_ENDPOINT_PSK + "_" + suf; + String identity = CLIENT_PSK_IDENTITY + "_" + suf; String keyPsk = CLIENT_PSK_KEY; PSKClientCredential clientCredentials = new PSKClientCredential(); clientCredentials.setEndpoint(clientEndpoint); @@ -142,7 +146,7 @@ public class PskLwm2mIntegrationTest extends AbstractSecurityLwM2MIntegrationTes Assert.assertNotNull(lwm2mDeviceProfileManyParams); lwM2MTestClient.start(true); - awaitObserveReadAll(2, lwm2mDevice.getId().getId().toString()); + awaitObserveReadAll(1, lwm2mDevice.getId().getId().toString()); awaitUpdateReg(3); } diff --git a/application/src/test/resources/lwm2m/3.xml b/application/src/test/resources/lwm2m/3-1_2.xml similarity index 100% rename from application/src/test/resources/lwm2m/3.xml rename to application/src/test/resources/lwm2m/3-1_2.xml diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/entity/EntityDaoService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/entity/EntityDaoService.java index e9350842f8..dca2e81f29 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/entity/EntityDaoService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/entity/EntityDaoService.java @@ -15,6 +15,7 @@ */ package org.thingsboard.server.dao.entity; +import com.google.common.util.concurrent.FluentFuture; import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.HasId; @@ -26,6 +27,8 @@ public interface EntityDaoService { Optional> findEntity(TenantId tenantId, EntityId entityId); + FluentFuture>> findEntityAsync(TenantId tenantId, EntityId entityId); + default long countByTenantId(TenantId tenantId) { throw new IllegalArgumentException("Not implemented for " + getEntityType()); } diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/entity/EntityService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/entity/EntityService.java index 9adf703e0b..0e41e0b031 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/entity/EntityService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/entity/EntityService.java @@ -15,6 +15,7 @@ */ package org.thingsboard.server.dao.entity; +import com.google.common.util.concurrent.FluentFuture; import org.thingsboard.server.common.data.EntityInfo; import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.EntityId; @@ -38,6 +39,8 @@ public interface EntityService { Optional fetchEntityCustomerId(TenantId tenantId, EntityId entityId); + FluentFuture> fetchEntityCustomerIdAsync(TenantId tenantId, EntityId entityId); + Optional> fetchEntity(TenantId tenantId, EntityId entityId); Map fetchEntityInfos(TenantId tenantId, CustomerId customerId, Set entityIds); @@ -47,4 +50,5 @@ public interface EntityService { long countEntitiesByQuery(TenantId tenantId, CustomerId customerId, EntityCountQuery query); PageData findEntityDataByQuery(TenantId tenantId, CustomerId customerId, EntityDataQuery query); + } diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/entityview/EntityViewService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/entityview/EntityViewService.java index 6e557106f8..5ec2dfc20e 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/entityview/EntityViewService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/entityview/EntityViewService.java @@ -31,9 +31,6 @@ import org.thingsboard.server.dao.entity.EntityDaoService; import java.util.List; -/** - * Created by Victor Basanets on 8/27/2017. - */ public interface EntityViewService extends EntityDaoService { EntityView saveEntityView(EntityView entityView); @@ -52,6 +49,8 @@ public interface EntityViewService extends EntityDaoService { EntityView findEntityViewById(TenantId tenantId, EntityViewId entityViewId, boolean putInCache); + ListenableFuture findEntityViewByIdAsync(TenantId tenantId, EntityViewId entityViewId); + EntityView findEntityViewByTenantIdAndName(TenantId tenantId, String name); ListenableFuture findEntityViewByTenantIdAndNameAsync(TenantId tenantId, String name); @@ -74,8 +73,6 @@ public interface EntityViewService extends EntityDaoService { ListenableFuture> findEntityViewsByQuery(TenantId tenantId, EntityViewSearchQuery query); - ListenableFuture findEntityViewByIdAsync(TenantId tenantId, EntityViewId entityViewId); - ListenableFuture> findEntityViewsByTenantIdAndEntityIdAsync(TenantId tenantId, EntityId entityId); List findEntityViewsByTenantIdAndEntityId(TenantId tenantId, EntityId entityId); @@ -95,4 +92,5 @@ public interface EntityViewService extends EntityDaoService { PageData findEntityViewsByTenantIdAndEdgeId(TenantId tenantId, EdgeId edgeId, PageLink pageLink); PageData findEntityViewsByTenantIdAndEdgeIdAndType(TenantId tenantId, EdgeId edgeId, String type, PageLink pageLink); + } diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/user/UserService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/user/UserService.java index c016631064..160e02fbc8 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/user/UserService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/user/UserService.java @@ -109,4 +109,5 @@ public interface UserService extends EntityDaoService { void removeMobileSession(TenantId tenantId, String mobileToken); + int countTenantAdmins(TenantId tenantId); } diff --git a/common/data/pom.xml b/common/data/pom.xml index 1a12a5da49..a574a6ed07 100644 --- a/common/data/pom.xml +++ b/common/data/pom.xml @@ -113,7 +113,7 @@ compile - dev.langchain4j + org.thingsboard.langchain4j langchain4j-core diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/HasCustomerId.java b/common/data/src/main/java/org/thingsboard/server/common/data/HasCustomerId.java index 6a5501840d..d7900e96ed 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/HasCustomerId.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/HasCustomerId.java @@ -20,4 +20,5 @@ import org.thingsboard.server.common.data.id.CustomerId; public interface HasCustomerId { CustomerId getCustomerId(); + } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/StringUtils.java b/common/data/src/main/java/org/thingsboard/server/common/data/StringUtils.java index 2b8b631027..cbc881d72f 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/StringUtils.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/StringUtils.java @@ -275,11 +275,4 @@ public class StringUtils { return result; } - public static String escapeControlChars(String text) { - return text - .replace("\n", "\\n") - .replace("\r", "\\r") - .replace("\t", "\\t"); - } - } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/ai/AiModel.java b/common/data/src/main/java/org/thingsboard/server/common/data/ai/AiModel.java index 4d7bb21930..3564f8dee0 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/ai/AiModel.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/ai/AiModel.java @@ -32,6 +32,7 @@ import org.thingsboard.server.common.data.id.AiModelId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.validation.Length; import org.thingsboard.server.common.data.validation.NoNullChar; +import org.thingsboard.server.common.data.validation.NoXss; import java.io.Serial; @@ -64,6 +65,7 @@ public final class AiModel extends BaseData implements HasTenantId, H @NotBlank @NoNullChar @Length(min = 1, max = 255) + @NoXss @Schema( requiredMode = Schema.RequiredMode.REQUIRED, accessMode = Schema.AccessMode.READ_WRITE, diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/Lwm2mDeviceProfileTransportConfiguration.java b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/Lwm2mDeviceProfileTransportConfiguration.java index 614da6cde6..e58ed8c04a 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/Lwm2mDeviceProfileTransportConfiguration.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/Lwm2mDeviceProfileTransportConfiguration.java @@ -17,10 +17,15 @@ package org.thingsboard.server.common.data.device.profile; import lombok.Data; import org.thingsboard.server.common.data.DeviceTransportType; +import org.thingsboard.server.common.data.device.data.PowerMode; import org.thingsboard.server.common.data.device.profile.lwm2m.OtherConfiguration; import org.thingsboard.server.common.data.device.profile.lwm2m.TelemetryMappingConfiguration; import org.thingsboard.server.common.data.device.profile.lwm2m.bootstrap.LwM2MBootstrapServerCredential; +import static org.eclipse.leshan.core.LwM2m.Version.V1_0; +import static org.thingsboard.server.common.data.device.profile.lwm2m.TelemetryObserveStrategy.SINGLE; + +import java.util.Collections; import java.util.List; @Data @@ -33,9 +38,18 @@ public class Lwm2mDeviceProfileTransportConfiguration implements DeviceProfileTr private List bootstrap; private OtherConfiguration clientLwM2mSettings; + public Lwm2mDeviceProfileTransportConfiguration() { + updateDefault(); + } + @Override public DeviceTransportType getType() { return DeviceTransportType.LWM2M; } + private void updateDefault(){ + this.setBootstrap(Collections.emptyList()); + this.setClientLwM2mSettings(new OtherConfiguration(false,1, 1, 1, PowerMode.DRX, null, null, null, null, null, V1_0.toString())); + this.setObserveAttr(new TelemetryMappingConfiguration(Collections.emptyMap(), Collections.emptySet(), Collections.emptySet(), Collections.emptySet(), Collections.emptyMap(), SINGLE)); + } } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/job/JobResult.java b/common/data/src/main/java/org/thingsboard/server/common/data/job/JobResult.java index bd2c73d0d8..6f6d924deb 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/job/JobResult.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/job/JobResult.java @@ -55,11 +55,17 @@ public abstract class JobResult implements Serializable { public void processTaskResult(TaskResult taskResult) { if (taskResult.isSuccess()) { - successfulCount++; + if (totalCount == null || successfulCount < totalCount) { + successfulCount++; + } } else if (taskResult.isDiscarded()) { - discardedCount++; + if (totalCount == null || discardedCount < totalCount) { + discardedCount++; + } } else { - failedCount++; + if (totalCount == null || failedCount < totalCount) { + failedCount++; + } if (results.size() < 100) { // preserving only first 100 errors, not reprocessing if there are more failures results.add(taskResult); } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/oauth2/OAuth2Client.java b/common/data/src/main/java/org/thingsboard/server/common/data/oauth2/OAuth2Client.java index 6396ecb7b8..e6b6c1ff6f 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/oauth2/OAuth2Client.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/oauth2/OAuth2Client.java @@ -30,6 +30,7 @@ import org.thingsboard.server.common.data.HasTenantId; import org.thingsboard.server.common.data.id.OAuth2ClientId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.validation.Length; +import org.thingsboard.server.common.data.validation.NoXss; import java.util.List; @@ -42,6 +43,7 @@ public class OAuth2Client extends BaseDataWithAdditionalInfo imp private TenantId tenantId; @Schema(description = "Oauth2 client title") @NotBlank + @NoXss @Length(fieldName = "title", max = 100, message = "cannot be longer than 100 chars") private String title; @Schema(description = "Config for mapping OAuth2 log in response to platform entities", requiredMode = Schema.RequiredMode.REQUIRED) diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/security/DeviceCredentials.java b/common/data/src/main/java/org/thingsboard/server/common/data/security/DeviceCredentials.java index ad73510d9e..6d1dbdcb4a 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/security/DeviceCredentials.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/security/DeviceCredentials.java @@ -24,11 +24,15 @@ import org.thingsboard.server.common.data.HasVersion; import org.thingsboard.server.common.data.id.DeviceCredentialsId; import org.thingsboard.server.common.data.id.DeviceId; +import java.io.Serial; + @Schema @EqualsAndHashCode(callSuper = true) public class DeviceCredentials extends BaseData implements DeviceCredentialsFilter, HasVersion { + @Serial private static final long serialVersionUID = -7869261127032877765L; + private DeviceId deviceId; private DeviceCredentialsType credentialsType; private String credentialsId; diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/util/CollectionsUtil.java b/common/data/src/main/java/org/thingsboard/server/common/data/util/CollectionsUtil.java index 71c5256203..082be9b71f 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/util/CollectionsUtil.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/util/CollectionsUtil.java @@ -95,4 +95,17 @@ public class CollectionsUtil { return false; } + public static Set addToSet(Set existing, T value) { + if (existing == null || existing.isEmpty()) { + return Set.of(value); + } + if (existing.contains(value)) { + return existing; + } + Set newSet = new HashSet<>(existing.size() + 1); + newSet.addAll(existing); + newSet.add(value); + return (Set) Set.of(newSet.toArray()); + } + } diff --git a/common/edge-api/src/main/java/org/thingsboard/edge/rpc/EdgeGrpcClient.java b/common/edge-api/src/main/java/org/thingsboard/edge/rpc/EdgeGrpcClient.java index 0eff7ad053..b2f47b4b73 100644 --- a/common/edge-api/src/main/java/org/thingsboard/edge/rpc/EdgeGrpcClient.java +++ b/common/edge-api/src/main/java/org/thingsboard/edge/rpc/EdgeGrpcClient.java @@ -136,12 +136,25 @@ public class EdgeGrpcClient implements EdgeRpcClient { .setConnectRequestMsg(ConnectRequestMsg.newBuilder() .setEdgeRoutingKey(edgeKey) .setEdgeSecret(edgeSecret) - .setEdgeVersion(EdgeVersion.V_4_2_0) + .setEdgeVersion(getNewestEdgeVersion()) .setMaxInboundMessageSize(maxInboundMessageSize) .build()) .build()); } + public static EdgeVersion getNewestEdgeVersion() { + EdgeVersion newest = null; + for (EdgeVersion v : EdgeVersion.values()) { + if (v == EdgeVersion.V_LATEST || v == EdgeVersion.UNRECOGNIZED) { + continue; + } + if (newest == null || v.getNumber() > newest.getNumber()) { + newest = v; + } + } + return newest; + } + private StreamObserver initOutputStream(String edgeKey, Consumer onUplinkResponse, Consumer onEdgeUpdate, diff --git a/common/message/src/main/java/org/thingsboard/server/common/msg/rule/engine/DeviceAttributesEventNotificationMsg.java b/common/message/src/main/java/org/thingsboard/server/common/msg/rule/engine/DeviceAttributesEventNotificationMsg.java index efee3dcb97..f647714c63 100644 --- a/common/message/src/main/java/org/thingsboard/server/common/msg/rule/engine/DeviceAttributesEventNotificationMsg.java +++ b/common/message/src/main/java/org/thingsboard/server/common/msg/rule/engine/DeviceAttributesEventNotificationMsg.java @@ -23,16 +23,15 @@ import org.thingsboard.server.common.data.kv.AttributeKvEntry; import org.thingsboard.server.common.msg.MsgType; import org.thingsboard.server.common.msg.ToDeviceActorNotificationMsg; +import java.io.Serial; import java.util.HashSet; import java.util.List; import java.util.Set; -/** - * @author Andrew Shvayka - */ @Data public class DeviceAttributesEventNotificationMsg implements ToDeviceActorNotificationMsg { + @Serial private static final long serialVersionUID = 2422071590415277039L; private final TenantId tenantId; @@ -56,4 +55,5 @@ public class DeviceAttributesEventNotificationMsg implements ToDeviceActorNotifi public MsgType getMsgType() { return MsgType.DEVICE_ATTRIBUTES_UPDATE_TO_DEVICE_ACTOR_MSG; } + } diff --git a/common/queue/pom.xml b/common/queue/pom.xml index 922e2d08ff..19368c1345 100644 --- a/common/queue/pom.xml +++ b/common/queue/pom.xml @@ -68,6 +68,10 @@ org.apache.kafka kafka-clients + + at.yawk.lz4 + lz4-java + com.google.cloud google-cloud-pubsub diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/kafka/KafkaAdmin.java b/common/queue/src/main/java/org/thingsboard/server/queue/kafka/KafkaAdmin.java index 6261e81497..3e2c64de69 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/kafka/KafkaAdmin.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/kafka/KafkaAdmin.java @@ -58,15 +58,12 @@ public class KafkaAdmin { private final TbKafkaSettings settings; - @Value("${queue.kafka.request.timeout.ms:30000}") - private int requestTimeoutMs; - @Value("${queue.kafka.topics_cache_ttl_ms:300000}") // 5 minutes by default - private int topicsCacheTtlMs; - private final LazyInitializer adminClient; private final CachedValue> topics; - public KafkaAdmin(@Lazy TbKafkaSettings settings) { + public KafkaAdmin(@Lazy TbKafkaSettings settings, + @Value("${queue.kafka.topics_cache_ttl_ms:300000}") + int topicsCacheTtlMs) { this.settings = settings; this.adminClient = LazyInitializer.builder() .setInitializer(() -> AdminClient.create(settings.toAdminProps())) @@ -91,7 +88,7 @@ public class KafkaAdmin { NewTopic newTopic = new NewTopic(topic, partitions, settings.getReplicationFactor()).configs(properties); try { - getClient().createTopics(List.of(newTopic)).all().get(requestTimeoutMs, TimeUnit.MILLISECONDS); + getClient().createTopics(List.of(newTopic)).all().get(settings.getRequestTimeoutMs(), TimeUnit.MILLISECONDS); topics.add(topic); } catch (ExecutionException ee) { log.trace("Failed to create topic {} with properties {}", topic, properties, ee); @@ -110,7 +107,7 @@ public class KafkaAdmin { public void deleteTopic(String topic) { log.debug("Deleting topic {}", topic); try { - getClient().deleteTopics(List.of(topic)).all().get(requestTimeoutMs, TimeUnit.MILLISECONDS); + getClient().deleteTopics(List.of(topic)).all().get(settings.getRequestTimeoutMs(), TimeUnit.MILLISECONDS); } catch (Exception e) { log.error("Failed to delete kafka topic [{}].", topic, e); } @@ -122,7 +119,7 @@ public class KafkaAdmin { public Set listTopics() { try { - Set topics = getClient().listTopics().names().get(requestTimeoutMs, TimeUnit.MILLISECONDS); + Set topics = getClient().listTopics().names().get(settings.getRequestTimeoutMs(), TimeUnit.MILLISECONDS); log.trace("Listed topics: {}", topics); return topics; } catch (Exception e) { @@ -150,7 +147,7 @@ public class KafkaAdmin { .collect(Collectors.toMap(tp -> tp, tp -> OffsetSpec.latest())); Map endOffsets = - getClient().listOffsets(latestOffsetsSpec).all().get(requestTimeoutMs, TimeUnit.MILLISECONDS); + getClient().listOffsets(latestOffsetsSpec).all().get(settings.getRequestTimeoutMs(), TimeUnit.MILLISECONDS); return committedOffsets.entrySet().stream() .mapToLong(entry -> { @@ -169,7 +166,7 @@ public class KafkaAdmin { @SneakyThrows public Map getConsumerGroupOffsets(String groupId) { - return getClient().listConsumerGroupOffsets(groupId).partitionsToOffsetAndMetadata().get(requestTimeoutMs, TimeUnit.MILLISECONDS); + return getClient().listConsumerGroupOffsets(groupId).partitionsToOffsetAndMetadata().get(settings.getRequestTimeoutMs(), TimeUnit.MILLISECONDS); } /** @@ -212,7 +209,7 @@ public class KafkaAdmin { } else { log.info("[{}] SHOULD alter topic offset [{}] less than old node group offset [{}]", tp, existingOffset.offset(), om.offset()); } - getClient().alterConsumerGroupOffsets(newGroupId, Map.of(tp, om)).all().get(requestTimeoutMs, TimeUnit.MILLISECONDS); + getClient().alterConsumerGroupOffsets(newGroupId, Map.of(tp, om)).all().get(settings.getRequestTimeoutMs(), TimeUnit.MILLISECONDS); log.info("[{}] altered new consumer groupId {}", tp, newGroupId); break; } @@ -229,7 +226,7 @@ public class KafkaAdmin { return true; } - List allPartitions = getClient().describeTopics(existingTopics).allTopicNames().get(requestTimeoutMs, TimeUnit.MILLISECONDS) + List allPartitions = getClient().describeTopics(existingTopics).allTopicNames().get(settings.getRequestTimeoutMs(), TimeUnit.MILLISECONDS) .entrySet().stream() .flatMap(entry -> { String topic = entry.getKey(); @@ -239,9 +236,9 @@ public class KafkaAdmin { .toList(); Map beginningOffsets = getClient().listOffsets(allPartitions.stream() - .collect(Collectors.toMap(partition -> partition, partition -> OffsetSpec.earliest()))).all().get(requestTimeoutMs, TimeUnit.MILLISECONDS); + .collect(Collectors.toMap(partition -> partition, partition -> OffsetSpec.earliest()))).all().get(settings.getRequestTimeoutMs(), TimeUnit.MILLISECONDS); Map endOffsets = getClient().listOffsets(allPartitions.stream() - .collect(Collectors.toMap(partition -> partition, partition -> OffsetSpec.latest()))).all().get(requestTimeoutMs, TimeUnit.MILLISECONDS); + .collect(Collectors.toMap(partition -> partition, partition -> OffsetSpec.latest()))).all().get(settings.getRequestTimeoutMs(), TimeUnit.MILLISECONDS); for (TopicPartition partition : allPartitions) { long beginningOffset = beginningOffsets.get(partition).offset(); @@ -261,7 +258,7 @@ public class KafkaAdmin { public void deleteConsumerGroup(String consumerGroupId) { try { - getClient().deleteConsumerGroups(List.of(consumerGroupId)).all().get(requestTimeoutMs, TimeUnit.MILLISECONDS); + getClient().deleteConsumerGroups(List.of(consumerGroupId)).all().get(settings.getRequestTimeoutMs(), TimeUnit.MILLISECONDS); } catch (Exception e) { log.warn("Failed to delete consumer group {}", consumerGroupId, e); } diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/kafka/TbKafkaSettings.java b/common/queue/src/main/java/org/thingsboard/server/queue/kafka/TbKafkaSettings.java index 11736f68cf..3dbcff1863 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/kafka/TbKafkaSettings.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/kafka/TbKafkaSettings.java @@ -112,6 +112,7 @@ public class TbKafkaSettings { @Value("${queue.kafka.fetch_max_bytes:134217728}") private int fetchMaxBytes; + @Getter @Value("${queue.kafka.request.timeout.ms:30000}") private int requestTimeoutMs; diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/DefaultLwM2mTransportService.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/DefaultLwM2mTransportService.java index 795f40aa20..789c8b6aac 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/DefaultLwM2mTransportService.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/DefaultLwM2mTransportService.java @@ -20,7 +20,6 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.eclipse.californium.core.CoapResource; import org.eclipse.californium.core.CoapServer; -import org.eclipse.californium.core.config.CoapConfig; import org.eclipse.californium.elements.config.Configuration; import org.eclipse.californium.scandium.config.DtlsConfig; import org.eclipse.californium.scandium.dtls.cipher.CipherSuite; @@ -196,14 +195,13 @@ public class DefaultLwM2mTransportService implements LwM2MTransportService { root = new CoapResource(""); coapServer.add(root); } - root.add(new LwM2mTransportCoapResource(otaPackageDataCache, FIRMWARE_UPDATE_COAP_RESOURCE, serverCoapConfig.get(CoapConfig.PREFERRED_BLOCK_SIZE), serverCoapConfig.get(CoapConfig.MAX_RESOURCE_BODY_SIZE))); - root.add(new LwM2mTransportCoapResource(otaPackageDataCache, SOFTWARE_UPDATE_COAP_RESOURCE,serverCoapConfig.get(CoapConfig.PREFERRED_BLOCK_SIZE), serverCoapConfig.get(CoapConfig.MAX_RESOURCE_BODY_SIZE))); + root.add(new LwM2mTransportCoapResource(otaPackageDataCache, FIRMWARE_UPDATE_COAP_RESOURCE)); + root.add(new LwM2mTransportCoapResource(otaPackageDataCache, SOFTWARE_UPDATE_COAP_RESOURCE)); } return leshanServer; } private void setServerWithCredentials(LeshanServerBuilder builder) { -// private void setServerWithCredentials(LeshanServerBuilder builder) { if (this.config.getSslCredentials() != null) { SslCredentials sslCredentials = this.config.getSslCredentials(); builder.setPublicKey(sslCredentials.getPublicKey()); diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportCoapResource.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportCoapResource.java index c46b57fb3f..752b888267 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportCoapResource.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportCoapResource.java @@ -34,21 +34,15 @@ import java.util.concurrent.atomic.AtomicInteger; import static org.thingsboard.server.transport.lwm2m.server.ota.DefaultLwM2MOtaUpdateService.FIRMWARE_UPDATE_COAP_RESOURCE; import static org.thingsboard.server.transport.lwm2m.server.ota.DefaultLwM2MOtaUpdateService.SOFTWARE_UPDATE_COAP_RESOURCE; -import static org.thingsboard.server.transport.lwm2m.utils.LwM2MTransportUtil.calculateSzx; @Slf4j public class LwM2mTransportCoapResource extends AbstractLwM2mTransportResource { - private final ConcurrentMap tokenToObserveRelationMap = new ConcurrentHashMap<>(); private final ConcurrentMap tokenToObserveNotificationSeqMap = new ConcurrentHashMap<>(); private final OtaPackageDataCache otaPackageDataCache; - private final int chunkSize; - private final int maxResourceBodySize; - public LwM2mTransportCoapResource(OtaPackageDataCache otaPackageDataCache, String name, int chunkSize, int maxResourceBodySize) { + public LwM2mTransportCoapResource(OtaPackageDataCache otaPackageDataCache, String name) { super(name); this.otaPackageDataCache = otaPackageDataCache; - this.chunkSize = chunkSize; - this.maxResourceBodySize = maxResourceBodySize; this.setObservable(true); // enable observing this.addObserver(new CoapResourceObserver()); } @@ -141,29 +135,23 @@ public class LwM2mTransportCoapResource extends AbstractLwM2mTransportResource { String idStr = exchange.getRequestOptions().getUriPath().get(exchange.getRequestOptions().getUriPath().size() - 1 ); UUID currentId = UUID.fromString(idStr); - log.info("Start Read ota data (path): [{}]", exchange.getRequestOptions().getUriPath().toString()); Response response = new Response(CoAP.ResponseCode.CONTENT); byte[] otaData = this.getOtaData(currentId); if (otaData != null && otaData.length > 0) { - if (otaData.length <= this.maxResourceBodySize) { - log.info("Read ota data (length): [{}]", otaData.length); - response.setPayload(otaData); - int chunkSize = calculateSzx(this.chunkSize); - if (exchange.getRequestOptions().hasBlock2()) { - chunkSize = exchange.getRequestOptions().getBlock2().getSzx(); - } else if (exchange.getRequestOptions().hasBlock1()) { - chunkSize = exchange.getRequestOptions().getBlock1().getSzx(); - } - log.info("With block2 Send currentId: [{}], length: [{}], chunkSize [{}], moreFlag [{}]", currentId.toString(), otaData.length, chunkSize, false); - boolean lastFlag = otaData.length <= this.chunkSize; - response.getOptions().setBlock2(chunkSize, lastFlag, 0); - response.setType(CoAP.Type.CON); - exchange.respond(response); + log.debug("Read ota data (length): [{}]", otaData.length); + response.setPayload(otaData); + if (exchange.getRequestOptions().getBlock2() != null) { + int szx = exchange.getRequestOptions().getBlock2().getSzx(); + int chunkSize = exchange.getRequestOptions().getBlock2().getSize(); + boolean lastFlag = otaData.length <= chunkSize; + response.getOptions().setBlock2(szx, lastFlag, 0); + log.trace("With block2 Send currentId: [{}], length: [{}], chunkSize [{}], szx [{}], moreFlag [{}]", currentId, otaData.length, chunkSize, szx, lastFlag); } else { - log.info("Ota package size: [{}] is larger than server's MAX_RESOURCE_BODY_SIZE [{}]", otaData.length, this.maxResourceBodySize); + log.trace("With block1 Send currentId: [{}], length: [{}], ", currentId, otaData.length); } + exchange.respond(response); } else { - log.info("Ota packaged currentId: [{}] is not found.", currentId.toString()); + log.trace("Ota packaged currentId: [{}] is not found.", currentId); } } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContextImpl.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContextImpl.java index 4cf8d825b9..36cf1639db 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContextImpl.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContextImpl.java @@ -360,20 +360,25 @@ public class LwM2mClientContextImpl implements LwM2mClientContext { @Override public Lwm2mDeviceProfileTransportConfiguration getProfile(Registration registration) { UUID profileId = getClientByEndpoint(registration.getEndpoint()).getProfileId(); - return doGetAndCache(profileId); + return profileId != null ? doGetAndCache(profileId) : null; } private Lwm2mDeviceProfileTransportConfiguration doGetAndCache(UUID profileId) { - - Lwm2mDeviceProfileTransportConfiguration result = profiles.get(profileId); - if (result == null) { - log.debug("Fetching profile [{}]", profileId); - DeviceProfile deviceProfile = deviceProfileCache.get(new DeviceProfileId(profileId)); - if (deviceProfile != null) { - result = profileUpdate(deviceProfile); - } else { - log.warn("Device profile was not found! Most probably device profile [{}] has been removed from the database.", profileId); + Lwm2mDeviceProfileTransportConfiguration result; + if (profileId != null) { + result = profiles.get(profileId); + if (result == null) { + log.debug("Fetching profile [{}]", profileId); + DeviceProfile deviceProfile = deviceProfileCache.get(new DeviceProfileId(profileId)); + if (deviceProfile != null) { + result = profileUpdate(deviceProfile); + } else { + log.warn("Device profile was not found! Most probably device profile [{}] has been removed from the database.", profileId); + } } + } else { + log.warn("Device profile not found! The device profile ID is null. Return Lwm2mDeviceProfileTransportConfiguration with default."); + result = new Lwm2mDeviceProfileTransportConfiguration(); } return result; } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/ota/DefaultLwM2MOtaUpdateService.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/ota/DefaultLwM2MOtaUpdateService.java index 79f077a71e..325f1e2280 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/ota/DefaultLwM2MOtaUpdateService.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/ota/DefaultLwM2MOtaUpdateService.java @@ -201,35 +201,39 @@ public class DefaultLwM2MOtaUpdateService extends LwM2MExecutorAwareService impl } var clientSettings = clientContext.getProfile(client.getRegistration()).getClientLwM2mSettings(); - initFwStrategy(client, clientSettings); - initSwStrategy(client, clientSettings); - - if (!attributesToFetch.isEmpty()) { - var future = attributesService.getSharedAttributes(client, attributesToFetch); - DonAsynchron.withCallback(future, attrs -> { - if (fwInfo.isSupported()) { - Optional newFwTitle = getAttributeValue(attrs, FIRMWARE_TITLE); - Optional newFwVersion = getAttributeValue(attrs, FIRMWARE_VERSION); - Optional newFwTag = getAttributeValue(attrs, FIRMWARE_TAG); - Optional newFwUrl = getAttributeValue(attrs, FIRMWARE_URL); - if (newFwTitle.isPresent() && newFwVersion.isPresent() && !isOtaDownloading(client) && !UPDATING.equals(fwInfo.status)) { - onTargetFirmwareUpdate(client, newFwTitle.get(), newFwVersion.get(), newFwUrl, newFwTag); + if (clientSettings != null) { + initFwStrategy(client, clientSettings); + initSwStrategy(client, clientSettings); + + + if (!attributesToFetch.isEmpty()) { + var future = attributesService.getSharedAttributes(client, attributesToFetch); + DonAsynchron.withCallback(future, attrs -> { + if (fwInfo.isSupported()) { + Optional newFwTitle = getAttributeValue(attrs, FIRMWARE_TITLE); + Optional newFwVersion = getAttributeValue(attrs, FIRMWARE_VERSION); + Optional newFwTag = getAttributeValue(attrs, FIRMWARE_TAG); + Optional newFwUrl = getAttributeValue(attrs, FIRMWARE_URL); + if (newFwTitle.isPresent() && newFwVersion.isPresent() && !isOtaDownloading(client) && !UPDATING.equals(fwInfo.status)) { + onTargetFirmwareUpdate(client, newFwTitle.get(), newFwVersion.get(), newFwUrl, newFwTag); + } } - } - if (swInfo.isSupported()) { - Optional newSwTitle = getAttributeValue(attrs, SOFTWARE_TITLE); - Optional newSwVersion = getAttributeValue(attrs, SOFTWARE_VERSION); - Optional newSwTag = getAttributeValue(attrs, SOFTWARE_TAG); - Optional newSwUrl = getAttributeValue(attrs, SOFTWARE_URL); - if (newSwTitle.isPresent() && newSwVersion.isPresent()) { - onTargetSoftwareUpdate(client, newSwTitle.get(), newSwVersion.get(), newSwUrl, newSwTag); + if (swInfo.isSupported()) { + Optional newSwTitle = getAttributeValue(attrs, SOFTWARE_TITLE); + Optional newSwVersion = getAttributeValue(attrs, SOFTWARE_VERSION); + Optional newSwTag = getAttributeValue(attrs, SOFTWARE_TAG); + Optional newSwUrl = getAttributeValue(attrs, SOFTWARE_URL); + if (newSwTitle.isPresent() && newSwVersion.isPresent()) { + onTargetSoftwareUpdate(client, newSwTitle.get(), newSwVersion.get(), newSwUrl, newSwTag); + } } - } - }, throwable -> { - if (fwInfo.isSupported()) { - update(fwInfo); - } - }, executor); + + }, throwable -> { + if (fwInfo.isSupported()) { + update(fwInfo); + } + }, executor); + } } } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbLwM2mRedisRegistrationStore.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbLwM2mRedisRegistrationStore.java index df432732b2..3c9828af22 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbLwM2mRedisRegistrationStore.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbLwM2mRedisRegistrationStore.java @@ -750,11 +750,14 @@ public class TbLwM2mRedisRegistrationStore implements RegistrationStore, Startab System.currentTimeMillis(), 0, cleanLimit); for (byte[] endpoint : endpointsExpired) { - Registration r = deserializeReg(connection.get(toEndpointKey(endpoint))); - if (!r.isAlive(gracePeriod)) { - Deregistration dereg = removeRegistration(connection, r.getId(), true); - if (dereg != null) - expirationListener.registrationExpired(dereg.getRegistration(), dereg.getObservations()); + byte[] data = connection.get(toEndpointKey(endpoint)); + if (data != null && data.length > 0) { + Registration r = deserializeReg(data); + if (!r.isAlive(gracePeriod)) { + Deregistration dereg = removeRegistration(connection, r.getId(), true); + if (dereg != null) + expirationListener.registrationExpired(dereg.getRegistration(), dereg.getObservations()); + } } } } catch (Exception e) { diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/uplink/DefaultLwM2mUplinkMsgHandler.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/uplink/DefaultLwM2mUplinkMsgHandler.java index 431b623da9..5e27b936f3 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/uplink/DefaultLwM2mUplinkMsgHandler.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/uplink/DefaultLwM2mUplinkMsgHandler.java @@ -222,8 +222,11 @@ public class DefaultLwM2mUplinkMsgHandler extends LwM2MExecutorAwareService impl log.info("[{}] Closing old session: {}", registration.getEndpoint(), new UUID(oldSessionInfo.get().getSessionIdMSB(), oldSessionInfo.get().getSessionIdLSB())); sessionManager.deregister(oldSessionInfo.get()); } - logService.log(lwM2MClient, LOG_LWM2M_INFO + ": Client registered with registration id: " + registration.getId() + " version: " - + registration.getLwM2mVersion() + " and modes: " + registration.getQueueMode() + ", " + registration.getBindingMode()); + String msgLogService = String.format(""" + %s: Endpoint [%s] Client registered with registration id: [%s] LwM2mVersion: [%s], SupportedObjectIdVer [%s] QueueMode [%s], BindingMode %s + """, LOG_LWM2M_INFO, registration.getEndpoint(), registration.getId(), registration.getLwM2mVersion(), registration.getSupportedObject(), registration.getQueueMode(), registration.getBindingMode()); + logService.log(lwM2MClient, msgLogService); + log.debug(msgLogService); sessionManager.register(lwM2MClient.getSession()); this.initClientTelemetry(lwM2MClient); this.initAttributes(lwM2MClient, true); @@ -242,7 +245,7 @@ public class DefaultLwM2mUplinkMsgHandler extends LwM2MExecutorAwareService impl logService.log(lwM2MClient, LOG_LWM2M_WARN + ": Client registration failed due to invalid state: " + stateException.getState()); } } catch (Throwable t) { - log.error("[{}] endpoint [{}] error Unable registration.", registration.getEndpoint(), t); + log.error("Endpoint [{}], Error Unable registration: [{}].", registration.getEndpoint(), t.getMessage(), t); logService.log(lwM2MClient, LOG_LWM2M_WARN + ": Client registration failed due to: " + t.getMessage()); } }); @@ -288,7 +291,6 @@ public class DefaultLwM2mUplinkMsgHandler extends LwM2MExecutorAwareService impl clientContext.unregister(client, registration); SessionInfoProto sessionInfo = client.getSession(); if (sessionInfo != null) { - securityStore.remove(client.getEndpoint(), client.getRegistration().getId()); sessionManager.deregister(sessionInfo); sessionStore.remove(registration.getEndpoint()); log.info("Client close session: [{}] unReg [{}] name [{}] profile ", registration.getId(), registration.getEndpoint(), sessionInfo.getDeviceType()); @@ -482,13 +484,18 @@ public class DefaultLwM2mUplinkMsgHandler extends LwM2MExecutorAwareService impl */ private void initClientTelemetry(LwM2mClient lwM2MClient) { Lwm2mDeviceProfileTransportConfiguration profile = clientContext.getProfile(lwM2MClient.getRegistration()); - Set supportedObjects = clientContext.getSupportedIdVerInClient(lwM2MClient); - if (supportedObjects != null && supportedObjects.size() > 0) { - this.sendReadRequests(lwM2MClient, profile, supportedObjects); - this.sendInitObserveRequests(lwM2MClient, profile, supportedObjects); - this.sendWriteAttributeRequests(lwM2MClient, profile, supportedObjects); + if (profile != null) { + Set supportedObjects = clientContext.getSupportedIdVerInClient(lwM2MClient); + if (supportedObjects != null && !supportedObjects.isEmpty()) { + this.sendInitObserveRequests(lwM2MClient, profile, supportedObjects); + this.sendReadRequests(lwM2MClient, profile, supportedObjects); + this.sendWriteAttributeRequests(lwM2MClient, profile, supportedObjects); // Removed. Used only for debug. // this.sendDiscoverRequests(lwM2MClient, profile, supportedObjects); + } + } else { + log.warn("[{}] Failed to process initClientTelemetry! Profile is null. Update procedure may not have completed after reboot yet", lwM2MClient.getEndpoint()); + logService.log(lwM2MClient, "Failed to process initClientTelemetry. Profile is null. Update procedure may not have completed after reboot yet"); } } @@ -1014,7 +1021,7 @@ public class DefaultLwM2mUplinkMsgHandler extends LwM2MExecutorAwareService impl }); } - private void updateValueOta(List clients, Lwm2mDeviceProfileTransportConfiguration oldProfile, Lwm2mDeviceProfileTransportConfiguration newProfile) { + private void updateValueOta(List clients, Lwm2mDeviceProfileTransportConfiguration newProfile, Lwm2mDeviceProfileTransportConfiguration oldProfile) { OtherConfiguration newLwM2mSettings = newProfile.getClientLwM2mSettings(); OtherConfiguration oldLwM2mSettings = oldProfile.getClientLwM2mSettings(); if (!newLwM2mSettings.getFwUpdateStrategy().equals(oldLwM2mSettings.getFwUpdateStrategy()) @@ -1096,6 +1103,9 @@ public class DefaultLwM2mUplinkMsgHandler extends LwM2MExecutorAwareService impl v -> attributesService.onAttributesUpdate(lwM2MClient, v, logFailedUpdateOfNonChangedValue), t -> log.error("[{}] Failed to get attributes", lwM2MClient.getEndpoint(), t), executor); + } else { + log.warn("[{}] Failed to process initAttributes! Profile is null. Update procedure may not have completed after reboot yet", lwM2MClient.getEndpoint()); + logService.log(lwM2MClient, "Failed to process initAttributes. Profile is null. Update procedure may not have completed after reboot yet"); } } @@ -1105,7 +1115,7 @@ public class DefaultLwM2mUplinkMsgHandler extends LwM2MExecutorAwareService impl private Map getNamesFromProfileForSharedAttributes(LwM2mClient lwM2MClient) { Lwm2mDeviceProfileTransportConfiguration profile = clientContext.getProfile(lwM2MClient.getRegistration()); - return profile.getObserveAttr().getKeyName(); + return profile != null ? profile.getObserveAttr().getKeyName() : Collections.emptyMap(); } public LwM2MTransportServerConfig getConfig() { diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/utils/LwM2MTransportUtil.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/utils/LwM2MTransportUtil.java index 160ca3d905..68ab475d39 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/utils/LwM2MTransportUtil.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/utils/LwM2MTransportUtil.java @@ -120,10 +120,6 @@ public class LwM2MTransportUtil { } } - public static List getBootstrapParametersFromThingsboard(DeviceProfile deviceProfile) { - return toLwM2MClientProfile(deviceProfile).getBootstrap(); - } - public static String fromVersionedIdToObjectId(String pathIdVer) { try { if (pathIdVer == null) { @@ -398,13 +394,6 @@ public class LwM2MTransportUtil { } } - public static int calculateSzx(int size) { - if (size < 16 || size > 1024 || (size & (size - 1)) != 0) { - throw new IllegalArgumentException("Size must be a power of 2 between 16 and 1024."); - } - return (int) (Math.log(size / 16) / Math.log(2)); - } - public static ConcurrentHashMap groupByObjectIdVersionedIds(Set targetIds) { return targetIds.stream() .collect(Collectors.groupingBy( diff --git a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/MqttSslHandlerProvider.java b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/MqttSslHandlerProvider.java index a756b84fe8..77396c69fa 100644 --- a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/MqttSslHandlerProvider.java +++ b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/MqttSslHandlerProvider.java @@ -20,7 +20,6 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Value; -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.stereotype.Component; @@ -46,12 +45,9 @@ import java.security.cert.X509Certificate; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; -/** - * Created by valerii.sosliuk on 11/6/16. - */ @Slf4j @Component("MqttSslHandlerProvider") -@ConditionalOnProperty(prefix = "transport.mqtt.ssl", value = "enabled", havingValue = "true", matchIfMissing = false) +@TbMqttSslTransportComponent public class MqttSslHandlerProvider { @Value("${transport.mqtt.ssl.protocol}") diff --git a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/MqttTransportHandler.java b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/MqttTransportHandler.java index 7f9da9e0b9..4397802951 100644 --- a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/MqttTransportHandler.java +++ b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/MqttTransportHandler.java @@ -133,9 +133,6 @@ import static org.thingsboard.server.transport.mqtt.util.sparkplug.SparkplugMetr import static org.thingsboard.server.transport.mqtt.util.sparkplug.SparkplugTopic.parseTopic; import static org.thingsboard.server.transport.mqtt.util.sparkplug.SparkplugTopicService.parseTopicPublish; -/** - * @author Andrew Shvayka - */ @Slf4j public class MqttTransportHandler extends ChannelInboundHandlerAdapter implements GenericFutureListener>, SessionMsgListener { diff --git a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/MqttTransportServerInitializer.java b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/MqttTransportServerInitializer.java index c630def89f..5d127fccb7 100644 --- a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/MqttTransportServerInitializer.java +++ b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/MqttTransportServerInitializer.java @@ -25,9 +25,6 @@ import io.netty.handler.ssl.SslHandler; import org.thingsboard.server.transport.mqtt.limits.IpFilter; import org.thingsboard.server.transport.mqtt.limits.ProxyIpFilter; -/** - * @author Andrew Shvayka - */ public class MqttTransportServerInitializer extends ChannelInitializer { private final MqttTransportContext context; diff --git a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/MqttTransportService.java b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/MqttTransportService.java index c7ff8912aa..d62f35d561 100644 --- a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/MqttTransportService.java +++ b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/MqttTransportService.java @@ -35,9 +35,6 @@ import org.thingsboard.server.common.data.TbTransportService; import java.net.InetSocketAddress; -/** - * @author Andrew Shvayka - */ @Service("MqttTransportService") @TbMqttTransportComponent @Slf4j diff --git a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/TbMqttSslTransportComponent.java b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/TbMqttSslTransportComponent.java new file mode 100644 index 0000000000..9f55d40919 --- /dev/null +++ b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/TbMqttSslTransportComponent.java @@ -0,0 +1,31 @@ +/** + * Copyright © 2016-2025 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.transport.mqtt; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; + +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * Same as @TbMqttTransportComponent with additional condition by `transport.mqtt.ssl.enabled == true` + */ + +@Inherited +@Retention(RetentionPolicy.RUNTIME) +@ConditionalOnExpression("'${transport.mqtt.ssl.enabled:false}'=='true' && ('${service.type:null}'=='tb-transport' || ('${service.type:null}'=='monolith' && '${transport.api_enabled:true}'=='true' && '${transport.mqtt.enabled:true}'=='true'))") +public @interface TbMqttSslTransportComponent {} diff --git a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/TbMqttTransportComponent.java b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/TbMqttTransportComponent.java index b517cda103..0d034aebb2 100644 --- a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/TbMqttTransportComponent.java +++ b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/TbMqttTransportComponent.java @@ -21,7 +21,11 @@ import java.lang.annotation.Inherited; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +/** + * See also @TbMqttSslTransportComponent + */ + @Inherited @Retention(RetentionPolicy.RUNTIME) -@ConditionalOnExpression("'${service.type:null}'=='tb-transport' || ('${service.type:null}'=='monolith' && '${transport.api_enabled:true}'=='true' && '${transport.mqtt.enabled}'=='true')") +@ConditionalOnExpression("'${service.type:null}'=='tb-transport' || ('${service.type:null}'=='monolith' && '${transport.api_enabled:true}'=='true' && '${transport.mqtt.enabled:true}'=='true')") public @interface TbMqttTransportComponent {} diff --git a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/adaptors/JsonMqttAdaptor.java b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/adaptors/JsonMqttAdaptor.java index 64f7e5df4a..61a886a7db 100644 --- a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/adaptors/JsonMqttAdaptor.java +++ b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/adaptors/JsonMqttAdaptor.java @@ -45,10 +45,6 @@ import java.util.UUID; import static org.thingsboard.server.common.data.device.profile.MqttTopics.DEVICE_SOFTWARE_FIRMWARE_RESPONSES_TOPIC_FORMAT; - -/** - * @author Andrew Shvayka - */ @Component @Slf4j public class JsonMqttAdaptor implements MqttTransportAdaptor { @@ -122,7 +118,7 @@ public class JsonMqttAdaptor implements MqttTransportAdaptor { public Optional convertToGatewayPublish(MqttDeviceAwareSessionContext ctx, String deviceName, TransportProtos.GetAttributeResponseMsg responseMsg) throws AdaptorException { return processConvertFromGatewayAttributeResponseMsg(ctx, deviceName, responseMsg); } - + @Override public Optional convertToPublish(MqttDeviceAwareSessionContext ctx, TransportProtos.AttributeUpdateNotificationMsg notificationMsg, String topic) { return Optional.of(createMqttPublishMsg(ctx, topic, JsonConverter.toJson(notificationMsg))); diff --git a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/adaptors/MqttTransportAdaptor.java b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/adaptors/MqttTransportAdaptor.java index 012709c31f..356004246f 100644 --- a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/adaptors/MqttTransportAdaptor.java +++ b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/adaptors/MqttTransportAdaptor.java @@ -41,9 +41,6 @@ import org.thingsboard.server.transport.mqtt.session.MqttDeviceAwareSessionConte import java.util.Optional; -/** - * @author Andrew Shvayka - */ public interface MqttTransportAdaptor { ByteBufAllocator ALLOCATOR = new UnpooledByteBufAllocator(false); @@ -90,4 +87,5 @@ public interface MqttTransportAdaptor { payload.writeBytes(payloadInBytes); return new MqttPublishMessage(mqttFixedHeader, header, payload); } + } diff --git a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/adaptors/ProtoMqttAdaptor.java b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/adaptors/ProtoMqttAdaptor.java index fd10ad750e..4472bb77d2 100644 --- a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/adaptors/ProtoMqttAdaptor.java +++ b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/adaptors/ProtoMqttAdaptor.java @@ -48,7 +48,7 @@ public class ProtoMqttAdaptor implements MqttTransportAdaptor { public TransportProtos.PostTelemetryMsg convertToPostTelemetry(MqttDeviceAwareSessionContext ctx, MqttPublishMessage inbound) throws AdaptorException { DeviceSessionCtx deviceSessionCtx = (DeviceSessionCtx) ctx; byte[] bytes = toBytes(inbound.payload()); - Descriptors.Descriptor telemetryDynamicMsgDescriptor = ProtoConverter.validateDescriptor(deviceSessionCtx.getTelemetryDynamicMsgDescriptor()); + Descriptors.Descriptor telemetryDynamicMsgDescriptor = ProtoConverter.validateDescriptor(deviceSessionCtx.getTelemetryDynamicMessageDescriptor()); try { return JsonConverter.convertToTelemetryProto(JsonParser.parseString(ProtoConverter.dynamicMsgToJson(bytes, telemetryDynamicMsgDescriptor))); } catch (Exception e) { @@ -228,4 +228,5 @@ public class ProtoMqttAdaptor implements MqttTransportAdaptor { private int getRequestId(String topicName, String topic) { return Integer.parseInt(topicName.substring(topic.length())); } + } diff --git a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/session/AbstractGatewayDeviceSessionContext.java b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/session/AbstractGatewayDeviceSessionContext.java index 8ce0fc5c1e..5bb3c9c28f 100644 --- a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/session/AbstractGatewayDeviceSessionContext.java +++ b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/session/AbstractGatewayDeviceSessionContext.java @@ -33,9 +33,6 @@ import org.thingsboard.server.gen.transport.TransportProtos.SessionInfoProto; import java.util.UUID; import java.util.concurrent.ConcurrentMap; -/** - * Created by ashvayka on 19.01.17. - */ @ToString(callSuper = true) @Slf4j public abstract class AbstractGatewayDeviceSessionContext extends MqttDeviceAwareSessionContext implements SessionMsgListener { diff --git a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/session/AbstractGatewaySessionHandler.java b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/session/AbstractGatewaySessionHandler.java index fee2f04e24..a2ad982765 100644 --- a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/session/AbstractGatewaySessionHandler.java +++ b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/session/AbstractGatewaySessionHandler.java @@ -96,9 +96,6 @@ import static org.thingsboard.server.transport.mqtt.util.sparkplug.SparkplugConn import static org.thingsboard.server.transport.mqtt.util.sparkplug.SparkplugMessageType.STATE; import static org.thingsboard.server.transport.mqtt.util.sparkplug.SparkplugMessageType.messageName; -/** - * Created by ashvayka on 19.01.17. - */ @Slf4j public abstract class AbstractGatewaySessionHandler { @@ -108,6 +105,7 @@ public abstract class AbstractGatewaySessionHandler deviceCreationLockMap; + @Getter private final ConcurrentMap devices; private final ConcurrentMap> deviceFutures; protected final ConcurrentMap mqttQoSMap; @@ -259,12 +258,14 @@ public abstract class AbstractGatewaySessionHandler { ack(msg, MqttReasonCodes.PubAck.SUCCESS); log.trace("[{}][{}][{}] onDeviceConnectOk: [{}]", gateway.getTenantId(), gateway.getDeviceId(), sessionId, deviceName); }, - t -> logDeviceCreationError(t, deviceName)); + t -> processFailure(msgId, deviceName, CONNECT, ackSent, t)); } public void onDeviceUpdate(TransportProtos.SessionInfoProto sessionInfo, Device device, Optional deviceProfileOpt) { @@ -821,11 +822,7 @@ public abstract class AbstractGatewaySessionHandler getDevices() { - return this.devices; - } - - protected TransportServiceCallback getAggregatePubAckCallback( + protected TransportServiceCallback getAggregatePubAckCallback( final ChannelHandlerContext ctx, final int msgId, final String deviceName, @@ -915,4 +912,5 @@ public abstract class AbstractGatewaySessionHandler getDefaultAdaptor(); + case V2_JSON -> context.getJsonMqttAdaptor(); + case V2_PROTO -> context.getProtoMqttAdaptor(); + default -> useJsonPayloadFormatForDefaultDownlinkTopics ? context.getJsonMqttAdaptor() : getDefaultAdaptor(); + }; } private MqttTransportAdaptor getDefaultAdaptor() { @@ -269,7 +246,7 @@ public class DeviceSessionCtx extends MqttDeviceAwareSessionContext { } } - public Collection getMsgQueueSnapshot(){ + public Collection getMsgQueueSnapshot() { return Collections.unmodifiableCollection(msgQueue); } diff --git a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/session/GatewayDeviceSessionContext.java b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/session/GatewayDeviceSessionContext.java index a48ee50054..24d7888a81 100644 --- a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/session/GatewayDeviceSessionContext.java +++ b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/session/GatewayDeviceSessionContext.java @@ -22,9 +22,6 @@ import org.thingsboard.server.common.transport.auth.TransportDeviceInfo; import java.util.concurrent.ConcurrentMap; -/** - * Created by nickAS21 on 26.12.22 - */ @ToString(callSuper = true) public class GatewayDeviceSessionContext extends AbstractGatewayDeviceSessionContext { diff --git a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/session/GatewaySessionHandler.java b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/session/GatewaySessionHandler.java index 2980b2ad60..487fe1a541 100644 --- a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/session/GatewaySessionHandler.java +++ b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/session/GatewaySessionHandler.java @@ -28,9 +28,6 @@ import org.thingsboard.server.gen.transport.TransportProtos; import java.util.Optional; import java.util.UUID; -/** - * Created by nickAS21 on 26.12.22 - */ @Slf4j public class GatewaySessionHandler extends AbstractGatewaySessionHandler { diff --git a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/session/MqttDeviceAwareSessionContext.java b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/session/MqttDeviceAwareSessionContext.java index 9db81a4d8b..24d23d7bdc 100644 --- a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/session/MqttDeviceAwareSessionContext.java +++ b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/session/MqttDeviceAwareSessionContext.java @@ -25,9 +25,6 @@ import java.util.UUID; import java.util.concurrent.ConcurrentMap; import java.util.stream.Collectors; -/** - * Created by ashvayka on 30.08.18. - */ @ToString(callSuper = true) public abstract class MqttDeviceAwareSessionContext extends DeviceAwareSessionContext { @@ -47,7 +44,7 @@ public abstract class MqttDeviceAwareSessionContext extends DeviceAwareSessionCo .stream() .filter(entry -> entry.getKey().matches(topic)) .map(Map.Entry::getValue) - .collect(Collectors.toList()); + .toList(); if (!qosList.isEmpty()) { return MqttQoS.valueOf(qosList.get(0)); } else { diff --git a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/session/MqttTopicMatcher.java b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/session/MqttTopicMatcher.java index 950a1f5bd9..ad3c7b9897 100644 --- a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/session/MqttTopicMatcher.java +++ b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/session/MqttTopicMatcher.java @@ -15,26 +15,25 @@ */ package org.thingsboard.server.transport.mqtt.session; +import lombok.Getter; + import java.util.regex.Pattern; public class MqttTopicMatcher { + @Getter private final String topic; private final Pattern topicRegex; public MqttTopicMatcher(String topic) { - if(topic == null){ + if (topic == null) { throw new NullPointerException("topic"); } this.topic = topic; this.topicRegex = Pattern.compile(topic.replace("+", "[^/]+").replace("#", ".+") + "$"); } - public String getTopic() { - return topic; - } - - public boolean matches(String topic){ + public boolean matches(String topic) { return this.topicRegex.matcher(topic).matches(); } @@ -52,4 +51,5 @@ public class MqttTopicMatcher { public int hashCode() { return topic.hashCode(); } + } diff --git a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/session/SparkplugNodeSessionHandler.java b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/session/SparkplugNodeSessionHandler.java index f9aba81c90..9ba4c3f989 100644 --- a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/session/SparkplugNodeSessionHandler.java +++ b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/session/SparkplugNodeSessionHandler.java @@ -64,9 +64,6 @@ import static org.thingsboard.server.transport.mqtt.util.sparkplug.SparkplugMetr import static org.thingsboard.server.transport.mqtt.util.sparkplug.SparkplugTopicService.TOPIC_SPLIT_REGEXP; import static org.thingsboard.server.transport.mqtt.util.sparkplug.SparkplugTopicService.TOPIC_STATE_REGEXP; -/** - * Created by nickAS21 on 12.12.22 - */ @Slf4j @SpecVersion(spec = "sparkplug", version = "3.0.0") public class SparkplugNodeSessionHandler extends AbstractGatewaySessionHandler { diff --git a/common/transport/snmp/src/main/java/org/thingsboard/server/transport/snmp/SnmpTransportContext.java b/common/transport/snmp/src/main/java/org/thingsboard/server/transport/snmp/SnmpTransportContext.java index 56b4e00162..93ce3d1278 100644 --- a/common/transport/snmp/src/main/java/org/thingsboard/server/transport/snmp/SnmpTransportContext.java +++ b/common/transport/snmp/src/main/java/org/thingsboard/server/transport/snmp/SnmpTransportContext.java @@ -15,11 +15,14 @@ */ package org.thingsboard.server.transport.snmp; +import jakarta.annotation.PreDestroy; import lombok.Getter; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; import org.springframework.context.event.EventListener; import org.springframework.stereotype.Component; +import org.thingsboard.common.util.ThingsBoardThreadFactory; import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.DeviceProfile; import org.thingsboard.server.common.data.DeviceTransportType; @@ -53,9 +56,12 @@ import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Optional; +import java.util.Set; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentLinkedDeque; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; @TbSnmpTransportComponent @Component @@ -72,30 +78,52 @@ public class SnmpTransportContext extends TransportContext { private final SnmpAuthService snmpAuthService; private final Map sessions = new ConcurrentHashMap<>(); - private final Collection allSnmpDevicesIds = new ConcurrentLinkedDeque<>(); + private final Set allSnmpDevicesIds = ConcurrentHashMap.newKeySet(); + private final ExecutorService snmpExecutor = Executors.newSingleThreadExecutor(ThingsBoardThreadFactory.forName("snmp-bootstrap")); + + @Value("${transport.snmp.batch_retries}") + private int snmpBootstrapBatchRetries; @AfterStartUp(order = AfterStartUp.AFTER_TRANSPORT_SERVICE) public void fetchDevicesAndEstablishSessions() { - log.info("Initializing SNMP devices sessions"); + snmpExecutor.execute(this::bootstrapWithRetries); + } + private void bootstrapWithRetries() { + log.info("Initializing SNMP devices sessions"); int batchIndex = 0; int batchSize = 512; boolean nextBatchExists = true; while (nextBatchExists) { - TransportProtos.GetSnmpDevicesResponseMsg snmpDevicesResponse = protoEntityService.getSnmpDevicesIds(batchIndex, batchSize); - snmpDevicesResponse.getIdsList().stream() - .map(id -> new DeviceId(UUID.fromString(id))) - .peek(allSnmpDevicesIds::add) - .filter(deviceId -> balancingService.isManagedByCurrentTransport(deviceId.getId())) - .map(protoEntityService::getDeviceById) - .forEach(device -> getExecutor().execute(() -> establishDeviceSession(device))); - - nextBatchExists = snmpDevicesResponse.getHasNextPage(); - batchIndex++; + for (int attempt = 1; attempt <= snmpBootstrapBatchRetries; attempt++) { + try { + TransportProtos.GetSnmpDevicesResponseMsg snmpDevicesResponse = protoEntityService.getSnmpDevicesIds(batchIndex, batchSize); + snmpDevicesResponse.getIdsList().stream() + .map(id -> new DeviceId(UUID.fromString(id))) + .peek(allSnmpDevicesIds::add) + .filter(deviceId -> balancingService.isManagedByCurrentTransport(deviceId.getId())) + .map(protoEntityService::getDeviceById) + .forEach(device -> getExecutor().execute(() -> establishDeviceSession(device))); + nextBatchExists = snmpDevicesResponse.getHasNextPage(); + batchIndex++; + break; + } catch (Exception e) { + if (attempt >= snmpBootstrapBatchRetries) { + log.error("SNMP bootstrap: batch {} failed after {} attempts.", batchIndex, attempt, e); + return; + } + log.warn("SNMP bootstrap: batch {} attempt {}/{} failed.", batchIndex, attempt, snmpBootstrapBatchRetries, e); + try { + TimeUnit.SECONDS.sleep(10); + } catch (InterruptedException ex) { + log.warn("SNMP bootstrap interrupted. Stopping bootstrap task."); + return; + } + } + } } - - log.debug("Found all SNMP devices ids: {}", allSnmpDevicesIds); + log.debug("Found SNMP devices ids: {}", allSnmpDevicesIds); } private void establishDeviceSession(Device device) { @@ -300,4 +328,9 @@ public class SnmpTransportContext extends TransportContext { return sessions.values(); } + @PreDestroy + public void destroy() { + snmpExecutor.shutdown(); + } + } diff --git a/common/util/src/main/java/org/thingsboard/common/util/JacksonUtil.java b/common/util/src/main/java/org/thingsboard/common/util/JacksonUtil.java index cd61c7ac20..e3ae70c9a5 100644 --- a/common/util/src/main/java/org/thingsboard/common/util/JacksonUtil.java +++ b/common/util/src/main/java/org/thingsboard/common/util/JacksonUtil.java @@ -83,6 +83,12 @@ public class JacksonUtil { .addModule(new Jdk8Module()) .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) .build(); + public static final ObjectMapper CANONICAL_JSON_MAPPER = JsonMapper.builder() + .addModule(new Jdk8Module()) + .configure(SerializationFeature.ORDER_MAP_ENTRIES_BY_KEYS, true) + .configure(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY, true) + .serializationInclusion(com.fasterxml.jackson.annotation.JsonInclude.Include.NON_NULL) + .build(); public static ObjectMapper getObjectMapperWithJavaTimeModule() { return JsonMapper.builder() @@ -207,6 +213,23 @@ public class JacksonUtil { return data; } + public static String toCanonicalString(Object value) { + try { + if (value == null) { + return null; + } + + if (value instanceof JsonNode) { + Object pojo = CANONICAL_JSON_MAPPER.convertValue(value, Object.class); + return CANONICAL_JSON_MAPPER.writeValueAsString(pojo); + } + + return CANONICAL_JSON_MAPPER.writeValueAsString(value); + } catch (Exception e) { + throw new IllegalArgumentException("The given Json object value cannot be transformed to a canonical String: " + value, e); + } + } + public static T treeToValue(JsonNode node, Class clazz) { try { return OBJECT_MAPPER.treeToValue(node, clazz); diff --git a/dao/src/main/java/org/thingsboard/server/dao/ai/AiModelServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/ai/AiModelServiceImpl.java index b091a29247..102bf76ee6 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/ai/AiModelServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/ai/AiModelServiceImpl.java @@ -36,6 +36,7 @@ import org.thingsboard.server.dao.sql.JpaExecutorService; import java.util.Optional; import java.util.Set; +import static com.google.common.util.concurrent.MoreExecutors.directExecutor; import static org.thingsboard.server.dao.service.Validator.validatePageLink; @Service @@ -115,6 +116,12 @@ class AiModelServiceImpl extends CachedVersionedEntityService model); // necessary to cast to HasId } + @Override + public FluentFuture>> findEntityAsync(TenantId tenantId, EntityId entityId) { + return findAiModelByTenantIdAndIdAsync(tenantId, new AiModelId(entityId.getId())) + .transform(modelOpt -> modelOpt.map(model -> model), directExecutor()); // necessary to cast to HasId + } + @Override public long countByTenantId(TenantId tenantId) { return aiModelDao.countByTenantId(tenantId); diff --git a/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmService.java b/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmService.java index 5c3e4f3c79..9696a4cf31 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmService.java @@ -15,7 +15,6 @@ */ package org.thingsboard.server.dao.alarm; - import com.fasterxml.jackson.databind.JsonNode; import com.google.common.util.concurrent.FluentFuture; import com.google.common.util.concurrent.ListenableFuture; @@ -81,6 +80,7 @@ import java.util.concurrent.ExecutionException; import java.util.stream.Collectors; import java.util.stream.Stream; +import static com.google.common.util.concurrent.MoreExecutors.directExecutor; import static org.thingsboard.server.dao.service.Validator.validateEntityDataPageLink; import static org.thingsboard.server.dao.service.Validator.validateId; @@ -97,8 +97,8 @@ public class BaseAlarmService extends AbstractCachedEntityService>> findEntityAsync(TenantId tenantId, EntityId entityId) { + return FluentFuture.from(findAlarmByIdAsync(tenantId, new AlarmId(entityId.getId()))) + .transform(Optional::ofNullable, directExecutor()); + } + @Override public EntityType getEntityType() { return EntityType.ALARM; diff --git a/dao/src/main/java/org/thingsboard/server/dao/asset/AssetProfileServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/asset/AssetProfileServiceImpl.java index 6bf44e4da1..4ddbabb5b6 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/asset/AssetProfileServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/asset/AssetProfileServiceImpl.java @@ -15,6 +15,7 @@ */ package org.thingsboard.server.dao.asset; +import com.google.common.util.concurrent.FluentFuture; import lombok.extern.slf4j.Slf4j; import org.hibernate.exception.ConstraintViolationException; import org.springframework.beans.factory.annotation.Autowired; @@ -49,6 +50,7 @@ import java.util.Map; import java.util.Optional; import java.util.stream.Collectors; +import static com.google.common.util.concurrent.MoreExecutors.directExecutor; import static org.thingsboard.server.dao.service.Validator.validateId; @Service("AssetProfileDaoService") @@ -323,6 +325,12 @@ public class AssetProfileServiceImpl extends CachedVersionedEntityService>> findEntityAsync(TenantId tenantId, EntityId entityId) { + return FluentFuture.from(assetProfileDao.findByIdAsync(tenantId, entityId.getId())) + .transform(Optional::ofNullable, directExecutor()); + } + @Override public EntityType getEntityType() { return EntityType.ASSET_PROFILE; diff --git a/dao/src/main/java/org/thingsboard/server/dao/asset/BaseAssetService.java b/dao/src/main/java/org/thingsboard/server/dao/asset/BaseAssetService.java index fed201d403..b8dc347a09 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/asset/BaseAssetService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/asset/BaseAssetService.java @@ -15,7 +15,7 @@ */ package org.thingsboard.server.dao.asset; - +import com.google.common.util.concurrent.FluentFuture; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.MoreExecutors; @@ -62,6 +62,7 @@ import java.util.List; import java.util.Optional; import java.util.stream.Collectors; +import static com.google.common.util.concurrent.MoreExecutors.directExecutor; import static org.thingsboard.server.dao.DaoUtil.toUUIDs; import static org.thingsboard.server.dao.service.Validator.validateId; import static org.thingsboard.server.dao.service.Validator.validateIds; @@ -93,8 +94,8 @@ public class BaseAssetService extends AbstractCachedEntityService keys = new ArrayList<>(2); keys.add(new AssetCacheKey(event.getTenantId(), event.getNewName())); @@ -519,6 +520,12 @@ public class BaseAssetService extends AbstractCachedEntityService>> findEntityAsync(TenantId tenantId, EntityId entityId) { + return FluentFuture.from(findAssetByIdAsync(tenantId, new AssetId(entityId.getId()))) + .transform(Optional::ofNullable, directExecutor()); + } + @Override public long countByTenantId(TenantId tenantId) { return assetDao.countByTenantId(tenantId); diff --git a/dao/src/main/java/org/thingsboard/server/dao/cf/BaseCalculatedFieldService.java b/dao/src/main/java/org/thingsboard/server/dao/cf/BaseCalculatedFieldService.java index c0cb886747..c9a53d795e 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/cf/BaseCalculatedFieldService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/cf/BaseCalculatedFieldService.java @@ -15,6 +15,7 @@ */ package org.thingsboard.server.dao.cf; +import com.google.common.util.concurrent.FluentFuture; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; @@ -38,6 +39,7 @@ import org.thingsboard.server.dao.service.DataValidator; import java.util.List; import java.util.Optional; +import static com.google.common.util.concurrent.MoreExecutors.directExecutor; import static org.thingsboard.server.dao.service.Validator.validateId; import static org.thingsboard.server.dao.service.Validator.validatePageLink; @@ -234,6 +236,12 @@ public class BaseCalculatedFieldService extends AbstractEntityService implements return Optional.ofNullable(findById(tenantId, new CalculatedFieldId(entityId.getId()))); } + @Override + public FluentFuture>> findEntityAsync(TenantId tenantId, EntityId entityId) { + return FluentFuture.from(calculatedFieldDao.findByIdAsync(tenantId, entityId.getId())) + .transform(Optional::ofNullable, directExecutor()); + } + @Override public EntityType getEntityType() { return EntityType.CALCULATED_FIELD; diff --git a/dao/src/main/java/org/thingsboard/server/dao/customer/CustomerServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/customer/CustomerServiceImpl.java index b06902d95e..9aee422030 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/customer/CustomerServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/customer/CustomerServiceImpl.java @@ -16,6 +16,7 @@ package org.thingsboard.server.dao.customer; import com.fasterxml.jackson.databind.JsonNode; +import com.google.common.util.concurrent.FluentFuture; import com.google.common.util.concurrent.ListenableFuture; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; @@ -55,6 +56,7 @@ import java.util.ArrayList; import java.util.List; import java.util.Optional; +import static com.google.common.util.concurrent.MoreExecutors.directExecutor; import static org.thingsboard.server.dao.service.Validator.validateId; @Service("CustomerDaoService") @@ -285,6 +287,12 @@ public class CustomerServiceImpl extends AbstractCachedEntityService>> findEntityAsync(TenantId tenantId, EntityId entityId) { + return FluentFuture.from(findCustomerByIdAsync(tenantId, new CustomerId(entityId.getId()))) + .transform(Optional::ofNullable, directExecutor()); + } + @Override public long countByTenantId(TenantId tenantId) { return customerDao.countByTenantId(tenantId); diff --git a/dao/src/main/java/org/thingsboard/server/dao/dashboard/DashboardServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/dashboard/DashboardServiceImpl.java index 1b21310237..9d8abe467c 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/dashboard/DashboardServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/dashboard/DashboardServiceImpl.java @@ -15,6 +15,7 @@ */ package org.thingsboard.server.dao.dashboard; +import com.google.common.util.concurrent.FluentFuture; import com.google.common.util.concurrent.ListenableFuture; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -61,6 +62,7 @@ import java.util.List; import java.util.Map; import java.util.Optional; +import static com.google.common.util.concurrent.MoreExecutors.directExecutor; import static org.thingsboard.server.dao.service.Validator.validateId; @Service("DashboardDaoService") @@ -70,6 +72,7 @@ public class DashboardServiceImpl extends AbstractEntityService implements Dashb public static final String INCORRECT_DASHBOARD_ID = "Incorrect dashboardId "; public static final String INCORRECT_TENANT_ID = "Incorrect tenantId "; + @Autowired private DashboardDao dashboardDao; @@ -424,6 +427,12 @@ public class DashboardServiceImpl extends AbstractEntityService implements Dashb return Optional.ofNullable(findDashboardById(tenantId, new DashboardId(entityId.getId()))); } + @Override + public FluentFuture>> findEntityAsync(TenantId tenantId, EntityId entityId) { + return FluentFuture.from(findDashboardByIdAsync(tenantId, new DashboardId(entityId.getId()))) + .transform(Optional::ofNullable, directExecutor()); + } + @Override public long countByTenantId(TenantId tenantId) { return dashboardDao.countByTenantId(tenantId); diff --git a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceCredentialsEvictEvent.java b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceCredentialsEvictEvent.java index ca265e78b1..33b410bcfe 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceCredentialsEvictEvent.java +++ b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceCredentialsEvictEvent.java @@ -18,9 +18,9 @@ package org.thingsboard.server.dao.device; import lombok.Data; @Data -class DeviceCredentialsEvictEvent { +public class DeviceCredentialsEvictEvent { - private final String newCedentialsId; + private final String newCredentialsId; private final String oldCredentialsId; } diff --git a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceCredentialsServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceCredentialsServiceImpl.java index 12859129a2..3423a74543 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceCredentialsServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceCredentialsServiceImpl.java @@ -47,6 +47,8 @@ import org.thingsboard.server.dao.exception.DataValidationException; import org.thingsboard.server.dao.exception.DeviceCredentialsValidationException; import org.thingsboard.server.dao.service.validator.DeviceCredentialsDataValidator; +import java.util.Objects; + import static org.thingsboard.server.dao.service.Validator.validateId; import static org.thingsboard.server.dao.service.Validator.validateString; @@ -61,8 +63,8 @@ public class DeviceCredentialsServiceImpl extends AbstractCachedEntityService JacksonUtil.valueToTree(deviceCredentials.getCredentialsId()); + case X509_CERTIFICATE -> JacksonUtil.valueToTree(deviceCredentials.getCredentialsValue()); + default -> JacksonUtil.fromString(deviceCredentials.getCredentialsValue(), JsonNode.class); + }; } private void formatSimpleMqttCredentials(DeviceCredentials deviceCredentials) { @@ -407,4 +407,11 @@ public class DeviceCredentialsServiceImpl extends AbstractCachedEntityService>> findEntityAsync(TenantId tenantId, EntityId entityId) { + return FluentFuture.from(deviceProfileDao.findByIdAsync(tenantId, entityId.getId())) + .transform(Optional::ofNullable, directExecutor()); + } + @Override public EntityType getEntityType() { return EntityType.DEVICE_PROFILE; @@ -432,8 +440,7 @@ public class DeviceProfileServiceImpl extends CachedVersionedEntityService 1) { return EncryptionUtil.certTrimNewLinesForChainInDeviceProfile(certificateValue); } - } catch (CertificateException ignored) { - } + } catch (CertificateException ignored) {} return EncryptionUtil.certTrimNewLines(certificateValue); } diff --git a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java index 6d993f3e3d..4a6e6ce9be 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java @@ -16,6 +16,7 @@ package org.thingsboard.server.dao.device; import com.fasterxml.jackson.databind.node.ObjectNode; +import com.google.common.util.concurrent.FluentFuture; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.MoreExecutors; @@ -89,6 +90,7 @@ import java.util.List; import java.util.Optional; import java.util.UUID; +import static com.google.common.util.concurrent.MoreExecutors.directExecutor; import static org.thingsboard.server.dao.DaoUtil.toUUIDs; import static org.thingsboard.server.dao.service.Validator.validateId; import static org.thingsboard.server.dao.service.Validator.validateIds; @@ -126,23 +128,21 @@ public class DeviceServiceImpl extends CachedVersionedEntityService INCORRECT_DEVICE_ID + id); - if (TenantId.SYS_TENANT_ID.equals(tenantId)) { - return cache.get(new DeviceCacheKey(deviceId), - () -> deviceDao.findById(tenantId, deviceId.getId())); - } else { - return cache.get(new DeviceCacheKey(tenantId, deviceId), - () -> deviceDao.findDeviceByTenantIdAndId(tenantId, deviceId.getId())); - } + return findDeviceByIdInternal(tenantId, deviceId); } @Override public ListenableFuture findDeviceByIdAsync(TenantId tenantId, DeviceId deviceId) { log.trace("Executing findDeviceByIdAsync [{}]", deviceId); validateId(deviceId, id -> INCORRECT_DEVICE_ID + id); + return executor.submit(() -> findDeviceByIdInternal(tenantId, deviceId)); + } + + private Device findDeviceByIdInternal(TenantId tenantId, DeviceId deviceId) { if (TenantId.SYS_TENANT_ID.equals(tenantId)) { - return deviceDao.findByIdAsync(tenantId, deviceId.getId()); + return cache.get(new DeviceCacheKey(deviceId), () -> deviceDao.findById(tenantId, deviceId.getId())); } else { - return deviceDao.findDeviceByTenantIdAndIdAsync(tenantId, deviceId.getId()); + return cache.get(new DeviceCacheKey(tenantId, deviceId), () -> deviceDao.findDeviceByTenantIdAndId(tenantId, deviceId.getId())); } } @@ -256,8 +256,8 @@ public class DeviceServiceImpl extends CachedVersionedEntityService toEvict = new ArrayList<>(3); toEvict.add(new DeviceCacheKey(event.getTenantId(), event.getNewName())); @@ -729,6 +729,12 @@ public class DeviceServiceImpl extends CachedVersionedEntityService>> findEntityAsync(TenantId tenantId, EntityId entityId) { + return FluentFuture.from(findDeviceByIdAsync(tenantId, new DeviceId(entityId.getId()))) + .transform(Optional::ofNullable, directExecutor()); + } + @Override public EntityType getEntityType() { return EntityType.DEVICE; diff --git a/dao/src/main/java/org/thingsboard/server/dao/domain/DomainServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/domain/DomainServiceImpl.java index c12d4d915e..e4e569c00a 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/domain/DomainServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/domain/DomainServiceImpl.java @@ -15,6 +15,7 @@ */ package org.thingsboard.server.dao.domain; +import com.google.common.util.concurrent.FluentFuture; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @@ -39,17 +40,16 @@ import org.thingsboard.server.dao.service.validator.DomainDataValidator; import java.util.Comparator; import java.util.List; -import java.util.Map; import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; +import static com.google.common.util.concurrent.MoreExecutors.directExecutor; + @Slf4j @Service public class DomainServiceImpl extends AbstractEntityService implements DomainService { - public static final String INCORRECT_TENANT_ID = "Incorrect tenantId "; - @Autowired private OAuth2ClientDao oauth2ClientDao; @Autowired @@ -66,8 +66,7 @@ public class DomainServiceImpl extends AbstractEntityService implements DomainSe eventPublisher.publishEvent(SaveEntityEvent.builder().tenantId(tenantId).entityId(savedDomain.getId()).entity(savedDomain).build()); return savedDomain; } catch (Exception e) { - checkConstraintViolation(e, - Map.of("domain_name_key", "Domain with such name and scheme already exists!")); + checkConstraintViolation(e, "domain_name_key", "Domain with such name and scheme already exists!"); throw e; } } @@ -142,6 +141,12 @@ public class DomainServiceImpl extends AbstractEntityService implements DomainSe return Optional.ofNullable(findDomainById(tenantId, new DomainId(entityId.getId()))); } + @Override + public FluentFuture>> findEntityAsync(TenantId tenantId, EntityId entityId) { + return FluentFuture.from(domainDao.findByIdAsync(tenantId, entityId.getId())) + .transform(Optional::ofNullable, directExecutor()); + } + @Override @Transactional public void deleteEntity(TenantId tenantId, EntityId id, boolean force) { @@ -163,4 +168,5 @@ public class DomainServiceImpl extends AbstractEntityService implements DomainSe public EntityType getEntityType() { return EntityType.DOMAIN; } + } diff --git a/dao/src/main/java/org/thingsboard/server/dao/edge/EdgeServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/edge/EdgeServiceImpl.java index 0655d05572..f0658ba658 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/edge/EdgeServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/edge/EdgeServiceImpl.java @@ -17,6 +17,7 @@ package org.thingsboard.server.dao.edge; import com.fasterxml.jackson.databind.node.ArrayNode; import com.fasterxml.jackson.databind.node.ObjectNode; +import com.google.common.util.concurrent.FluentFuture; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.MoreExecutors; @@ -83,6 +84,7 @@ import java.util.Optional; import java.util.UUID; import java.util.stream.Collectors; +import static com.google.common.util.concurrent.MoreExecutors.directExecutor; import static org.thingsboard.server.dao.DaoUtil.toUUIDs; import static org.thingsboard.server.dao.edge.BaseRelatedEdgesService.RELATED_EDGES_CACHE_ITEMS; import static org.thingsboard.server.dao.service.Validator.validateId; @@ -137,8 +139,8 @@ public class EdgeServiceImpl extends AbstractCachedEntityService keys = new ArrayList<>(2); keys.add(new EdgeCacheKey(event.getTenantId(), event.getNewName())); @@ -629,6 +631,12 @@ public class EdgeServiceImpl extends AbstractCachedEntityService>> findEntityAsync(TenantId tenantId, EntityId entityId) { + return FluentFuture.from(findEdgeByIdAsync(tenantId, new EdgeId(entityId.getId()))) + .transform(Optional::ofNullable, directExecutor()); + } + @Override public EntityType getEntityType() { return EntityType.EDGE; diff --git a/dao/src/main/java/org/thingsboard/server/dao/entity/BaseEntityService.java b/dao/src/main/java/org/thingsboard/server/dao/entity/BaseEntityService.java index 2fca546fc9..b512f353f5 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/entity/BaseEntityService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/entity/BaseEntityService.java @@ -15,6 +15,7 @@ */ package org.thingsboard.server.dao.entity; +import com.google.common.util.concurrent.FluentFuture; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Lazy; @@ -67,15 +68,13 @@ import java.util.concurrent.ExecutionException; import java.util.function.Function; import java.util.stream.Collectors; +import static com.google.common.util.concurrent.MoreExecutors.directExecutor; import static org.thingsboard.server.common.data.id.EntityId.NULL_UUID; import static org.thingsboard.server.common.data.query.EntityFilterType.ENTITY_NAME; import static org.thingsboard.server.common.data.query.EntityFilterType.ENTITY_TYPE; import static org.thingsboard.server.dao.service.Validator.validateEntityDataPageLink; import static org.thingsboard.server.dao.service.Validator.validateId; -/** - * Created by ashvayka on 04.05.17. - */ @Service @Slf4j public class BaseEntityService extends AbstractEntityService implements EntityService { @@ -93,7 +92,7 @@ public class BaseEntityService extends AbstractEntityService implements EntitySe @Autowired @Lazy - EntityServiceRegistry entityServiceRegistry; + private EntityServiceRegistry entityServiceRegistry; @Autowired private EdqsService edqsService; @@ -198,6 +197,11 @@ public class BaseEntityService extends AbstractEntityService implements EntitySe return fetchAndConvert(tenantId, entityId, this::getCustomerId); } + @Override + public FluentFuture> fetchEntityCustomerIdAsync(TenantId tenantId, EntityId entityId) { + return fetchAndConvertAsync(tenantId, entityId, this::getCustomerId); + } + @Override public Optional fetchNameLabelAndCustomerDetails(TenantId tenantId, EntityId entityId) { log.trace("Executing fetchNameLabelAndCustomerDetails [{}]", entityId); @@ -239,6 +243,12 @@ public class BaseEntityService extends AbstractEntityService implements EntitySe return entityOpt.map(converter); } + private FluentFuture> fetchAndConvertAsync(TenantId tenantId, EntityId entityId, Function, T> converter) { + EntityDaoService entityDaoService = entityServiceRegistry.getServiceByEntityType(entityId.getEntityType()); + return entityDaoService.findEntityAsync(tenantId, entityId) + .transform(entityOpt -> entityOpt.map(converter), directExecutor()); + } + private String getName(HasId entity) { return entity instanceof HasName ? ((HasName) entity).getName() : null; } @@ -329,7 +339,7 @@ public class BaseEntityService extends AbstractEntityService implements EntitySe } if ((query.getEntityFields() == null || query.getEntityFields().isEmpty()) && - (query.getLatestValues() == null || query.getLatestValues().isEmpty())) { + (query.getLatestValues() == null || query.getLatestValues().isEmpty())) { return false; } diff --git a/dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewServiceImpl.java index 0e742e20db..3128036e0e 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewServiceImpl.java @@ -16,6 +16,7 @@ package org.thingsboard.server.dao.entityview; import com.google.common.base.Function; +import com.google.common.util.concurrent.FluentFuture; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.MoreExecutors; @@ -60,13 +61,11 @@ import java.util.List; import java.util.Optional; import java.util.stream.Collectors; +import static com.google.common.util.concurrent.MoreExecutors.directExecutor; import static org.thingsboard.server.dao.service.Validator.validateId; import static org.thingsboard.server.dao.service.Validator.validatePageLink; import static org.thingsboard.server.dao.service.Validator.validateString; -/** - * Created by Victor Basanets on 8/28/2017. - */ @Service("EntityViewDaoService") @Slf4j public class EntityViewServiceImpl extends CachedVersionedEntityService implements EntityViewService { @@ -176,6 +175,17 @@ public class EntityViewServiceImpl extends CachedVersionedEntityService INCORRECT_ENTITY_VIEW_ID + id); + return findEntityViewByIdInternal(tenantId, entityViewId, putInCache); + } + + @Override + public ListenableFuture findEntityViewByIdAsync(TenantId tenantId, EntityViewId entityViewId) { + log.trace("Executing findEntityViewByIdAsync [{}]", entityViewId); + validateId(entityViewId, id -> INCORRECT_ENTITY_VIEW_ID + id); + return service.submit(() -> findEntityViewByIdInternal(tenantId, entityViewId, true)); + } + + private EntityView findEntityViewByIdInternal(TenantId tenantId, EntityViewId entityViewId, boolean putInCache) { EntityViewCacheValue value = cache.get(EntityViewCacheKey.byId(entityViewId), () -> { EntityView entityView = entityViewDao.findById(tenantId, entityViewId.getId()); return new EntityViewCacheValue(entityView, null); @@ -190,7 +200,6 @@ public class EntityViewServiceImpl extends CachedVersionedEntityService entityViewDao.findEntityViewByTenantIdAndName(tenantId.getId(), name).orElse(null) , EntityViewCacheValue::getEntityView, v -> new EntityViewCacheValue(v, null), true); - } @Override @@ -307,13 +316,6 @@ public class EntityViewServiceImpl extends CachedVersionedEntityService findEntityViewByIdAsync(TenantId tenantId, EntityViewId entityViewId) { - log.trace("Executing findEntityViewByIdAsync [{}]", entityViewId); - validateId(entityViewId, id -> INCORRECT_ENTITY_VIEW_ID + id); - return entityViewDao.findByIdAsync(tenantId, entityViewId.getId()); - } - @Override public ListenableFuture> findEntityViewsByTenantIdAndEntityIdAsync(TenantId tenantId, EntityId entityId) { log.trace("Executing findEntityViewsByTenantIdAndEntityIdAsync, tenantId [{}], entityId [{}]", tenantId, entityId); @@ -479,6 +481,12 @@ public class EntityViewServiceImpl extends CachedVersionedEntityService>> findEntityAsync(TenantId tenantId, EntityId entityId) { + return FluentFuture.from(findEntityViewByIdAsync(tenantId, new EntityViewId(entityId.getId()))) + .transform(Optional::ofNullable, directExecutor()); + } + @Override public EntityType getEntityType() { return EntityType.ENTITY_VIEW; diff --git a/dao/src/main/java/org/thingsboard/server/dao/job/DefaultJobService.java b/dao/src/main/java/org/thingsboard/server/dao/job/DefaultJobService.java index 360aa0063b..06f219ca3d 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/job/DefaultJobService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/job/DefaultJobService.java @@ -15,6 +15,7 @@ */ package org.thingsboard.server.dao.job; +import com.google.common.util.concurrent.FluentFuture; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; @@ -44,6 +45,7 @@ import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; +import static com.google.common.util.concurrent.MoreExecutors.directExecutor; import static org.thingsboard.server.common.data.job.JobStatus.CANCELLED; import static org.thingsboard.server.common.data.job.JobStatus.COMPLETED; import static org.thingsboard.server.common.data.job.JobStatus.FAILED; @@ -87,11 +89,7 @@ public class DefaultJobService extends AbstractEntityService implements JobServi } job.getResult().setCancellationTs(System.currentTimeMillis()); JobStatus prevStatus = job.getStatus(); - if (job.getStatus() == QUEUED) { - job.setStatus(CANCELLED); // setting cancelled status right away, because we don't expect stats for cancelled tasks - } else if (job.getStatus() == PENDING) { - job.setStatus(RUNNING); - } + job.setStatus(CANCELLED); saveJob(tenantId, job, true, prevStatus); } @@ -145,7 +143,7 @@ public class DefaultJobService extends AbstractEntityService implements JobServi } } - if (job.getStatus() == RUNNING) { + if (job.getStatus().isOneOf(RUNNING, CANCELLED)) { if (result.getTotalCount() != null && result.getCompletedCount() >= result.getTotalCount()) { if (result.getCancellationTs() > 0) { job.setStatus(CANCELLED); @@ -193,7 +191,7 @@ public class DefaultJobService extends AbstractEntityService implements JobServi private void checkWaitingJobs(TenantId tenantId, JobType jobType) { Job queuedJob = jobDao.findOldestByTenantIdAndTypeAndStatusForUpdate(tenantId, jobType, QUEUED); - if (queuedJob == null) { + if (queuedJob == null || jobDao.existsByTenantIdAndTypeAndStatusOneOf(tenantId, jobType, PENDING, RUNNING)) { return; } queuedJob.setStatus(PENDING); @@ -245,6 +243,12 @@ public class DefaultJobService extends AbstractEntityService implements JobServi return Optional.ofNullable(findJobById(tenantId, (JobId) entityId)); } + @Override + public FluentFuture>> findEntityAsync(TenantId tenantId, EntityId entityId) { + return FluentFuture.from(jobDao.findByIdAsync(tenantId, entityId.getId())) + .transform(Optional::ofNullable, directExecutor()); + } + @Override public void deleteEntity(TenantId tenantId, EntityId id, boolean force) { jobDao.removeById(tenantId, id.getId()); diff --git a/dao/src/main/java/org/thingsboard/server/dao/mobile/MobileAppBundleServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/mobile/MobileAppBundleServiceImpl.java index d20623ad66..98f4a612e7 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/mobile/MobileAppBundleServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/mobile/MobileAppBundleServiceImpl.java @@ -15,6 +15,7 @@ */ package org.thingsboard.server.dao.mobile; +import com.google.common.util.concurrent.FluentFuture; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @@ -40,11 +41,11 @@ import org.thingsboard.server.dao.service.DataValidator; import java.util.Comparator; import java.util.List; -import java.util.Map; import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; +import static com.google.common.util.concurrent.MoreExecutors.directExecutor; import static org.thingsboard.server.dao.service.Validator.checkNotNull; @Slf4j @@ -60,7 +61,6 @@ public class MobileAppBundleServiceImpl extends AbstractEntityService implements @Autowired private DataValidator mobileAppBundleDataValidator; - @Override public MobileAppBundle saveMobileAppBundle(TenantId tenantId, MobileAppBundle mobileAppBundle) { log.trace("Executing saveMobileAppBundle [{}]", mobileAppBundle); @@ -71,8 +71,8 @@ public class MobileAppBundleServiceImpl extends AbstractEntityService implements return savedMobileApp; } catch (Exception e) { checkConstraintViolation(e, - Map.of("mobile_app_bundle_android_app_id_key", "Android mobile app is already configured in another bundle!", - "mobile_app_bundle_ios_app_id_key", "IOS mobile app is already configured in another bundle!")); + "mobile_app_bundle_android_app_id_key", "Android mobile app is already configured in another bundle!", + "mobile_app_bundle_ios_app_id_key", "IOS mobile app is already configured in another bundle!"); throw e; } } @@ -149,6 +149,12 @@ public class MobileAppBundleServiceImpl extends AbstractEntityService implements return Optional.ofNullable(findMobileAppBundleById(tenantId, new MobileAppBundleId(entityId.getId()))); } + @Override + public FluentFuture>> findEntityAsync(TenantId tenantId, EntityId entityId) { + return FluentFuture.from(mobileAppBundleDao.findByIdAsync(tenantId, entityId.getId())) + .transform(Optional::ofNullable, directExecutor()); + } + @Override @Transactional public void deleteEntity(TenantId tenantId, EntityId id, boolean force) { @@ -167,4 +173,5 @@ public class MobileAppBundleServiceImpl extends AbstractEntityService implements .collect(Collectors.toList()); mobileAppBundleInfo.setOauth2ClientInfos(clients); } + } diff --git a/dao/src/main/java/org/thingsboard/server/dao/mobile/MobileAppServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/mobile/MobileAppServiceImpl.java index f4e803b28e..b7785496d4 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/mobile/MobileAppServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/mobile/MobileAppServiceImpl.java @@ -15,6 +15,7 @@ */ package org.thingsboard.server.dao.mobile; +import com.google.common.util.concurrent.FluentFuture; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @@ -35,9 +36,10 @@ import org.thingsboard.server.dao.eventsourcing.SaveEntityEvent; import org.thingsboard.server.dao.service.DataValidator; import org.thingsboard.server.dao.service.Validator; -import java.util.Map; import java.util.Optional; +import static com.google.common.util.concurrent.MoreExecutors.directExecutor; + @Slf4j @Service public class MobileAppServiceImpl extends AbstractEntityService implements MobileAppService { @@ -58,8 +60,7 @@ public class MobileAppServiceImpl extends AbstractEntityService implements Mobil eventPublisher.publishEvent(SaveEntityEvent.builder().tenantId(tenantId).entity(savedMobileApp).build()); return savedMobileApp; } catch (Exception e) { - checkConstraintViolation(e, - Map.of("mobile_app_pkg_name_platform_unq_key", "Mobile app with such package name and platform already exists!")); + checkConstraintViolation(e, "mobile_app_pkg_name_platform_unq_key", "Mobile app with such package name and platform already exists!"); throw e; } } @@ -88,6 +89,12 @@ public class MobileAppServiceImpl extends AbstractEntityService implements Mobil return Optional.ofNullable(findMobileAppById(tenantId, new MobileAppId(entityId.getId()))); } + @Override + public FluentFuture>> findEntityAsync(TenantId tenantId, EntityId entityId) { + return FluentFuture.from(mobileAppDao.findByIdAsync(tenantId, entityId.getId())) + .transform(Optional::ofNullable, directExecutor()); + } + @Override @Transactional public void deleteEntity(TenantId tenantId, EntityId id, boolean force) { @@ -117,4 +124,5 @@ public class MobileAppServiceImpl extends AbstractEntityService implements Mobil public EntityType getEntityType() { return EntityType.MOBILE_APP; } + } diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/sqlts/dictionary/KeyDictionaryCompositeKey.java b/dao/src/main/java/org/thingsboard/server/dao/model/sqlts/dictionary/KeyDictionaryCompositeKey.java index 4f3285b9bf..00e49ea703 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/model/sqlts/dictionary/KeyDictionaryCompositeKey.java +++ b/dao/src/main/java/org/thingsboard/server/dao/model/sqlts/dictionary/KeyDictionaryCompositeKey.java @@ -25,7 +25,7 @@ import java.io.Serializable; @Data @NoArgsConstructor @AllArgsConstructor -public class KeyDictionaryCompositeKey implements Serializable{ +public class KeyDictionaryCompositeKey implements Serializable { @Transient private static final long serialVersionUID = -4089175869616037523L; diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/sqlts/dictionary/KeyDictionaryEntry.java b/dao/src/main/java/org/thingsboard/server/dao/model/sqlts/dictionary/KeyDictionaryEntry.java index a95c7a2bc6..8365e8facc 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/model/sqlts/dictionary/KeyDictionaryEntry.java +++ b/dao/src/main/java/org/thingsboard/server/dao/model/sqlts/dictionary/KeyDictionaryEntry.java @@ -36,8 +36,7 @@ public final class KeyDictionaryEntry { @Column(name = KEY_COLUMN) private String key; - @Column(name = KEY_ID_COLUMN, unique = true, columnDefinition = "int") - @Generated - private int keyId; + @Column(name = KEY_ID_COLUMN, unique = true, columnDefinition = "int", insertable = false, updatable = false) + private Integer keyId; -} \ No newline at end of file +} diff --git a/dao/src/main/java/org/thingsboard/server/dao/notification/DefaultNotificationRequestService.java b/dao/src/main/java/org/thingsboard/server/dao/notification/DefaultNotificationRequestService.java index ffed043fe2..35c7839429 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/notification/DefaultNotificationRequestService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/notification/DefaultNotificationRequestService.java @@ -15,6 +15,7 @@ */ package org.thingsboard.server.dao.notification; +import com.google.common.util.concurrent.FluentFuture; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.context.ApplicationEventPublisher; @@ -38,6 +39,8 @@ import org.thingsboard.server.dao.service.DataValidator; import java.util.List; import java.util.Optional; +import static com.google.common.util.concurrent.MoreExecutors.directExecutor; + @Service @Slf4j @RequiredArgsConstructor @@ -129,13 +132,17 @@ public class DefaultNotificationRequestService implements NotificationRequestSer return Optional.ofNullable(findNotificationRequestById(tenantId, new NotificationRequestId(entityId.getId()))); } + @Override + public FluentFuture>> findEntityAsync(TenantId tenantId, EntityId entityId) { + return FluentFuture.from(notificationRequestDao.findByIdAsync(tenantId, entityId.getId())) + .transform(Optional::ofNullable, directExecutor()); + } + @Override public EntityType getEntityType() { return EntityType.NOTIFICATION_REQUEST; } - private static class NotificationRequestValidator extends DataValidator { - - } + private static class NotificationRequestValidator extends DataValidator {} } diff --git a/dao/src/main/java/org/thingsboard/server/dao/notification/DefaultNotificationRuleService.java b/dao/src/main/java/org/thingsboard/server/dao/notification/DefaultNotificationRuleService.java index c349b84f0a..b2f79c9555 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/notification/DefaultNotificationRuleService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/notification/DefaultNotificationRuleService.java @@ -15,6 +15,7 @@ */ package org.thingsboard.server.dao.notification; +import com.google.common.util.concurrent.FluentFuture; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.thingsboard.server.common.data.EntityType; @@ -33,9 +34,10 @@ import org.thingsboard.server.dao.eventsourcing.DeleteEntityEvent; import org.thingsboard.server.dao.eventsourcing.SaveEntityEvent; import java.util.List; -import java.util.Map; import java.util.Optional; +import static com.google.common.util.concurrent.MoreExecutors.directExecutor; + @Service @RequiredArgsConstructor public class DefaultNotificationRuleService extends AbstractEntityService implements NotificationRuleService, EntityDaoService { @@ -56,9 +58,7 @@ public class DefaultNotificationRuleService extends AbstractEntityService implem .created(notificationRule.getId() == null).build()); return savedRule; } catch (Exception e) { - checkConstraintViolation(e, Map.of( - "uq_notification_rule_name", "Notification rule with such name already exists" - )); + checkConstraintViolation(e, "uq_notification_rule_name", "Notification rule with such name already exists"); throw e; } } @@ -114,6 +114,12 @@ public class DefaultNotificationRuleService extends AbstractEntityService implem return Optional.ofNullable(findNotificationRuleById(tenantId, new NotificationRuleId(entityId.getId()))); } + @Override + public FluentFuture>> findEntityAsync(TenantId tenantId, EntityId entityId) { + return FluentFuture.from(notificationRuleDao.findByIdAsync(tenantId, entityId.getId())) + .transform(Optional::ofNullable, directExecutor()); + } + @Override public EntityType getEntityType() { return EntityType.NOTIFICATION_RULE; diff --git a/dao/src/main/java/org/thingsboard/server/dao/notification/DefaultNotificationService.java b/dao/src/main/java/org/thingsboard/server/dao/notification/DefaultNotificationService.java index 99efd18aee..8c5a051771 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/notification/DefaultNotificationService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/notification/DefaultNotificationService.java @@ -15,6 +15,7 @@ */ package org.thingsboard.server.dao.notification; +import com.google.common.util.concurrent.FluentFuture; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; @@ -37,6 +38,8 @@ import org.thingsboard.server.dao.sql.query.EntityKeyMapping; import java.util.Optional; import java.util.Set; +import static com.google.common.util.concurrent.MoreExecutors.directExecutor; + @Service @Slf4j @RequiredArgsConstructor @@ -95,6 +98,12 @@ public class DefaultNotificationService implements NotificationService, EntityDa return Optional.ofNullable(findNotificationById(tenantId, new NotificationId(entityId.getId()))); } + @Override + public FluentFuture>> findEntityAsync(TenantId tenantId, EntityId entityId) { + return FluentFuture.from(notificationDao.findByIdAsync(tenantId, entityId.getId())) + .transform(Optional::ofNullable, directExecutor()); + } + @Override public EntityType getEntityType() { return EntityType.NOTIFICATION; diff --git a/dao/src/main/java/org/thingsboard/server/dao/notification/DefaultNotificationTargetService.java b/dao/src/main/java/org/thingsboard/server/dao/notification/DefaultNotificationTargetService.java index e873b18c76..02a7e4b891 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/notification/DefaultNotificationTargetService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/notification/DefaultNotificationTargetService.java @@ -15,6 +15,7 @@ */ package org.thingsboard.server.dao.notification; +import com.google.common.util.concurrent.FluentFuture; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; @@ -47,13 +48,14 @@ import org.thingsboard.server.dao.eventsourcing.SaveEntityEvent; import org.thingsboard.server.dao.user.UserService; import java.util.List; -import java.util.Map; import java.util.Objects; import java.util.Optional; import java.util.stream.Collectors; import static org.apache.commons.collections4.CollectionUtils.isNotEmpty; +import static com.google.common.util.concurrent.MoreExecutors.directExecutor; + @Service @Slf4j @RequiredArgsConstructor @@ -72,9 +74,7 @@ public class DefaultNotificationTargetService extends AbstractEntityService impl .created(notificationTarget.getId() == null).build()); return savedTarget; } catch (Exception e) { - checkConstraintViolation(e, Map.of( - "uq_notification_target_name", "Recipients group with such name already exists" - )); + checkConstraintViolation(e, "uq_notification_target_name", "Recipients group with such name already exists"); throw e; } } @@ -229,6 +229,12 @@ public class DefaultNotificationTargetService extends AbstractEntityService impl return Optional.ofNullable(findNotificationTargetById(tenantId, new NotificationTargetId(entityId.getId()))); } + @Override + public FluentFuture>> findEntityAsync(TenantId tenantId, EntityId entityId) { + return FluentFuture.from(notificationTargetDao.findByIdAsync(tenantId, entityId.getId())) + .transform(Optional::ofNullable, directExecutor()); + } + @Override public EntityType getEntityType() { return EntityType.NOTIFICATION_TARGET; diff --git a/dao/src/main/java/org/thingsboard/server/dao/notification/DefaultNotificationTemplateService.java b/dao/src/main/java/org/thingsboard/server/dao/notification/DefaultNotificationTemplateService.java index 8e98714b85..4218e06881 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/notification/DefaultNotificationTemplateService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/notification/DefaultNotificationTemplateService.java @@ -15,6 +15,7 @@ */ package org.thingsboard.server.dao.notification; +import com.google.common.util.concurrent.FluentFuture; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.thingsboard.server.common.data.EntityType; @@ -37,6 +38,8 @@ import java.util.List; import java.util.Map; import java.util.Optional; +import static com.google.common.util.concurrent.MoreExecutors.directExecutor; + @Service @RequiredArgsConstructor public class DefaultNotificationTemplateService extends AbstractEntityService implements NotificationTemplateService, EntityDaoService { @@ -144,6 +147,12 @@ public class DefaultNotificationTemplateService extends AbstractEntityService im return Optional.ofNullable(findNotificationTemplateById(tenantId, new NotificationTemplateId(entityId.getId()))); } + @Override + public FluentFuture>> findEntityAsync(TenantId tenantId, EntityId entityId) { + return FluentFuture.from(notificationTemplateDao.findByIdAsync(tenantId, entityId.getId())) + .transform(Optional::ofNullable, directExecutor()); + } + @Override public EntityType getEntityType() { return EntityType.NOTIFICATION_TEMPLATE; diff --git a/dao/src/main/java/org/thingsboard/server/dao/oauth2/OAuth2ClientServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/oauth2/OAuth2ClientServiceImpl.java index 861633ec3b..a373d36580 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/oauth2/OAuth2ClientServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/oauth2/OAuth2ClientServiceImpl.java @@ -15,6 +15,7 @@ */ package org.thingsboard.server.dao.oauth2; +import com.google.common.util.concurrent.FluentFuture; import jakarta.transaction.Transactional; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; @@ -41,6 +42,7 @@ import java.util.List; import java.util.Optional; import java.util.stream.Collectors; +import static com.google.common.util.concurrent.MoreExecutors.directExecutor; @Slf4j @Service("OAuth2ClientService") @@ -107,7 +109,6 @@ public class OAuth2ClientServiceImpl extends AbstractEntityService implements OA .tenantId(tenantId) .entityId(oAuth2ClientId) .build()); - } @Override @@ -149,6 +150,12 @@ public class OAuth2ClientServiceImpl extends AbstractEntityService implements OA return Optional.ofNullable(findOAuth2ClientById(tenantId, new OAuth2ClientId(entityId.getId()))); } + @Override + public FluentFuture>> findEntityAsync(TenantId tenantId, EntityId entityId) { + return FluentFuture.from(oauth2ClientDao.findByIdAsync(tenantId, entityId.getId())) + .transform(Optional::ofNullable, directExecutor()); + } + @Override @Transactional public void deleteEntity(TenantId tenantId, EntityId id, boolean force) { diff --git a/dao/src/main/java/org/thingsboard/server/dao/ota/BaseOtaPackageService.java b/dao/src/main/java/org/thingsboard/server/dao/ota/BaseOtaPackageService.java index 343a2485ce..16894fe56c 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/ota/BaseOtaPackageService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/ota/BaseOtaPackageService.java @@ -17,6 +17,7 @@ package org.thingsboard.server.dao.ota; import com.google.common.hash.HashFunction; import com.google.common.hash.Hashing; +import com.google.common.util.concurrent.FluentFuture; import com.google.common.util.concurrent.ListenableFuture; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -47,6 +48,7 @@ import org.thingsboard.server.dao.service.PaginatedRemover; import java.nio.ByteBuffer; import java.util.Optional; +import static com.google.common.util.concurrent.MoreExecutors.directExecutor; import static org.thingsboard.server.dao.service.Validator.validateId; import static org.thingsboard.server.dao.service.Validator.validatePageLink; @@ -254,6 +256,12 @@ public class BaseOtaPackageService extends AbstractCachedEntityService>> findEntityAsync(TenantId tenantId, EntityId entityId) { + return FluentFuture.from(findOtaPackageInfoByIdAsync(tenantId, new OtaPackageId(entityId.getId()))) + .transform(Optional::ofNullable, directExecutor()); + } + @Override public EntityType getEntityType() { return EntityType.OTA_PACKAGE; diff --git a/dao/src/main/java/org/thingsboard/server/dao/queue/BaseQueueService.java b/dao/src/main/java/org/thingsboard/server/dao/queue/BaseQueueService.java index d36d5f2a15..248326a722 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/queue/BaseQueueService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/queue/BaseQueueService.java @@ -15,6 +15,7 @@ */ package org.thingsboard.server.dao.queue; +import com.google.common.util.concurrent.FluentFuture; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.hibernate.exception.ConstraintViolationException; @@ -42,6 +43,9 @@ import org.thingsboard.server.dao.tenant.TbTenantProfileCache; import java.util.List; import java.util.Optional; +import static com.google.common.util.concurrent.MoreExecutors.directExecutor; +import static org.thingsboard.server.dao.service.Validator.validateId; + @Service("QueueDaoService") @Slf4j @RequiredArgsConstructor @@ -127,7 +131,7 @@ public class BaseQueueService extends AbstractEntityService implements QueueServ @Override public void deleteQueuesByTenantId(TenantId tenantId) { - Validator.validateId(tenantId, "Incorrect tenant id for delete queues request."); + validateId(tenantId, __ -> "Incorrect tenant id for delete queues request."); tenantQueuesRemover.removeEntities(tenantId, tenantId); } @@ -141,24 +145,30 @@ public class BaseQueueService extends AbstractEntityService implements QueueServ return Optional.ofNullable(findQueueById(tenantId, new QueueId(entityId.getId()))); } + @Override + public FluentFuture>> findEntityAsync(TenantId tenantId, EntityId entityId) { + return FluentFuture.from(queueDao.findByIdAsync(tenantId, entityId.getId())) + .transform(Optional::ofNullable, directExecutor()); + } + @Override public EntityType getEntityType() { return EntityType.QUEUE; } - private PaginatedRemover tenantQueuesRemover = - new PaginatedRemover<>() { + private final PaginatedRemover tenantQueuesRemover = new PaginatedRemover<>() { - @Override - protected PageData findEntities(TenantId tenantId, TenantId id, PageLink pageLink) { - return queueDao.findQueuesByTenantId(id, pageLink); - } + @Override + protected PageData findEntities(TenantId tenantId, TenantId id, PageLink pageLink) { + return queueDao.findQueuesByTenantId(id, pageLink); + } - @Override - protected void removeEntity(TenantId tenantId, Queue entity) { - deleteQueue(tenantId, entity.getId()); - } - }; + @Override + protected void removeEntity(TenantId tenantId, Queue entity) { + deleteQueue(tenantId, entity.getId()); + } + + }; private TenantId getSystemOrIsolatedTenantId(TenantId tenantId) { if (!tenantId.equals(TenantId.SYS_TENANT_ID)) { @@ -167,7 +177,7 @@ public class BaseQueueService extends AbstractEntityService implements QueueServ return tenantId; } } - return TenantId.SYS_TENANT_ID; } + } diff --git a/dao/src/main/java/org/thingsboard/server/dao/queue/BaseQueueStatsService.java b/dao/src/main/java/org/thingsboard/server/dao/queue/BaseQueueStatsService.java index 9e4c7136d5..4091daac20 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/queue/BaseQueueStatsService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/queue/BaseQueueStatsService.java @@ -15,6 +15,7 @@ */ package org.thingsboard.server.dao.queue; +import com.google.common.util.concurrent.FluentFuture; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; @@ -35,6 +36,7 @@ import org.thingsboard.server.dao.service.Validator; import java.util.List; import java.util.Optional; +import static com.google.common.util.concurrent.MoreExecutors.directExecutor; import static org.thingsboard.server.dao.service.Validator.validateId; import static org.thingsboard.server.dao.service.Validator.validateIds; @@ -106,6 +108,12 @@ public class BaseQueueStatsService extends AbstractEntityService implements Queu return Optional.ofNullable(findQueueStatsById(tenantId, new QueueStatsId(entityId.getId()))); } + @Override + public FluentFuture>> findEntityAsync(TenantId tenantId, EntityId entityId) { + return FluentFuture.from(queueStatsDao.findByIdAsync(tenantId, entityId.getId())) + .transform(Optional::ofNullable, directExecutor()); + } + @Override public EntityType getEntityType() { return EntityType.QUEUE_STATS; diff --git a/dao/src/main/java/org/thingsboard/server/dao/resource/BaseImageService.java b/dao/src/main/java/org/thingsboard/server/dao/resource/BaseImageService.java index c16e37d30f..25ef83d556 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/resource/BaseImageService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/resource/BaseImageService.java @@ -17,11 +17,11 @@ package org.thingsboard.server.dao.resource; import com.fasterxml.jackson.databind.JsonNode; import jakarta.annotation.PostConstruct; -import lombok.Data; import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.RandomStringUtils; import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.Strings; import org.apache.commons.lang3.exception.ExceptionUtils; import org.apache.commons.lang3.tuple.Pair; import org.springframework.stereotype.Service; @@ -356,8 +356,8 @@ public class BaseImageService extends BaseResourceService implements ImageServic imageName = imageName + type + " image"; UpdateResult result = convertToImageUrl(entity.getTenantId(), imageName, entity.getImage(), Collections.emptyMap()); - entity.setImage(result.getValue()); - return result.isUpdated(); + entity.setImage(result.value()); + return result.updated(); } @Transactional(noRollbackFor = Exception.class) // we don't want transaction to rollback in case of an image processing failure @@ -373,8 +373,8 @@ public class BaseImageService extends BaseResourceService implements ImageServic Map imagesLinks = getResourcesLinks(widgetTypeDetails.getResources()); UpdateResult result = convertToImageUrl(tenantId, prefix + " image", widgetTypeDetails.getImage(), imagesLinks); - boolean updated = result.isUpdated(); - widgetTypeDetails.setImage(result.getValue()); + boolean updated = result.updated(); + widgetTypeDetails.setImage(result.value()); if (widgetTypeDetails.getDescriptor().isObject()) { JsonNode defaultConfig = widgetTypeDetails.getDefaultConfig(); @@ -397,8 +397,8 @@ public class BaseImageService extends BaseResourceService implements ImageServic Map imagesLinks = getResourcesLinks(dashboard.getResources()); var result = convertToImageUrl(tenantId, prefix + " image", dashboard.getImage(), imagesLinks); - boolean updated = result.isUpdated(); - dashboard.setImage(result.getValue()); + boolean updated = result.updated(); + dashboard.setImage(result.value()); updated |= convertToImageUrlsByMapping(tenantId, DASHBOARD_BASE64_MAPPING, Collections.singletonMap("prefix", prefix), dashboard.getConfiguration(), imagesLinks); updated |= convertToImageUrls(tenantId, prefix, dashboard.getConfiguration(), imagesLinks); @@ -409,10 +409,10 @@ public class BaseImageService extends BaseResourceService implements ImageServic AtomicBoolean updated = new AtomicBoolean(false); JacksonUtil.replaceAllByMapping(configuration, mapping, templateParams, (name, value) -> { UpdateResult result = convertToImageUrl(tenantId, name, value, links); - if (result.isUpdated()) { + if (result.updated()) { updated.set(true); } - return result.getValue(); + return result.value(); }); return updated.get(); } @@ -514,10 +514,10 @@ public class BaseImageService extends BaseResourceService implements ImageServic AtomicBoolean updated = new AtomicBoolean(false); JacksonUtil.replaceAll(root, title, (path, value) -> { UpdateResult result = convertToImageUrl(tenantId, path, value, true, links); - if (result.isUpdated()) { + if (result.updated()) { updated.set(true); } - return result.getValue(); + return result.value(); }); return updated.get(); } @@ -678,16 +678,18 @@ public class BaseImageService extends BaseResourceService implements ImageServic private String getImageLink(String value) { if (value.startsWith(DataConstants.TB_IMAGE_PREFIX + "/api/images")) { - return StringUtils.removeStart(value, DataConstants.TB_IMAGE_PREFIX); + return Strings.CS.removeStart(value, DataConstants.TB_IMAGE_PREFIX); } else { return null; } } - @Data(staticConstructor = "of") - private static class UpdateResult { - private final boolean updated; - private final String value; + private record UpdateResult(boolean updated, String value) { + + static UpdateResult of(boolean updated, String value) { + return new UpdateResult(updated, value); + } + } } diff --git a/dao/src/main/java/org/thingsboard/server/dao/resource/BaseResourceService.java b/dao/src/main/java/org/thingsboard/server/dao/resource/BaseResourceService.java index 7f0dd4a6bf..1eed9a6b59 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/resource/BaseResourceService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/resource/BaseResourceService.java @@ -18,6 +18,7 @@ package org.thingsboard.server.dao.resource; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.node.TextNode; import com.google.common.hash.Hashing; +import com.google.common.util.concurrent.FluentFuture; import com.google.common.util.concurrent.ListenableFuture; import jakarta.annotation.PostConstruct; import lombok.RequiredArgsConstructor; @@ -79,6 +80,7 @@ import java.util.UUID; import java.util.concurrent.atomic.AtomicBoolean; import java.util.function.UnaryOperator; +import static com.google.common.util.concurrent.MoreExecutors.directExecutor; import static org.thingsboard.server.common.data.StringUtils.isNotEmpty; import static org.thingsboard.server.dao.device.DeviceServiceImpl.INCORRECT_TENANT_ID; import static org.thingsboard.server.dao.service.Validator.validateId; @@ -107,7 +109,8 @@ public class BaseResourceService extends AbstractCachedEntityService DASHBOARD_RESOURCES_MAPPING = Map.of( @@ -275,7 +278,7 @@ public class BaseResourceService extends AbstractCachedEntityService>> findEntityAsync(TenantId tenantId, EntityId entityId) { + return FluentFuture.from(findResourceInfoByIdAsync(tenantId, new TbResourceId(entityId.getId()))) + .transform(Optional::ofNullable, directExecutor()); + } + @Override public EntityType getEntityType() { return EntityType.TB_RESOURCE; diff --git a/dao/src/main/java/org/thingsboard/server/dao/rpc/BaseRpcService.java b/dao/src/main/java/org/thingsboard/server/dao/rpc/BaseRpcService.java index 15b9717f47..f06e2e45df 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/rpc/BaseRpcService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/rpc/BaseRpcService.java @@ -15,6 +15,7 @@ */ package org.thingsboard.server.dao.rpc; +import com.google.common.util.concurrent.FluentFuture; import com.google.common.util.concurrent.ListenableFuture; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -33,6 +34,7 @@ import org.thingsboard.server.dao.service.PaginatedRemover; import java.util.Optional; +import static com.google.common.util.concurrent.MoreExecutors.directExecutor; import static org.thingsboard.server.dao.service.Validator.validateId; import static org.thingsboard.server.dao.service.Validator.validatePageLink; @@ -40,6 +42,7 @@ import static org.thingsboard.server.dao.service.Validator.validatePageLink; @Slf4j @RequiredArgsConstructor public class BaseRpcService implements RpcService { + public static final String INCORRECT_TENANT_ID = "Incorrect tenantId "; public static final String INCORRECT_RPC_ID = "Incorrect rpcId "; @@ -113,21 +116,29 @@ public class BaseRpcService implements RpcService { return Optional.ofNullable(findById(tenantId, new RpcId(entityId.getId()))); } + @Override + public FluentFuture>> findEntityAsync(TenantId tenantId, EntityId entityId) { + return FluentFuture.from(findRpcByIdAsync(tenantId, new RpcId(entityId.getId()))) + .transform(Optional::ofNullable, directExecutor()); + } + @Override public EntityType getEntityType() { return EntityType.RPC; } - private PaginatedRemover tenantRpcRemover = - new PaginatedRemover<>() { - @Override - protected PageData findEntities(TenantId tenantId, TenantId id, PageLink pageLink) { - return rpcDao.findAllRpcByTenantId(id, pageLink); - } - - @Override - protected void removeEntity(TenantId tenantId, Rpc entity) { - deleteRpc(tenantId, entity.getId()); - } - }; + private final PaginatedRemover tenantRpcRemover = new PaginatedRemover<>() { + + @Override + protected PageData findEntities(TenantId tenantId, TenantId id, PageLink pageLink) { + return rpcDao.findAllRpcByTenantId(id, pageLink); + } + + @Override + protected void removeEntity(TenantId tenantId, Rpc entity) { + deleteRpc(tenantId, entity.getId()); + } + + }; + } diff --git a/dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleChainService.java b/dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleChainService.java index 8538bd9492..8912e47c5b 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleChainService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleChainService.java @@ -18,6 +18,7 @@ package org.thingsboard.server.dao.rule; import com.datastax.oss.driver.api.core.uuid.Uuids; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.node.ObjectNode; +import com.google.common.util.concurrent.FluentFuture; import com.google.common.util.concurrent.ListenableFuture; import lombok.extern.slf4j.Slf4j; import org.apache.commons.collections4.CollectionUtils; @@ -28,6 +29,7 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.common.data.BaseData; +import org.thingsboard.server.common.data.BaseDataWithAdditionalInfo; import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.audit.ActionType; import org.thingsboard.server.common.data.edge.Edge; @@ -38,6 +40,7 @@ import org.thingsboard.server.common.data.id.HasId; import org.thingsboard.server.common.data.id.RuleChainId; import org.thingsboard.server.common.data.id.RuleNodeId; import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.id.UUIDBased; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageDataIterable; import org.thingsboard.server.common.data.page.PageLink; @@ -80,6 +83,7 @@ import java.util.UUID; import java.util.function.Function; import java.util.stream.Collectors; +import static com.google.common.util.concurrent.MoreExecutors.directExecutor; import static org.thingsboard.server.common.data.DataConstants.TENANT; import static org.thingsboard.server.dao.service.Validator.validateId; import static org.thingsboard.server.dao.service.Validator.validateIds; @@ -87,9 +91,6 @@ import static org.thingsboard.server.dao.service.Validator.validatePageLink; import static org.thingsboard.server.dao.service.Validator.validatePositiveNumber; import static org.thingsboard.server.dao.service.Validator.validateString; -/** - * Created by igor on 3/12/18. - */ @Service("RuleChainDaoService") @Slf4j public class BaseRuleChainService extends AbstractEntityService implements RuleChainService { @@ -98,6 +99,7 @@ public class BaseRuleChainService extends AbstractEntityService implements RuleC public static final String INCORRECT_TENANT_ID = "Incorrect tenantId "; public static final String TB_RULE_CHAIN_INPUT_NODE = "org.thingsboard.rule.engine.flow.TbRuleChainInputNode"; + @Autowired private RuleChainDao ruleChainDao; @@ -260,7 +262,7 @@ public class BaseRuleChainService extends AbstractEntityService implements RuleC firstRuleNodeId = nodes.get(ruleChainMetaData.getFirstNodeIndex()).getId(); } if ((ruleChain.getFirstRuleNodeId() != null && !ruleChain.getFirstRuleNodeId().equals(firstRuleNodeId)) - || (ruleChain.getFirstRuleNodeId() == null && firstRuleNodeId != null)) { + || (ruleChain.getFirstRuleNodeId() == null && firstRuleNodeId != null)) { ruleChain.setFirstRuleNodeId(firstRuleNodeId); } if (ruleChainMetaData.getConnections() != null) { @@ -876,6 +878,17 @@ public class BaseRuleChainService extends AbstractEntityService implements RuleC return Optional.ofNullable(hasId); } + @Override + public FluentFuture>> findEntityAsync(TenantId tenantId, EntityId entityId) { + ListenableFuture> future; + if (entityId.getEntityType() == EntityType.RULE_NODE) { + future = findRuleNodeByIdAsync(tenantId, new RuleNodeId(entityId.getId())); + } else { + future = findRuleChainByIdAsync(tenantId, new RuleChainId(entityId.getId())); + } + return FluentFuture.from(future).transform(Optional::ofNullable, directExecutor()); + } + @Override public long countByTenantId(TenantId tenantId) { return ruleChainDao.countByTenantId(tenantId); @@ -919,18 +932,11 @@ public class BaseRuleChainService extends AbstractEntityService implements RuleC ComponentClusteringMode nodeConfigType = ReflectionUtils.getAnnotationProperty(ruleNode.getType(), "org.thingsboard.rule.engine.api.RuleNode", "clusteringMode"); - switch (nodeConfigType) { - case ENABLED: - singletonMode = false; - break; - case SINGLETON: - singletonMode = true; - break; - case USER_PREFERENCE: - default: - singletonMode = ruleNode.isSingletonMode(); - break; - } + singletonMode = switch (nodeConfigType) { + case ENABLED -> false; + case SINGLETON -> true; + default -> ruleNode.isSingletonMode(); + }; } catch (Exception e) { log.warn("Failed to get clustering mode: {}", ExceptionUtils.getRootCauseMessage(e)); singletonMode = false; diff --git a/dao/src/main/java/org/thingsboard/server/dao/settings/AdminSettingsServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/settings/AdminSettingsServiceImpl.java index 604a37f4bb..7440481700 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/settings/AdminSettingsServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/settings/AdminSettingsServiceImpl.java @@ -17,6 +17,7 @@ package org.thingsboard.server.dao.settings; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.node.ObjectNode; +import com.google.common.util.concurrent.FluentFuture; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @@ -31,6 +32,8 @@ import org.thingsboard.server.dao.service.Validator; import java.util.Optional; +import static com.google.common.util.concurrent.MoreExecutors.directExecutor; + @Service @Slf4j public class AdminSettingsServiceImpl implements AdminSettingsService { @@ -106,6 +109,12 @@ public class AdminSettingsServiceImpl implements AdminSettingsService { return Optional.ofNullable(adminSettingsDao.findById(tenantId, entityId.getId())); } + @Override + public FluentFuture>> findEntityAsync(TenantId tenantId, EntityId entityId) { + return FluentFuture.from(adminSettingsDao.findByIdAsync(tenantId, entityId.getId())) + .transform(Optional::ofNullable, directExecutor()); + } + @Override public EntityType getEntityType() { return EntityType.ADMIN_SETTINGS; diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/user/JpaUserDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/user/JpaUserDao.java index 35d15bab51..753955089c 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/user/JpaUserDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/user/JpaUserDao.java @@ -136,6 +136,11 @@ public class JpaUserDao extends JpaAbstractDao implements User DaoUtil.toPageable(pageLink))); } + @Override + public int countTenantAdmins(UUID tenantId) { + return userRepository.countByTenantIdAndAuthority(tenantId, Authority.TENANT_ADMIN); + } + @Override public Long countByTenantId(TenantId tenantId) { return userRepository.countByTenantId(tenantId.getId()); diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/user/UserRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/user/UserRepository.java index 0a30a859c6..2254377af3 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/user/UserRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/user/UserRepository.java @@ -78,4 +78,6 @@ public interface UserRepository extends JpaRepository { "u.customerId, u.version, u.firstName, u.lastName, u.email, u.phone, u.additionalInfo) " + "FROM UserEntity u WHERE u.id > :id ORDER BY u.id") List findNextBatch(@Param("id") UUID id, Limit limit); + + int countByTenantIdAndAuthority(UUID tenantId, Authority authority); } diff --git a/dao/src/main/java/org/thingsboard/server/dao/sqlts/dictionary/JpaKeyDictionaryDao.java b/dao/src/main/java/org/thingsboard/server/dao/sqlts/dictionary/JpaKeyDictionaryDao.java index c14c069f23..46bc10010e 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sqlts/dictionary/JpaKeyDictionaryDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sqlts/dictionary/JpaKeyDictionaryDao.java @@ -17,8 +17,6 @@ package org.thingsboard.server.dao.sqlts.dictionary; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.hibernate.exception.ConstraintViolationException; -import org.springframework.dao.DataIntegrityViolationException; import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; @@ -48,43 +46,34 @@ public class JpaKeyDictionaryDao extends JpaAbstractDaoListeningExecutorService @Transactional(propagation = Propagation.NOT_SUPPORTED) @Override public Integer getOrSaveKeyId(String strKey) { - Integer keyId = keyDictionaryMap.get(strKey); - if (keyId == null) { - Optional tsKvDictionaryOptional; - tsKvDictionaryOptional = keyDictionaryRepository.findById(new KeyDictionaryCompositeKey(strKey)); - if (tsKvDictionaryOptional.isEmpty()) { - creationLock.lock(); - try { - keyId = keyDictionaryMap.get(strKey); - if (keyId != null) { - return keyId; - } - tsKvDictionaryOptional = keyDictionaryRepository.findById(new KeyDictionaryCompositeKey(strKey)); - if (tsKvDictionaryOptional.isEmpty()) { - KeyDictionaryEntry keyDictionaryEntry = new KeyDictionaryEntry(); - keyDictionaryEntry.setKey(strKey); - try { - KeyDictionaryEntry saved = keyDictionaryRepository.save(keyDictionaryEntry); - keyDictionaryMap.put(saved.getKey(), saved.getKeyId()); - keyId = saved.getKeyId(); - } catch (DataIntegrityViolationException | ConstraintViolationException e) { - tsKvDictionaryOptional = keyDictionaryRepository.findById(new KeyDictionaryCompositeKey(strKey)); - KeyDictionaryEntry dictionary = tsKvDictionaryOptional.orElseThrow(() -> new RuntimeException("Failed to get KeyDictionaryEntry entity from DB!")); - keyDictionaryMap.put(dictionary.getKey(), dictionary.getKeyId()); - keyId = dictionary.getKeyId(); - } - } else { - keyId = tsKvDictionaryOptional.get().getKeyId(); - } - } finally { - creationLock.unlock(); - } - } else { - keyId = tsKvDictionaryOptional.get().getKeyId(); - keyDictionaryMap.put(strKey, keyId); + Integer cached = keyDictionaryMap.get(strKey); + if (cached != null) { + return cached; + } + var compositeKey = new KeyDictionaryCompositeKey(strKey); + Optional existingId = keyDictionaryRepository.findById(compositeKey).map(KeyDictionaryEntry::getKeyId); + if (existingId.isPresent()) { + return cacheAndReturn(strKey, existingId.get()); + } + creationLock.lock(); + try { + Integer fromCache = keyDictionaryMap.get(strKey); + if (fromCache != null) { + return fromCache; } + Integer keyId = keyDictionaryRepository.upsertAndGetKeyId(strKey); + if (keyId != null) { + return cacheAndReturn(strKey, keyId); + } + log.warn("upsertAndGetKeyId returned: [{}] for key: [{}], falling back to findById", keyId, strKey); + keyId = keyDictionaryRepository.findById(compositeKey) + .map(KeyDictionaryEntry::getKeyId) + .orElseThrow(() -> new IllegalStateException( + "Failed to resolve keyId for string key: " + strKey + " after fallback.")); + return cacheAndReturn(strKey, keyId); + } finally { + creationLock.unlock(); } - return keyId; } @Override @@ -98,4 +87,9 @@ public class JpaKeyDictionaryDao extends JpaAbstractDaoListeningExecutorService return DaoUtil.pageToPageData(keyDictionaryRepository.findAll(DaoUtil.toPageable(pageLink))); } + private Integer cacheAndReturn(String key, Integer keyId) { + keyDictionaryMap.put(key, keyId); + return keyId; + } + } diff --git a/dao/src/main/java/org/thingsboard/server/dao/sqlts/dictionary/KeyDictionaryRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sqlts/dictionary/KeyDictionaryRepository.java index d264cd9966..e836cedb19 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sqlts/dictionary/KeyDictionaryRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sqlts/dictionary/KeyDictionaryRepository.java @@ -19,6 +19,7 @@ import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; import org.thingsboard.server.dao.model.sqlts.dictionary.KeyDictionaryCompositeKey; import org.thingsboard.server.dao.model.sqlts.dictionary.KeyDictionaryEntry; @@ -31,4 +32,7 @@ public interface KeyDictionaryRepository extends JpaRepository findAll(Pageable pageable); -} \ No newline at end of file + @Query(value = "INSERT INTO key_dictionary (key) VALUES (:key) ON CONFLICT (key) DO UPDATE SET key = EXCLUDED.key RETURNING key_id", nativeQuery = true) + Integer upsertAndGetKeyId(@Param("key") String key); + +} diff --git a/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantProfileServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantProfileServiceImpl.java index e165d6cfe6..b9172306bb 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantProfileServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantProfileServiceImpl.java @@ -15,6 +15,7 @@ */ package org.thingsboard.server.dao.tenant; +import com.google.common.util.concurrent.FluentFuture; import lombok.extern.slf4j.Slf4j; import org.hibernate.exception.ConstraintViolationException; import org.springframework.beans.factory.annotation.Autowired; @@ -44,6 +45,7 @@ import java.util.List; import java.util.Optional; import java.util.UUID; +import static com.google.common.util.concurrent.MoreExecutors.directExecutor; import static org.thingsboard.common.util.DebugModeUtil.DEBUG_MODE_DEFAULT_DURATION_MINUTES; import static org.thingsboard.server.dao.service.Validator.validateId; @@ -230,23 +232,29 @@ public class TenantProfileServiceImpl extends AbstractCachedEntityService>> findEntityAsync(TenantId tenantId, EntityId entityId) { + return FluentFuture.from(tenantProfileDao.findByIdAsync(tenantId, entityId.getId())) + .transform(Optional::ofNullable, directExecutor()); + } + @Override public EntityType getEntityType() { return EntityType.TENANT_PROFILE; } - private final PaginatedRemover tenantProfilesRemover = - new PaginatedRemover<>() { + private final PaginatedRemover tenantProfilesRemover = new PaginatedRemover<>() { - @Override - protected PageData findEntities(TenantId tenantId, String id, PageLink pageLink) { - return tenantProfileDao.findTenantProfiles(tenantId, pageLink); - } + @Override + protected PageData findEntities(TenantId tenantId, String id, PageLink pageLink) { + return tenantProfileDao.findTenantProfiles(tenantId, pageLink); + } + + @Override + protected void removeEntity(TenantId tenantId, TenantProfile entity) { + removeTenantProfile(tenantId, entity, entity.isDefault()); + } - @Override - protected void removeEntity(TenantId tenantId, TenantProfile entity) { - removeTenantProfile(tenantId, entity, entity.isDefault()); - } - }; + }; } diff --git a/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantServiceImpl.java index 0df7c36527..bd5a621562 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantServiceImpl.java @@ -15,6 +15,7 @@ */ package org.thingsboard.server.dao.tenant; +import com.google.common.util.concurrent.FluentFuture; import com.google.common.util.concurrent.ListenableFuture; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; @@ -51,6 +52,7 @@ import java.util.List; import java.util.Optional; import java.util.function.Consumer; +import static com.google.common.util.concurrent.MoreExecutors.directExecutor; import static org.thingsboard.server.dao.service.Validator.validateId; @Service("TenantDaoService") @@ -85,8 +87,8 @@ public class TenantServiceImpl extends AbstractCachedEntityService existsTenantCache; - @TransactionalEventListener(classes = TenantEvictEvent.class) @Override + @TransactionalEventListener public void handleEvictEvent(TenantEvictEvent event) { TenantId tenantId = event.getTenantId(); cache.evict(tenantId); @@ -245,6 +247,12 @@ public class TenantServiceImpl extends AbstractCachedEntityService>> findEntityAsync(TenantId tenantId, EntityId entityId) { + return FluentFuture.from(findTenantByIdAsync(tenantId, TenantId.fromUUID(entityId.getId()))) + .transform(Optional::ofNullable, directExecutor()); + } + @Override public EntityType getEntityType() { return EntityType.TENANT; diff --git a/dao/src/main/java/org/thingsboard/server/dao/usagerecord/ApiUsageStateServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/usagerecord/ApiUsageStateServiceImpl.java index 1282493650..49ee56e7be 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/usagerecord/ApiUsageStateServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/usagerecord/ApiUsageStateServiceImpl.java @@ -15,6 +15,7 @@ */ package org.thingsboard.server.dao.usagerecord; +import com.google.common.util.concurrent.FluentFuture; import lombok.extern.slf4j.Slf4j; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; @@ -48,11 +49,13 @@ import java.util.List; import java.util.Objects; import java.util.Optional; +import static com.google.common.util.concurrent.MoreExecutors.directExecutor; import static org.thingsboard.server.dao.service.Validator.validateId; @Service("ApiUsageStateDaoService") @Slf4j public class ApiUsageStateServiceImpl extends AbstractEntityService implements ApiUsageStateService { + public static final String INCORRECT_TENANT_ID = "Incorrect tenantId "; private final ApiUsageStateDao apiUsageStateDao; @@ -161,7 +164,7 @@ public class ApiUsageStateServiceImpl extends AbstractEntityService implements A public ApiUsageState update(ApiUsageState apiUsageState) { log.trace("Executing save [{}]", apiUsageState.getTenantId()); validateId(apiUsageState.getTenantId(), id -> INCORRECT_TENANT_ID + id); - validateId(apiUsageState.getId(), "Can't save new usage state. Only update is allowed!"); + validateId(apiUsageState.getId(), __ -> "Can't save new usage state. Only update is allowed!"); apiUsageState.setVersion(null); ApiUsageState savedState = apiUsageStateDao.save(apiUsageState.getTenantId(), apiUsageState); eventPublisher.publishEvent(SaveEntityEvent.builder().tenantId(savedState.getTenantId()).entityId(savedState.getId()) @@ -195,6 +198,12 @@ public class ApiUsageStateServiceImpl extends AbstractEntityService implements A return Optional.ofNullable(findApiUsageStateById(tenantId, new ApiUsageStateId(entityId.getId()))); } + @Override + public FluentFuture>> findEntityAsync(TenantId tenantId, EntityId entityId) { + return FluentFuture.from(apiUsageStateDao.findByIdAsync(tenantId, entityId.getId())) + .transform(Optional::ofNullable, directExecutor()); + } + @Transactional @Override public void deleteByTenantId(TenantId tenantId) { diff --git a/dao/src/main/java/org/thingsboard/server/dao/user/UserDao.java b/dao/src/main/java/org/thingsboard/server/dao/user/UserDao.java index b60b263ac8..127aa6141a 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/user/UserDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/user/UserDao.java @@ -101,4 +101,5 @@ public interface UserDao extends Dao, TenantEntityDao { PageData findByAuthorityAndTenantProfilesIds(Authority authority, List tenantProfilesIds, PageLink pageLink); + int countTenantAdmins(UUID tenantId); } diff --git a/dao/src/main/java/org/thingsboard/server/dao/user/UserServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/user/UserServiceImpl.java index 5c94ba1891..595a2a6611 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/user/UserServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/user/UserServiceImpl.java @@ -18,6 +18,7 @@ package org.thingsboard.server.dao.user; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.node.ObjectNode; +import com.google.common.util.concurrent.FluentFuture; import com.google.common.util.concurrent.ListenableFuture; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -72,6 +73,7 @@ import java.util.Objects; import java.util.Optional; import java.util.concurrent.TimeUnit; +import static com.google.common.util.concurrent.MoreExecutors.directExecutor; import static org.thingsboard.server.common.data.StringUtils.generateSafeToken; import static org.thingsboard.server.dao.service.Validator.validateId; import static org.thingsboard.server.dao.service.Validator.validatePageLink; @@ -103,8 +105,8 @@ public class UserServiceImpl extends AbstractCachedEntityService keys = new ArrayList<>(2); keys.add(new UserCacheKey(event.tenantId(), event.newEmail())); @@ -179,7 +181,7 @@ public class UserServiceImpl extends AbstractCachedEntityService findMobileSessionInfo(TenantId tenantId, UserId userId) { return Optional.ofNullable(userSettingsService.findUserSettings(tenantId, userId, UserSettingsType.MOBILE)) .map(UserSettings::getSettings).map(settings -> JacksonUtil.treeToValue(settings, UserMobileSessionInfo.class)); @@ -563,6 +570,12 @@ public class UserServiceImpl extends AbstractCachedEntityService>> findEntityAsync(TenantId tenantId, EntityId entityId) { + return FluentFuture.from(findUserByIdAsync(tenantId, new UserId(entityId.getId()))) + .transform(Optional::ofNullable, directExecutor()); + } + @Override public long countByTenantId(TenantId tenantId) { return userDao.countByTenantId(tenantId); diff --git a/dao/src/main/java/org/thingsboard/server/dao/widget/WidgetTypeServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/widget/WidgetTypeServiceImpl.java index 7e74c2a18b..db8cd875e3 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/widget/WidgetTypeServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/widget/WidgetTypeServiceImpl.java @@ -15,6 +15,7 @@ */ package org.thingsboard.server.dao.widget; +import com.google.common.util.concurrent.FluentFuture; import lombok.extern.slf4j.Slf4j; import org.apache.commons.collections4.CollectionUtils; import org.springframework.beans.factory.annotation.Autowired; @@ -47,6 +48,7 @@ import java.util.ArrayList; import java.util.List; import java.util.Optional; +import static com.google.common.util.concurrent.MoreExecutors.directExecutor; import static org.thingsboard.server.dao.service.Validator.validateIds; @Service("WidgetTypeDaoService") @@ -54,8 +56,6 @@ import static org.thingsboard.server.dao.service.Validator.validateIds; public class WidgetTypeServiceImpl implements WidgetTypeService { public static final String INCORRECT_TENANT_ID = "Incorrect tenantId "; - public static final String INCORRECT_RESOURCE_ID = "Incorrect resourceId "; - public static final String INCORRECT_BUNDLE_ALIAS = "Incorrect bundleAlias "; public static final String INCORRECT_WIDGETS_BUNDLE_ID = "Incorrect widgetsBundleId "; @Autowired @@ -281,6 +281,12 @@ public class WidgetTypeServiceImpl implements WidgetTypeService { return Optional.ofNullable(findWidgetTypeById(tenantId, new WidgetTypeId(entityId.getId()))); } + @Override + public FluentFuture>> findEntityAsync(TenantId tenantId, EntityId entityId) { + return FluentFuture.from(widgetTypeDao.findByIdAsync(tenantId, entityId.getId())) + .transform(Optional::ofNullable, directExecutor()); + } + @Override public EntityType getEntityType() { return EntityType.WIDGET_TYPE; @@ -303,6 +309,7 @@ public class WidgetTypeServiceImpl implements WidgetTypeService { protected void removeEntity(TenantId tenantId, WidgetTypeInfo entity) { deleteWidgetType(tenantId, new WidgetTypeId(entity.getUuidId())); } + }; private final PaginatedRemover bundleWidgetTypesRemover = new PaginatedRemover<>() { @@ -316,6 +323,7 @@ public class WidgetTypeServiceImpl implements WidgetTypeService { protected void removeEntity(TenantId tenantId, WidgetTypeInfo widgetTypeInfo) { deleteWidgetType(tenantId, widgetTypeInfo.getId()); } + }; } diff --git a/dao/src/main/java/org/thingsboard/server/dao/widget/WidgetsBundleServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/widget/WidgetsBundleServiceImpl.java index f057ce22ca..5b5930fb0a 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/widget/WidgetsBundleServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/widget/WidgetsBundleServiceImpl.java @@ -16,6 +16,7 @@ package org.thingsboard.server.dao.widget; import com.fasterxml.jackson.databind.JsonNode; +import com.google.common.util.concurrent.FluentFuture; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationEventPublisher; @@ -33,12 +34,10 @@ import org.thingsboard.server.common.data.widget.WidgetType; import org.thingsboard.server.common.data.widget.WidgetTypeDetails; import org.thingsboard.server.common.data.widget.WidgetsBundle; import org.thingsboard.server.common.data.widget.WidgetsBundleFilter; -import org.thingsboard.server.dao.entity.AbstractCachedEntityService; import org.thingsboard.server.dao.eventsourcing.DeleteEntityEvent; import org.thingsboard.server.dao.eventsourcing.SaveEntityEvent; import org.thingsboard.server.dao.exception.IncorrectParameterException; import org.thingsboard.server.dao.resource.ImageService; -import org.thingsboard.server.dao.resource.ResourceService; import org.thingsboard.server.dao.service.DataValidator; import org.thingsboard.server.dao.service.PaginatedRemover; import org.thingsboard.server.dao.service.Validator; @@ -48,13 +47,15 @@ import java.util.List; import java.util.Optional; import java.util.stream.Stream; +import static com.google.common.util.concurrent.MoreExecutors.directExecutor; +import static org.thingsboard.server.dao.entity.AbstractEntityService.checkConstraintViolation; + @Service("WidgetsBundleDaoService") @Slf4j public class WidgetsBundleServiceImpl implements WidgetsBundleService { private static final int DEFAULT_WIDGETS_BUNDLE_LIMIT = 300; public static final String INCORRECT_TENANT_ID = "Incorrect tenantId "; - public static final String INCORRECT_PAGE_LINK = "Incorrect page link "; @Autowired private WidgetsBundleDao widgetsBundleDao; @@ -71,9 +72,6 @@ public class WidgetsBundleServiceImpl implements WidgetsBundleService { @Autowired private ImageService imageService; - @Autowired - private ResourceService resourceService; - @Override public WidgetsBundle findWidgetsBundleById(TenantId tenantId, WidgetsBundleId widgetsBundleId) { log.trace("Executing findWidgetsBundleById [{}]", widgetsBundleId); @@ -92,9 +90,9 @@ public class WidgetsBundleServiceImpl implements WidgetsBundleService { .entityId(result.getId()).created(widgetsBundle.getId() == null).build()); return result; } catch (Exception e) { - AbstractCachedEntityService.checkConstraintViolation(e, - "uq_widgets_bundle_alias", "Widgets Bundle with such alias already exists!"); - AbstractCachedEntityService.checkConstraintViolation(e, "widgets_bundle_external_id_unq_key", "Widgets Bundle with such external id already exists!"); + checkConstraintViolation(e, + "uq_widgets_bundle_alias", "Widgets Bundle with such alias already exists!", + "widgets_bundle_external_id_unq_key", "Widgets Bundle with such external id already exists!"); throw e; } } @@ -248,9 +246,7 @@ public class WidgetsBundleServiceImpl implements WidgetsBundleService { } if (widgetsBundleDescriptor.has("widgetTypeFqns")) { JsonNode widgetFqnsArrayJson = widgetsBundleDescriptor.get("widgetTypeFqns"); - widgetFqnsArrayJson.forEach(fqnJson -> { - widgetTypeFqns.add(fqnJson.asText()); - }); + widgetFqnsArrayJson.forEach(fqnJson -> widgetTypeFqns.add(fqnJson.asText())); } widgetTypeService.updateWidgetsBundleWidgetFqns(TenantId.SYS_TENANT_ID, widgetsBundle.getId(), widgetTypeFqns); }); @@ -274,23 +270,29 @@ public class WidgetsBundleServiceImpl implements WidgetsBundleService { return Optional.ofNullable(findWidgetsBundleById(tenantId, new WidgetsBundleId(entityId.getId()))); } + @Override + public FluentFuture>> findEntityAsync(TenantId tenantId, EntityId entityId) { + return FluentFuture.from(widgetsBundleDao.findByIdAsync(tenantId, entityId.getId())) + .transform(Optional::ofNullable, directExecutor()); + } + @Override public EntityType getEntityType() { return EntityType.WIDGETS_BUNDLE; } - private PaginatedRemover tenantWidgetsBundleRemover = - new PaginatedRemover() { + private final PaginatedRemover tenantWidgetsBundleRemover = new PaginatedRemover<>() { - @Override - protected PageData findEntities(TenantId tenantId, TenantId id, PageLink pageLink) { - return widgetsBundleDao.findTenantWidgetsBundlesByTenantId(id.getId(), pageLink); - } + @Override + protected PageData findEntities(TenantId tenantId, TenantId id, PageLink pageLink) { + return widgetsBundleDao.findTenantWidgetsBundlesByTenantId(id.getId(), pageLink); + } + + @Override + protected void removeEntity(TenantId tenantId, WidgetsBundle entity) { + deleteWidgetsBundle(tenantId, new WidgetsBundleId(entity.getUuidId())); + } - @Override - protected void removeEntity(TenantId tenantId, WidgetsBundle entity) { - deleteWidgetsBundle(tenantId, new WidgetsBundleId(entity.getUuidId())); - } - }; + }; } diff --git a/dao/src/main/resources/sql/schema-views-and-functions.sql b/dao/src/main/resources/sql/schema-functions.sql similarity index 73% rename from dao/src/main/resources/sql/schema-views-and-functions.sql rename to dao/src/main/resources/sql/schema-functions.sql index a6a7ae43cb..e763210a3d 100644 --- a/dao/src/main/resources/sql/schema-views-and-functions.sql +++ b/dao/src/main/resources/sql/schema-functions.sql @@ -14,84 +14,6 @@ -- limitations under the License. -- -DROP VIEW IF EXISTS device_info_active_attribute_view CASCADE; -CREATE OR REPLACE VIEW device_info_active_attribute_view AS -SELECT d.* - , c.title as customer_title - , COALESCE((c.additional_info::json->>'isPublic')::bool, FALSE) as customer_is_public - , d.type as device_profile_name - , COALESCE(da.bool_v, FALSE) as active -FROM device d - LEFT JOIN customer c ON c.id = d.customer_id - LEFT JOIN attribute_kv da ON da.entity_id = d.id AND da.attribute_type = 2 AND da.attribute_key = (select key_id from key_dictionary where key = 'active'); - -DROP VIEW IF EXISTS device_info_active_ts_view CASCADE; -CREATE OR REPLACE VIEW device_info_active_ts_view AS -SELECT d.* - , c.title as customer_title - , COALESCE((c.additional_info::json->>'isPublic')::bool, FALSE) as customer_is_public - , d.type as device_profile_name - , COALESCE(dt.bool_v, FALSE) as active -FROM device d - LEFT JOIN customer c ON c.id = d.customer_id - LEFT JOIN ts_kv_latest dt ON dt.entity_id = d.id and dt.key = (select key_id from key_dictionary where key = 'active'); - -DROP VIEW IF EXISTS device_info_view CASCADE; -CREATE OR REPLACE VIEW device_info_view AS SELECT * FROM device_info_active_attribute_view; - -DROP VIEW IF EXISTS alarm_info CASCADE; -CREATE VIEW alarm_info AS -SELECT a.*, -(CASE WHEN a.acknowledged AND a.cleared THEN 'CLEARED_ACK' - WHEN NOT a.acknowledged AND a.cleared THEN 'CLEARED_UNACK' - WHEN a.acknowledged AND NOT a.cleared THEN 'ACTIVE_ACK' - WHEN NOT a.acknowledged AND NOT a.cleared THEN 'ACTIVE_UNACK' END) as status, -COALESCE(CASE WHEN a.originator_type = 0 THEN (select title from tenant where id = a.originator_id) - WHEN a.originator_type = 1 THEN (select title from customer where id = a.originator_id) - WHEN a.originator_type = 2 THEN (select email from tb_user where id = a.originator_id) - WHEN a.originator_type = 3 THEN (select title from dashboard where id = a.originator_id) - WHEN a.originator_type = 4 THEN (select name from asset where id = a.originator_id) - WHEN a.originator_type = 5 THEN (select name from device where id = a.originator_id) - WHEN a.originator_type = 9 THEN (select name from entity_view where id = a.originator_id) - WHEN a.originator_type = 13 THEN (select name from device_profile where id = a.originator_id) - WHEN a.originator_type = 14 THEN (select name from asset_profile where id = a.originator_id) - WHEN a.originator_type = 18 THEN (select name from edge where id = a.originator_id) END - , 'Deleted') originator_name, -COALESCE(CASE WHEN a.originator_type = 0 THEN (select title from tenant where id = a.originator_id) - WHEN a.originator_type = 1 THEN (select COALESCE(NULLIF(title, ''), email) from customer where id = a.originator_id) - WHEN a.originator_type = 2 THEN (select email from tb_user where id = a.originator_id) - WHEN a.originator_type = 3 THEN (select title from dashboard where id = a.originator_id) - WHEN a.originator_type = 4 THEN (select COALESCE(NULLIF(label, ''), name) from asset where id = a.originator_id) - WHEN a.originator_type = 5 THEN (select COALESCE(NULLIF(label, ''), name) from device where id = a.originator_id) - WHEN a.originator_type = 9 THEN (select name from entity_view where id = a.originator_id) - WHEN a.originator_type = 13 THEN (select name from device_profile where id = a.originator_id) - WHEN a.originator_type = 14 THEN (select name from asset_profile where id = a.originator_id) - WHEN a.originator_type = 18 THEN (select COALESCE(NULLIF(label, ''), name) from edge where id = a.originator_id) END - , 'Deleted') as originator_label, -u.first_name as assignee_first_name, u.last_name as assignee_last_name, u.email as assignee_email -FROM alarm a -LEFT JOIN tb_user u ON u.id = a.assignee_id; - -DROP VIEW IF EXISTS edge_active_attribute_view CASCADE; -CREATE OR REPLACE VIEW edge_active_attribute_view AS -SELECT ee.id - , ee.created_time - , ee.additional_info - , ee.customer_id - , ee.root_rule_chain_id - , ee.type - , ee.name - , ee.label - , ee.routing_key - , ee.secret - , ee.tenant_id - , ee.version -FROM edge ee - JOIN attribute_kv ON ee.id = attribute_kv.entity_id - JOIN key_dictionary ON attribute_kv.attribute_key = key_dictionary.key_id -WHERE attribute_kv.bool_v = true AND key_dictionary.key = 'active' -ORDER BY ee.id; - CREATE OR REPLACE FUNCTION create_or_update_active_alarm( t_id uuid, c_id uuid, a_id uuid, a_created_ts bigint, a_o_id uuid, a_o_type integer, a_type varchar, @@ -306,19 +228,6 @@ BEGIN END $$; -DROP VIEW IF EXISTS widget_type_info_view CASCADE; -CREATE OR REPLACE VIEW widget_type_info_view AS -SELECT t.*, - COALESCE((t.descriptor::json->>'type')::text, '') as widget_type, - array_to_json(ARRAY( - SELECT json_build_object('id', wb.widgets_bundle_id, 'name', b.title) - FROM widgets_bundle_widget wb - JOIN widgets_bundle b ON wb.widgets_bundle_id = b.id - WHERE wb.widget_type_id = t.id - ORDER BY b.title - )) AS bundles -FROM widget_type t; - CREATE OR REPLACE PROCEDURE cleanup_timeseries_by_ttl(IN null_uuid uuid, IN system_ttl bigint, INOUT deleted bigint) LANGUAGE plpgsql AS @@ -389,4 +298,4 @@ BEGIN FETCH tenant_cursor INTO tenant_id_record; END LOOP; END -$$; \ No newline at end of file +$$; diff --git a/dao/src/main/resources/sql/schema-views.sql b/dao/src/main/resources/sql/schema-views.sql new file mode 100644 index 0000000000..c8f7ea6483 --- /dev/null +++ b/dao/src/main/resources/sql/schema-views.sql @@ -0,0 +1,106 @@ +-- +-- Copyright © 2016-2025 The Thingsboard Authors +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- + +DROP VIEW IF EXISTS device_info_active_attribute_view CASCADE; +CREATE OR REPLACE VIEW device_info_active_attribute_view AS +SELECT d.* + , c.title as customer_title + , COALESCE((c.additional_info::json->>'isPublic')::bool, FALSE) as customer_is_public + , d.type as device_profile_name + , COALESCE(da.bool_v, FALSE) as active +FROM device d + LEFT JOIN customer c ON c.id = d.customer_id + LEFT JOIN attribute_kv da ON da.entity_id = d.id AND da.attribute_type = 2 AND da.attribute_key = (select key_id from key_dictionary where key = 'active'); + +DROP VIEW IF EXISTS device_info_active_ts_view CASCADE; +CREATE OR REPLACE VIEW device_info_active_ts_view AS +SELECT d.* + , c.title as customer_title + , COALESCE((c.additional_info::json->>'isPublic')::bool, FALSE) as customer_is_public + , d.type as device_profile_name + , COALESCE(dt.bool_v, FALSE) as active +FROM device d + LEFT JOIN customer c ON c.id = d.customer_id + LEFT JOIN ts_kv_latest dt ON dt.entity_id = d.id and dt.key = (select key_id from key_dictionary where key = 'active'); + +DROP VIEW IF EXISTS device_info_view CASCADE; +CREATE OR REPLACE VIEW device_info_view AS SELECT * FROM device_info_active_attribute_view; + +DROP VIEW IF EXISTS alarm_info CASCADE; +CREATE VIEW alarm_info AS +SELECT a.*, +(CASE WHEN a.acknowledged AND a.cleared THEN 'CLEARED_ACK' + WHEN NOT a.acknowledged AND a.cleared THEN 'CLEARED_UNACK' + WHEN a.acknowledged AND NOT a.cleared THEN 'ACTIVE_ACK' + WHEN NOT a.acknowledged AND NOT a.cleared THEN 'ACTIVE_UNACK' END) as status, +COALESCE(CASE WHEN a.originator_type = 0 THEN (select title from tenant where id = a.originator_id) + WHEN a.originator_type = 1 THEN (select title from customer where id = a.originator_id) + WHEN a.originator_type = 2 THEN (select email from tb_user where id = a.originator_id) + WHEN a.originator_type = 3 THEN (select title from dashboard where id = a.originator_id) + WHEN a.originator_type = 4 THEN (select name from asset where id = a.originator_id) + WHEN a.originator_type = 5 THEN (select name from device where id = a.originator_id) + WHEN a.originator_type = 9 THEN (select name from entity_view where id = a.originator_id) + WHEN a.originator_type = 13 THEN (select name from device_profile where id = a.originator_id) + WHEN a.originator_type = 14 THEN (select name from asset_profile where id = a.originator_id) + WHEN a.originator_type = 18 THEN (select name from edge where id = a.originator_id) END + , 'Deleted') originator_name, +COALESCE(CASE WHEN a.originator_type = 0 THEN (select title from tenant where id = a.originator_id) + WHEN a.originator_type = 1 THEN (select COALESCE(NULLIF(title, ''), email) from customer where id = a.originator_id) + WHEN a.originator_type = 2 THEN (select email from tb_user where id = a.originator_id) + WHEN a.originator_type = 3 THEN (select title from dashboard where id = a.originator_id) + WHEN a.originator_type = 4 THEN (select COALESCE(NULLIF(label, ''), name) from asset where id = a.originator_id) + WHEN a.originator_type = 5 THEN (select COALESCE(NULLIF(label, ''), name) from device where id = a.originator_id) + WHEN a.originator_type = 9 THEN (select name from entity_view where id = a.originator_id) + WHEN a.originator_type = 13 THEN (select name from device_profile where id = a.originator_id) + WHEN a.originator_type = 14 THEN (select name from asset_profile where id = a.originator_id) + WHEN a.originator_type = 18 THEN (select COALESCE(NULLIF(label, ''), name) from edge where id = a.originator_id) END + , 'Deleted') as originator_label, +u.first_name as assignee_first_name, u.last_name as assignee_last_name, u.email as assignee_email +FROM alarm a +LEFT JOIN tb_user u ON u.id = a.assignee_id; + +DROP VIEW IF EXISTS edge_active_attribute_view CASCADE; +CREATE OR REPLACE VIEW edge_active_attribute_view AS +SELECT ee.id + , ee.created_time + , ee.additional_info + , ee.customer_id + , ee.root_rule_chain_id + , ee.type + , ee.name + , ee.label + , ee.routing_key + , ee.secret + , ee.tenant_id + , ee.version +FROM edge ee + JOIN attribute_kv ON ee.id = attribute_kv.entity_id + JOIN key_dictionary ON attribute_kv.attribute_key = key_dictionary.key_id +WHERE attribute_kv.bool_v = true AND key_dictionary.key = 'active' +ORDER BY ee.id; + +DROP VIEW IF EXISTS widget_type_info_view CASCADE; +CREATE OR REPLACE VIEW widget_type_info_view AS +SELECT t.*, + COALESCE((t.descriptor::json->>'type')::text, '') as widget_type, + array_to_json(ARRAY( + SELECT json_build_object('id', wb.widgets_bundle_id, 'name', b.title) + FROM widgets_bundle_widget wb + JOIN widgets_bundle b ON wb.widgets_bundle_id = b.id + WHERE wb.widget_type_id = t.id + ORDER BY b.title + )) AS bundles +FROM widget_type t; diff --git a/dao/src/test/java/org/thingsboard/server/dao/PostgreSqlInitializer.java b/dao/src/test/java/org/thingsboard/server/dao/PostgreSqlInitializer.java index b2bb965380..49956bd6d4 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/PostgreSqlInitializer.java +++ b/dao/src/test/java/org/thingsboard/server/dao/PostgreSqlInitializer.java @@ -33,7 +33,8 @@ public class PostgreSqlInitializer { "sql/schema-entities.sql", "sql/schema-entities-idx.sql", "sql/schema-entities-idx-psql-addon.sql", - "sql/schema-views-and-functions.sql", + "sql/schema-views.sql", + "sql/schema-functions.sql", "sql/system-data.sql", "sql/system-test-psql.sql"); private static final String dropAllTablesSqlFile = "sql/psql/drop-all-tables.sql"; diff --git a/dao/src/test/java/org/thingsboard/server/dao/TimescaleSqlInitializer.java b/dao/src/test/java/org/thingsboard/server/dao/TimescaleSqlInitializer.java index c9d13b6926..511afd1eca 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/TimescaleSqlInitializer.java +++ b/dao/src/test/java/org/thingsboard/server/dao/TimescaleSqlInitializer.java @@ -33,7 +33,8 @@ public class TimescaleSqlInitializer { "sql/schema-entities.sql", "sql/schema-entities-idx.sql", "sql/schema-entities-idx-psql-addon.sql", - "sql/schema-views-and-functions.sql", + "sql/schema-views.sql", + "sql/schema-functions.sql", "sql/system-data.sql", "sql/system-test-psql.sql"); private static final String dropAllTablesSqlFile = "sql/psql/drop-all-tables.sql"; @@ -63,4 +64,5 @@ public class TimescaleSqlInitializer { throw new RuntimeException("Unable to clean up the Timescale database. Reason: " + e.getMessage(), e); } } + } diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/DeviceCredentialsServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/DeviceCredentialsServiceTest.java index 636b1a2ba5..d5c969b6f3 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/DeviceCredentialsServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/DeviceCredentialsServiceTest.java @@ -19,7 +19,10 @@ import com.datastax.oss.driver.api.core.uuid.Uuids; import org.junit.Assert; import org.junit.Test; import org.junit.jupiter.api.Assertions; +import org.mockito.Mockito; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationEventPublisher; +import org.springframework.test.context.bean.override.mockito.MockitoBean; import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.id.DeviceCredentialsId; import org.thingsboard.server.common.data.id.DeviceId; @@ -27,6 +30,7 @@ import org.thingsboard.server.common.data.security.DeviceCredentials; import org.thingsboard.server.common.data.security.DeviceCredentialsType; import org.thingsboard.server.dao.device.DeviceCredentialsService; import org.thingsboard.server.dao.device.DeviceService; +import org.thingsboard.server.dao.eventsourcing.ActionEntityEvent; import org.thingsboard.server.dao.exception.DataValidationException; @DaoSqlTest @@ -36,6 +40,8 @@ public class DeviceCredentialsServiceTest extends AbstractServiceTest { DeviceCredentialsService deviceCredentialsService; @Autowired DeviceService deviceService; + @MockitoBean + ApplicationEventPublisher eventPublisher; @Test public void testCreateDeviceCredentials() { @@ -185,5 +191,39 @@ public class DeviceCredentialsServiceTest extends AbstractServiceTest { Assert.assertEquals(deviceCredentials, foundDeviceCredentials); deviceService.deleteDevice(tenantId, savedDevice.getId()); } -} + @Test + public void testUpdateDeviceCredentialsWithSameValuesDoesNotPublishEvent() { + Device device = new Device(); + device.setTenantId(tenantId); + device.setName("My device"); + device.setType("default"); + Device savedDevice = deviceService.saveDevice(device); + + try { + DeviceCredentials deviceCredentials = deviceCredentialsService.findDeviceCredentialsByDeviceId(tenantId, savedDevice.getId()); + Assert.assertNotNull(deviceCredentials); + + DeviceCredentials updatedCredentials = new DeviceCredentials(deviceCredentials.getId()); + updatedCredentials.setDeviceId(deviceCredentials.getDeviceId()); + updatedCredentials.setCredentialsType(deviceCredentials.getCredentialsType()); + updatedCredentials.setCredentialsId(deviceCredentials.getCredentialsId()); + updatedCredentials.setCredentialsValue(deviceCredentials.getCredentialsValue()); + + Mockito.reset(eventPublisher); + + DeviceCredentials result = deviceCredentialsService.updateDeviceCredentials(tenantId, updatedCredentials); + + Assert.assertEquals(deviceCredentials.getCredentialsId(), result.getCredentialsId()); + Assert.assertEquals(deviceCredentials.getCredentialsType(), result.getCredentialsType()); + Assert.assertEquals(deviceCredentials.getCredentialsValue(), result.getCredentialsValue()); + Assert.assertEquals(deviceCredentials.getDeviceId(), result.getDeviceId()); + + Mockito.verify(eventPublisher, Mockito.never()).publishEvent(Mockito.any(ActionEntityEvent.class)); + + } finally { + deviceService.deleteDevice(tenantId, savedDevice.getId()); + } + } + +} diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/OtaPackageServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/OtaPackageServiceTest.java index 39fb69ffce..70f2ff119d 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/OtaPackageServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/OtaPackageServiceTest.java @@ -53,6 +53,7 @@ import static org.thingsboard.server.common.data.ota.OtaPackageType.FIRMWARE; public class OtaPackageServiceTest extends AbstractServiceTest { public static final String TITLE = "My firmware"; + public static final String TARGET_FW_VERSION = "fw.v.1.5.0-update"; private static final String FILE_NAME = "filename.txt"; private static final String VERSION = "v1.0"; private static final String CONTENT_TYPE = "text/plain"; diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/install/sql/EntitiesSchemaSqlTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/install/sql/EntitiesSchemaSqlTest.java index 9f10ecfb7b..b28b410a12 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/install/sql/EntitiesSchemaSqlTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/install/sql/EntitiesSchemaSqlTest.java @@ -35,8 +35,10 @@ public class EntitiesSchemaSqlTest extends AbstractServiceTest { @Value("${classpath:sql/schema-entities.sql}") private Path installEntitiesPath; - @Value("${classpath:sql/schema-views-and-functions.sql}") + @Value("${classpath:sql/schema-views.sql}") private Path installViewsPath; + @Value("${classpath:sql/schema-functions.sql}") + private Path installFunctionsPath; @Autowired private JdbcTemplate jdbcTemplate; @@ -45,10 +47,12 @@ public class EntitiesSchemaSqlTest extends AbstractServiceTest { public void testRepeatedInstall() throws IOException { String entitiesScript = Files.readString(installEntitiesPath); String viewsScript = Files.readString(installViewsPath); + String functionsScript = Files.readString(installFunctionsPath); try { for (int i = 1; i <= 2; i++) { jdbcTemplate.execute(entitiesScript); jdbcTemplate.execute(viewsScript); + jdbcTemplate.execute(functionsScript); } } catch (Exception e) { Assertions.fail("Failed to execute reinstall", e); diff --git a/dao/src/test/java/org/thingsboard/server/dao/sqlts/dictionary/KeyDictionaryDaoTest.java b/dao/src/test/java/org/thingsboard/server/dao/sqlts/dictionary/KeyDictionaryDaoTest.java new file mode 100644 index 0000000000..11c14c99f4 --- /dev/null +++ b/dao/src/test/java/org/thingsboard/server/dao/sqlts/dictionary/KeyDictionaryDaoTest.java @@ -0,0 +1,111 @@ +/** + * Copyright © 2016-2025 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.dao.sqlts.dictionary; + +import org.junit.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.thingsboard.server.dao.dictionary.KeyDictionaryDao; +import org.thingsboard.server.dao.model.sqlts.dictionary.KeyDictionaryCompositeKey; +import org.thingsboard.server.dao.model.sqlts.dictionary.KeyDictionaryEntry; +import org.thingsboard.server.dao.service.AbstractServiceTest; +import org.thingsboard.server.dao.service.DaoSqlTest; + +import java.util.Arrays; +import java.util.Optional; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; + +import static org.assertj.core.api.Assertions.assertThat; + +@DaoSqlTest +public class KeyDictionaryDaoTest extends AbstractServiceTest { + + @Autowired + private KeyDictionaryDao keyDictionaryDao; + + @Autowired + private KeyDictionaryRepository keyDictionaryRepository; + + private static final String KEY = "testKeyDictionaryDaoTestKey"; + + @Test + public void testGetOrSaveKeyId_concurrent() throws Exception { + int threads = 8; + ExecutorService executor = Executors.newFixedThreadPool(threads); + + CountDownLatch allReady = new CountDownLatch(threads); + CountDownLatch start = new CountDownLatch(1); + CountDownLatch allDone = new CountDownLatch(threads); + + Integer[] keyIds = new Integer[threads]; + + try { + for (int i = 0; i < threads; i++) { + final int idx = i; + executor.submit(() -> { + allReady.countDown(); + try { + // wait until all threads are ready + start.await(); + // concurrent call + Integer id = keyDictionaryDao.getOrSaveKeyId(KEY); + keyIds[idx] = id; + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } finally { + allDone.countDown(); + } + }); + } + + // ensure all threads are queued + allReady.await(5, TimeUnit.SECONDS); + // fire the start gun + start.countDown(); + // wait for all to finish + allDone.await(10, TimeUnit.SECONDS); + } finally { + executor.shutdownNow(); + } + + // basic sanity + for (int i = 0; i < threads; i++) { + assertThat(keyIds[i]) + .as("keyId[%s]", i) + .isNotNull() + .isGreaterThan(0); + } + + // all threads must see the same keyId + int first = keyIds[0]; + assertThat(first).isGreaterThan(0); + assertThat(Arrays.stream(keyIds).distinct().count()) + .as("all threads should get the same keyId") + .isEqualTo(1); + + // DB must have exactly one row for this key and the same id + KeyDictionaryCompositeKey id = new KeyDictionaryCompositeKey(KEY); + Optional entry = keyDictionaryRepository.findById(id); + + assertThat(entry.isPresent()).isTrue(); + assertThat(entry.get().getKeyId()).isEqualTo(first); + + keyDictionaryRepository.deleteById(id); + } + +} diff --git a/edqs/src/main/resources/edqs.yml b/edqs/src/main/resources/edqs.yml index f6b611d5a9..9bdee541a3 100644 --- a/edqs/src/main/resources/edqs.yml +++ b/edqs/src/main/resources/edqs.yml @@ -177,6 +177,8 @@ queue: print-interval-ms: "${TB_QUEUE_KAFKA_CONSUMER_STATS_MIN_PRINT_INTERVAL_MS:60000}" # Time to wait for the stats-loading requests to Kafka to finish kafka-response-timeout-ms: "${TB_QUEUE_KAFKA_CONSUMER_STATS_RESPONSE_TIMEOUT_MS:1000}" + # Topics cache TTL in milliseconds. 5 minutes by default + topics_cache_ttl_ms: "${TB_QUEUE_KAFKA_TOPICS_CACHE_TTL_MS:300000}" partitions: hash_function_name: "${TB_QUEUE_PARTITIONS_HASH_FUNCTION_NAME:murmur3_128}" # murmur3_32, murmur3_128 or sha256 diff --git a/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/connectivity/CoapClientTest.java b/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/connectivity/CoapClientTest.java index 995b90e529..5697d40db4 100644 --- a/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/connectivity/CoapClientTest.java +++ b/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/connectivity/CoapClientTest.java @@ -21,6 +21,7 @@ import org.testng.annotations.AfterMethod; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; import org.thingsboard.common.util.JacksonUtil; +import org.thingsboard.server.common.data.AttributeScope; import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.DeviceProfile; import org.thingsboard.server.common.data.DeviceProfileProvisionType; @@ -28,6 +29,8 @@ import org.thingsboard.server.common.data.security.DeviceCredentials; import org.thingsboard.server.msa.AbstractCoapClientTest; import org.thingsboard.server.msa.DisableUIListeners; +import java.util.Map; + import static org.assertj.core.api.Assertions.assertThat; import static org.thingsboard.server.msa.prototypes.DevicePrototypes.defaultDevicePrototype; @@ -52,14 +55,27 @@ public class CoapClientTest extends AbstractCoapClientTest{ DeviceProfile deviceProfile = testRestClient.getDeviceProfileById(device.getDeviceProfileId()); deviceProfile = updateDeviceProfileWithProvisioningStrategy(deviceProfile, DeviceProfileProvisionType.CHECK_PRE_PROVISIONED_DEVICES); - DeviceCredentials expectedDeviceCredentials = testRestClient.getDeviceCredentialsByDeviceId(device.getId()); + DeviceCredentials deviceCreds = testRestClient.getDeviceCredentialsByDeviceId(device.getId()); JsonNode provisionResponse = JacksonUtil.fromBytes(createCoapClientAndPublish(device.getName())); - assertThat(provisionResponse.get("credentialsType").asText()).isEqualTo(expectedDeviceCredentials.getCredentialsType().name()); - assertThat(provisionResponse.get("credentialsValue").asText()).isEqualTo(expectedDeviceCredentials.getCredentialsId()); + assertThat(provisionResponse.get("credentialsType").asText()).isEqualTo(deviceCreds.getCredentialsType().name()); + assertThat(provisionResponse.get("credentialsValue").asText()).isEqualTo(deviceCreds.getCredentialsId()); assertThat(provisionResponse.get("status").asText()).isEqualTo("SUCCESS"); + JsonNode attributes = testRestClient.getAttributes(device.getId(), AttributeScope.SERVER_SCOPE, "provisionState"); + assertThat(attributes.get(0).get("value").asText()).isEqualTo("provisioned"); + + // provision second time should fail + JsonNode provisionResponse2 = JacksonUtil.fromBytes(createCoapClientAndPublish(device.getName())); + assertThat(provisionResponse2.get("status").asText()).isEqualTo("FAILURE"); + + // update provision attribute to non-valid value + testRestClient.postTelemetryAttribute(device.getId(), AttributeScope.SERVER_SCOPE.name(), JacksonUtil.valueToTree(Map.of("provisionState", "non-valid"))); + + JsonNode provisionResponse3 = JacksonUtil.fromBytes(createCoapClientAndPublish(device.getName())); + assertThat(provisionResponse3.get("status").asText()).isEqualTo("FAILURE"); + updateDeviceProfileWithProvisioningStrategy(deviceProfile, DeviceProfileProvisionType.DISABLED); } diff --git a/msa/edqs/docker/Dockerfile b/msa/edqs/docker/Dockerfile index e9099c09c5..2ecd46fa45 100644 --- a/msa/edqs/docker/Dockerfile +++ b/msa/edqs/docker/Dockerfile @@ -14,7 +14,7 @@ # limitations under the License. # -FROM thingsboard/openjdk17:bookworm-slim +FROM ${docker.base.image} COPY start-tb-edqs.sh ${pkg.name}.deb /tmp/ diff --git a/msa/js-executor/package.json b/msa/js-executor/package.json index 220561f6e7..3f4370b642 100644 --- a/msa/js-executor/package.json +++ b/msa/js-executor/package.json @@ -1,7 +1,7 @@ { "name": "thingsboard-js-executor", "private": true, - "version": "4.2.1", + "version": "4.2.1.1", "description": "ThingsBoard JavaScript Executor Microservice", "main": "server.ts", "bin": "server.js", @@ -15,7 +15,7 @@ "dependencies": { "config": "^4.1.1", "express": "^5.1.0", - "js-yaml": "^4.1.0", + "js-yaml": "^4.1.1", "kafkajs": "^2.2.4", "long": "^5.3.2", "uuid-parse": "^1.1.0", diff --git a/msa/js-executor/yarn.lock b/msa/js-executor/yarn.lock index 25ed229141..1d42a9cd96 100644 --- a/msa/js-executor/yarn.lock +++ b/msa/js-executor/yarn.lock @@ -945,10 +945,10 @@ isarray@~1.0.0: resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" integrity sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ== -js-yaml@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" - integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== +js-yaml@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.1.tgz#854c292467705b699476e1a2decc0c8a3458806b" + integrity sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA== dependencies: argparse "^2.0.1" @@ -1533,9 +1533,9 @@ supports-preserve-symlinks-flag@^1.0.0: integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== tar-fs@^2.0.0, tar-fs@^2.1.1: - version "2.1.3" - resolved "https://registry.yarnpkg.com/tar-fs/-/tar-fs-2.1.3.tgz#fb3b8843a26b6f13a08e606f7922875eb1fbbf92" - integrity sha512-090nwYJDmlhwFwEW3QQl+vaNnxsO2yVsd45eTKRBzSzu+hlb1w2K9inVq5b0ngXuLVqQ4ApvsUHHnu/zQNkWAg== + version "2.1.4" + resolved "https://registry.yarnpkg.com/tar-fs/-/tar-fs-2.1.4.tgz#800824dbf4ef06ded9afea4acafe71c67c76b930" + integrity sha512-mDAjwmZdh7LTT6pNleZ05Yt65HC3E+NiQzl672vQG38jIrehtJk/J3mNwIg+vShQPcLF/LV7CMnDW6vjj6sfYQ== dependencies: chownr "^1.1.1" mkdirp-classic "^0.5.2" diff --git a/msa/monitoring/docker/Dockerfile b/msa/monitoring/docker/Dockerfile index a0b38bb3bd..d32f4d06d6 100644 --- a/msa/monitoring/docker/Dockerfile +++ b/msa/monitoring/docker/Dockerfile @@ -14,7 +14,7 @@ # limitations under the License. # -FROM thingsboard/openjdk17:bookworm-slim +FROM ${docker.base.image} COPY start-tb-monitoring.sh ${pkg.name}.deb /tmp/ diff --git a/msa/pom.xml b/msa/pom.xml index 9d3b1d1466..48c83f6ee1 100644 --- a/msa/pom.xml +++ b/msa/pom.xml @@ -32,6 +32,7 @@ ${basedir}/.. thingsboard + thingsboard/openjdk17:bookworm-slim true true 1.4.13 diff --git a/msa/tb-node/docker/Dockerfile b/msa/tb-node/docker/Dockerfile index 013a37ef9c..c084c9c15b 100644 --- a/msa/tb-node/docker/Dockerfile +++ b/msa/tb-node/docker/Dockerfile @@ -14,7 +14,7 @@ # limitations under the License. # -FROM thingsboard/openjdk17:bookworm-slim +FROM ${docker.base.image} COPY logback.xml start-tb-node.sh ${pkg.name}.deb /tmp/ diff --git a/msa/transport/coap/docker/Dockerfile b/msa/transport/coap/docker/Dockerfile index 1d88541096..f5aa18898c 100644 --- a/msa/transport/coap/docker/Dockerfile +++ b/msa/transport/coap/docker/Dockerfile @@ -14,7 +14,7 @@ # limitations under the License. # -FROM thingsboard/openjdk17:bookworm-slim +FROM ${docker.base.image} COPY start-tb-coap-transport.sh ${pkg.name}.deb /tmp/ diff --git a/msa/transport/http/docker/Dockerfile b/msa/transport/http/docker/Dockerfile index d7c8622ace..f224a776ad 100644 --- a/msa/transport/http/docker/Dockerfile +++ b/msa/transport/http/docker/Dockerfile @@ -14,7 +14,7 @@ # limitations under the License. # -FROM thingsboard/openjdk17:bookworm-slim +FROM ${docker.base.image} COPY start-tb-http-transport.sh ${pkg.name}.deb /tmp/ diff --git a/msa/transport/lwm2m/docker/Dockerfile b/msa/transport/lwm2m/docker/Dockerfile index ec65d9a8a5..6b35776fce 100644 --- a/msa/transport/lwm2m/docker/Dockerfile +++ b/msa/transport/lwm2m/docker/Dockerfile @@ -14,7 +14,7 @@ # limitations under the License. # -FROM thingsboard/openjdk17:bookworm-slim +FROM ${docker.base.image} COPY start-tb-lwm2m-transport.sh ${pkg.name}.deb /tmp/ diff --git a/msa/transport/mqtt/docker/Dockerfile b/msa/transport/mqtt/docker/Dockerfile index 1502b9e3c0..270d357e4a 100644 --- a/msa/transport/mqtt/docker/Dockerfile +++ b/msa/transport/mqtt/docker/Dockerfile @@ -14,7 +14,7 @@ # limitations under the License. # -FROM thingsboard/openjdk17:bookworm-slim +FROM ${docker.base.image} COPY start-tb-mqtt-transport.sh ${pkg.name}.deb /tmp/ diff --git a/msa/transport/snmp/docker/Dockerfile b/msa/transport/snmp/docker/Dockerfile index 0ec79e5148..713ff11607 100644 --- a/msa/transport/snmp/docker/Dockerfile +++ b/msa/transport/snmp/docker/Dockerfile @@ -14,7 +14,7 @@ # limitations under the License. # -FROM thingsboard/openjdk17:bookworm-slim +FROM ${docker.base.image} COPY start-tb-snmp-transport.sh ${pkg.name}.deb /tmp/ diff --git a/msa/vc-executor-docker/docker/Dockerfile b/msa/vc-executor-docker/docker/Dockerfile index 3c65098c42..ae03092daf 100644 --- a/msa/vc-executor-docker/docker/Dockerfile +++ b/msa/vc-executor-docker/docker/Dockerfile @@ -14,7 +14,7 @@ # limitations under the License. # -FROM thingsboard/openjdk17:bookworm-slim +FROM ${docker.base.image} ENV DEBIAN_FRONTEND=noninteractive RUN apt-get update \ diff --git a/msa/vc-executor/src/main/resources/tb-vc-executor.yml b/msa/vc-executor/src/main/resources/tb-vc-executor.yml index 7d1166e512..ea89fb7d23 100644 --- a/msa/vc-executor/src/main/resources/tb-vc-executor.yml +++ b/msa/vc-executor/src/main/resources/tb-vc-executor.yml @@ -151,6 +151,8 @@ queue: print-interval-ms: "${TB_QUEUE_KAFKA_CONSUMER_STATS_MIN_PRINT_INTERVAL_MS:60000}" # Time to wait for the stats-loading requests to Kafka to finis kafka-response-timeout-ms: "${TB_QUEUE_KAFKA_CONSUMER_STATS_RESPONSE_TIMEOUT_MS:1000}" + # Topics cache TTL in milliseconds. 5 minutes by default + topics_cache_ttl_ms: "${TB_QUEUE_KAFKA_TOPICS_CACHE_TTL_MS:300000}" partitions: hash_function_name: "${TB_QUEUE_PARTITIONS_HASH_FUNCTION_NAME:murmur3_128}" # murmur3_32, murmur3_128 or sha256 core: diff --git a/msa/web-ui/package.json b/msa/web-ui/package.json index 2fcf6ab914..97d69546bc 100644 --- a/msa/web-ui/package.json +++ b/msa/web-ui/package.json @@ -1,7 +1,7 @@ { "name": "thingsboard-web-ui", "private": true, - "version": "4.2.1", + "version": "4.2.1.1", "description": "ThingsBoard Web UI Microservice", "main": "server.ts", "bin": "server.js", @@ -19,7 +19,7 @@ "express": "^5.1.0", "http": "0.0.0", "http-proxy": "^1.18.1", - "js-yaml": "^4.1.0", + "js-yaml": "^4.1.1", "winston": "^3.17.0", "winston-daily-rotate-file": "^5.0.0" }, diff --git a/msa/web-ui/server.ts b/msa/web-ui/server.ts index bee2e5af31..db0a464499 100644 --- a/msa/web-ui/server.ts +++ b/msa/web-ui/server.ts @@ -81,12 +81,12 @@ let connections: Socket[] = []; } } }); - app.all('/api/*', (req, res) => { + app.all('/api/*splat', (req, res) => { logger.debug(req.method + ' ' + req.originalUrl); apiProxy.web(req, res); }); - app.all('/static/rulenode/*', (req, res) => { + app.all('/static/rulenode/*splat', (req, res) => { apiProxy.web(req, res); }); diff --git a/msa/web-ui/yarn.lock b/msa/web-ui/yarn.lock index 7af758435e..0f8b6f3eed 100644 --- a/msa/web-ui/yarn.lock +++ b/msa/web-ui/yarn.lock @@ -1017,10 +1017,10 @@ isarray@~1.0.0: resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" integrity sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ== -js-yaml@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" - integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== +js-yaml@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.1.tgz#854c292467705b699476e1a2decc0c8a3458806b" + integrity sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA== dependencies: argparse "^2.0.1" @@ -1615,9 +1615,9 @@ supports-preserve-symlinks-flag@^1.0.0: integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== tar-fs@^2.0.0, tar-fs@^2.1.1: - version "2.1.3" - resolved "https://registry.yarnpkg.com/tar-fs/-/tar-fs-2.1.3.tgz#fb3b8843a26b6f13a08e606f7922875eb1fbbf92" - integrity sha512-090nwYJDmlhwFwEW3QQl+vaNnxsO2yVsd45eTKRBzSzu+hlb1w2K9inVq5b0ngXuLVqQ4ApvsUHHnu/zQNkWAg== + version "2.1.4" + resolved "https://registry.yarnpkg.com/tar-fs/-/tar-fs-2.1.4.tgz#800824dbf4ef06ded9afea4acafe71c67c76b930" + integrity sha512-mDAjwmZdh7LTT6pNleZ05Yt65HC3E+NiQzl672vQG38jIrehtJk/J3mNwIg+vShQPcLF/LV7CMnDW6vjj6sfYQ== dependencies: chownr "^1.1.1" mkdirp-classic "^0.5.2" diff --git a/packaging/java/build.gradle b/packaging/java/build.gradle index 499c34c412..bb0c8a94de 100644 --- a/packaging/java/build.gradle +++ b/packaging/java/build.gradle @@ -92,7 +92,11 @@ buildRpm { archiveVersion = projectVersion.replace('-', '') archiveFileName = "${pkgName}.rpm" - requires("(java-17 or java-17-headless or jre-17 or jre-17-headless)") // .or() notation does work in RPM plugin + // Support Java 17 (existing), plus Java 21 and Java 25 for RPM-based distros + // Keep using RPM boolean expression syntax since .or() chaining is for DEB only + requires("(java-17 or java-17-headless or jre-17 or jre-17-headless or " + + "java-21 or java-21-headless or jre-21 or jre-21-headless or " + + "java-25 or java-25-headless or jre-25 or jre-25-headless)") from("${buildDir}/conf") { include "${pkgName}.conf" @@ -132,6 +136,8 @@ buildDeb { archiveFileName = "${pkgName}.deb" requires("openjdk-17-jre").or("java17-runtime").or("oracle-java17-installer").or("openjdk-17-jre-headless") + .or("openjdk-21-jre").or("java21-runtime").or("oracle-java21-installer").or("openjdk-21-jre-headless") + .or("openjdk-25-jre").or("java25-runtime").or("oracle-java25-installer").or("openjdk-25-jre-headless") from("${buildDir}/conf") { include "${pkgName}.conf" diff --git a/pom.xml b/pom.xml index 13a8523682..7f8ef8074a 100755 --- a/pom.xml +++ b/pom.xml @@ -63,7 +63,7 @@ 5.6.0 3.9.3 3.25.5 - 1.68.1 + 1.76.0 1.2.8 1.18.38 1.2.5 @@ -86,6 +86,7 @@ org.apache.kafka.common.network.NetworkReceive class in the application module. It addresses the issue https://issues.apache.org/jira/browse/KAFKA-4090. Here is the source to track https://github.com/apache/kafka/tree/trunk/clients/src/main/java/org/apache/kafka/common/network --> 3.9.1 + 1.10.1 8.10.1 3.5.3 2.2 @@ -101,7 +102,7 @@ 1.6.4 1.6.1 - 1.9.4 + 1.11.0 4.4 1.0.4TB 3.7.1 @@ -110,7 +111,7 @@ 4.0.2 1.7.5 3.8.0 - 1.1.0 + 1.8.0-TB 2.38.0 1.24 1.11.0 @@ -146,7 +147,7 @@ 9.2.0 1.1.10.5 9.10.0 - 4.1.125.Final + 4.1.128.Final @@ -911,7 +912,7 @@ import - dev.langchain4j + org.thingsboard.langchain4j langchain4j-bom ${langchain4j.version} pom @@ -1153,6 +1154,17 @@ org.apache.kafka kafka-clients ${kafka.version} + + + org.lz4 + lz4-java + + + + + at.yawk.lz4 + lz4-java + ${lz4.version} com.github.springtestdbunit @@ -1433,6 +1445,12 @@ org.apache.cassandra cassandra-all ${cassandra-all.version} + + + org.lz4 + lz4-java + + org.testng @@ -1908,6 +1926,10 @@ central https://repo1.maven.org/maven2/ + + thingsboard-repo + https://repo.thingsboard.io/artifactory/libs-release-public + spring-snapshots Spring Snapshots diff --git a/rule-engine/rule-engine-api/pom.xml b/rule-engine/rule-engine-api/pom.xml index 80de81c974..c52fb92594 100644 --- a/rule-engine/rule-engine-api/pom.xml +++ b/rule-engine/rule-engine-api/pom.xml @@ -99,7 +99,7 @@ provided - dev.langchain4j + org.thingsboard.langchain4j langchain4j diff --git a/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/RuleEngineTelemetryService.java b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/RuleEngineTelemetryService.java index 678f3a015d..27cf108d1f 100644 --- a/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/RuleEngineTelemetryService.java +++ b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/RuleEngineTelemetryService.java @@ -15,9 +15,6 @@ */ package org.thingsboard.rule.engine.api; -/** - * Created by ashvayka on 02.04.18. - */ public interface RuleEngineTelemetryService { void saveTimeseries(TimeseriesSaveRequest request); diff --git a/rule-engine/rule-engine-components/pom.xml b/rule-engine/rule-engine-components/pom.xml index c775b7b7e9..f582f1277a 100644 --- a/rule-engine/rule-engine-components/pom.xml +++ b/rule-engine/rule-engine-components/pom.xml @@ -96,6 +96,10 @@ org.apache.kafka kafka-clients + + at.yawk.lz4 + lz4-java + com.amazonaws aws-java-sdk-sns @@ -154,7 +158,7 @@ json-path - dev.langchain4j + org.thingsboard.langchain4j langchain4j diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbAbstractGetEntityDataNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbAbstractGetEntityDataNode.java index ebf32bf6b1..1982596e91 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbAbstractGetEntityDataNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbAbstractGetEntityDataNode.java @@ -58,15 +58,9 @@ public abstract class TbAbstractGetEntityDataNode extends Tb protected void processDataAndTell(TbContext ctx, TbMsg msg, T entityId, ObjectNode msgDataAsJsonNode) { DataToFetch dataToFetch = config.getDataToFetch(); switch (dataToFetch) { - case ATTRIBUTES: - processAttributesKvEntryData(ctx, msg, entityId, msgDataAsJsonNode); - break; - case LATEST_TELEMETRY: - processTsKvEntryData(ctx, msg, entityId, msgDataAsJsonNode); - break; - case FIELDS: - processFieldsData(ctx, msg, entityId, msgDataAsJsonNode, true); - break; + case ATTRIBUTES -> processAttributesKvEntryData(ctx, msg, entityId, msgDataAsJsonNode); + case LATEST_TELEMETRY -> processTsKvEntryData(ctx, msg, entityId, msgDataAsJsonNode); + case FIELDS -> processFieldsData(ctx, msg, entityId, msgDataAsJsonNode, true); } } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbAbstractNodeWithFetchTo.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbAbstractNodeWithFetchTo.java index 189ec47ef1..a11e3333ff 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbAbstractNodeWithFetchTo.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbAbstractNodeWithFetchTo.java @@ -17,8 +17,7 @@ package org.thingsboard.rule.engine.metadata; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.node.ObjectNode; -import com.google.common.util.concurrent.AsyncFunction; -import com.google.common.util.concurrent.Futures; +import com.google.common.base.Function; import lombok.extern.slf4j.Slf4j; import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.rule.engine.api.TbContext; @@ -54,12 +53,12 @@ public abstract class TbAbstractNodeWithFetchTo AsyncFunction checkIfEntityIsPresentOrThrow(String message) { + protected Function checkIfEntityIsPresentOrThrow(String message) { return id -> { if (id == null || id.isNullUid()) { - return Futures.immediateFailedFuture(new NoSuchElementException(message)); + throw new NoSuchElementException(message); } - return Futures.immediateFuture(id); + return id; }; } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetCustomerAttributeNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetCustomerAttributeNode.java index d779bacb77..02a1330a53 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetCustomerAttributeNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetCustomerAttributeNode.java @@ -16,19 +16,22 @@ package org.thingsboard.rule.engine.metadata; import com.fasterxml.jackson.databind.JsonNode; -import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import org.thingsboard.rule.engine.api.RuleNode; import org.thingsboard.rule.engine.api.TbContext; import org.thingsboard.rule.engine.api.TbNodeConfiguration; import org.thingsboard.rule.engine.api.TbNodeException; import org.thingsboard.rule.engine.api.util.TbNodeUtils; -import org.thingsboard.rule.engine.util.EntitiesCustomerIdAsyncLoader; +import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.plugin.ComponentType; import org.thingsboard.server.common.data.util.TbPair; +import java.util.NoSuchElementException; + +import static com.google.common.util.concurrent.Futures.immediateFuture; + @RuleNode( type = ComponentType.ENRICHMENT, name = "customer attributes", @@ -44,8 +47,6 @@ import org.thingsboard.server.common.data.util.TbPair; ) public class TbGetCustomerAttributeNode extends TbAbstractGetEntityDataNode { - private static final String CUSTOMER_NOT_FOUND_MESSAGE = "Failed to find customer for entity with id: %s and type: %s"; - @Override protected TbGetEntityDataNodeConfiguration loadNodeConfiguration(TbNodeConfiguration configuration) throws TbNodeException { var config = TbNodeUtils.convert(configuration, TbGetEntityDataNodeConfiguration.class); @@ -56,10 +57,19 @@ public class TbGetCustomerAttributeNode extends TbAbstractGetEntityDataNode findEntityAsync(TbContext ctx, EntityId originator) { - return Futures.transformAsync(EntitiesCustomerIdAsyncLoader.findEntityIdAsync(ctx, originator), - checkIfEntityIsPresentOrThrow(String.format(CUSTOMER_NOT_FOUND_MESSAGE, originator.getId(), originator.getEntityType().getNormalName())), - ctx.getDbCallbackExecutor() - ); + if (originator.getEntityType() == EntityType.CUSTOMER) { + return immediateFuture((CustomerId) originator); + } + return ctx.getEntityService().fetchEntityCustomerIdAsync(ctx.getTenantId(), originator) + .transform(customerIdOpt -> { + if (customerIdOpt.isEmpty()) { + throw new NoSuchElementException("Originator not found"); + } + if (customerIdOpt.get().isNullUid()) { + throw new IllegalStateException("Originator is not assigned to any customer"); + } + return customerIdOpt.get(); + }, ctx.getDbCallbackExecutor()); } @Override diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetDeviceAttrNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetDeviceAttrNode.java index cf370114c3..9dbdba8ebe 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetDeviceAttrNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetDeviceAttrNode.java @@ -55,7 +55,7 @@ public class TbGetDeviceAttrNode extends TbAbstractGetAttributesNode findEntityIdAsync(TbContext ctx, TbMsg msg) { - return Futures.transformAsync( + return Futures.transform( EntitiesRelatedDeviceIdAsyncLoader.findDeviceAsync(ctx, msg.getOriginator(), config.getDeviceRelationsQuery()), checkIfEntityIsPresentOrThrow(RELATED_DEVICE_NOT_FOUND_MESSAGE), ctx.getDbCallbackExecutor()); diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetRelatedAttributeNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetRelatedAttributeNode.java index dffcaf35ba..fcd11a08f1 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetRelatedAttributeNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetRelatedAttributeNode.java @@ -58,7 +58,7 @@ public class TbGetRelatedAttributeNode extends TbAbstractGetEntityDataNode findEntityAsync(TbContext ctx, EntityId originator) { var relatedAttrConfig = (TbGetRelatedDataNodeConfiguration) config; - return Futures.transformAsync( + return Futures.transform( EntitiesRelatedEntityIdAsyncLoader.findEntityAsync(ctx, originator, relatedAttrConfig.getRelationsQuery()), checkIfEntityIsPresentOrThrow(RELATED_ENTITY_NOT_FOUND_MESSAGE), ctx.getDbCallbackExecutor()); diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/DeviceState.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/DeviceState.java index 4bd81050db..63db109d64 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/DeviceState.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/DeviceState.java @@ -17,6 +17,7 @@ package org.thingsboard.rule.engine.profile; import com.google.gson.JsonElement; import com.google.gson.JsonParser; +import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.rule.engine.api.TbContext; @@ -29,9 +30,14 @@ import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.DeviceProfile; import org.thingsboard.server.common.data.StringUtils; import org.thingsboard.server.common.data.alarm.Alarm; +import org.thingsboard.server.common.data.device.profile.AlarmCondition; import org.thingsboard.server.common.data.device.profile.AlarmConditionFilterKey; import org.thingsboard.server.common.data.device.profile.AlarmConditionKeyType; +import org.thingsboard.server.common.data.device.profile.AlarmConditionSpec; +import org.thingsboard.server.common.data.device.profile.AlarmConditionSpecType; +import org.thingsboard.server.common.data.device.profile.AlarmRule; import org.thingsboard.server.common.data.device.profile.DeviceProfileAlarm; +import org.thingsboard.server.common.data.device.profile.DurationAlarmConditionSpec; import org.thingsboard.server.common.data.exception.ApiUsageLimitsExceededException; import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.common.data.id.DeviceProfileId; @@ -39,6 +45,8 @@ import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.kv.AttributeKvEntry; import org.thingsboard.server.common.data.kv.KvEntry; import org.thingsboard.server.common.data.kv.TsKvEntry; +import org.thingsboard.server.common.data.query.DynamicValue; +import org.thingsboard.server.common.data.query.DynamicValueSourceType; import org.thingsboard.server.common.data.query.EntityKey; import org.thingsboard.server.common.data.query.EntityKeyType; import org.thingsboard.server.common.data.rule.RuleNodeState; @@ -56,6 +64,7 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.ExecutionException; import java.util.stream.Collectors; +import java.util.stream.Stream; import static org.thingsboard.server.common.data.msg.TbMsgType.ACTIVITY_EVENT; import static org.thingsboard.server.common.data.msg.TbMsgType.ALARM_ACK; @@ -87,6 +96,10 @@ class DeviceState { this.deviceId = deviceId; this.deviceProfile = deviceProfile; + if (hasDurationRulesWithDynamicValueFromCurrentDevice(deviceProfile)) { + latestValues = fetchLatestValues(ctx, deviceId); + } + this.dynamicPredicateValueCtx = new DynamicPredicateValueCtxImpl(ctx.getTenantId(), deviceId, ctx); if (config.isPersistAlarmRulesState()) { @@ -116,7 +129,10 @@ class DeviceState { public void updateProfile(TbContext ctx, DeviceProfile deviceProfile) throws ExecutionException, InterruptedException { Set oldKeys = Set.copyOf(this.deviceProfile.getEntityKeys()); this.deviceProfile.updateDeviceProfile(deviceProfile); - if (latestValues != null) { + + if (latestValues == null && hasDurationRulesWithDynamicValueFromCurrentDevice(this.deviceProfile)) { + latestValues = fetchLatestValues(ctx, deviceId); + } else if (latestValues != null) { Set keysToFetch = new HashSet<>(this.deviceProfile.getEntityKeys()); keysToFetch.removeAll(oldKeys); if (!keysToFetch.isEmpty()) { @@ -134,10 +150,31 @@ class DeviceState { } } + private static boolean hasDurationRulesWithDynamicValueFromCurrentDevice(ProfileState deviceProfile) { + return deviceProfile.getAlarmSettings().stream().anyMatch(DeviceState::isDurationRuleWithDynamicValueFromCurrentDevice); + } + + private static boolean isDurationRuleWithDynamicValueFromCurrentDevice(DeviceProfileAlarm alarm) { + return Stream.concat(alarm.getCreateRules().values().stream(), Stream.ofNullable(alarm.getClearRule())) + .map(AlarmRule::getCondition) + .map(AlarmCondition::getSpec) + .anyMatch(spec -> isDurationRule(spec) && hasDynamicDurationValueFromCurrentDevice((DurationAlarmConditionSpec) spec)); + } + + private static boolean isDurationRule(AlarmConditionSpec spec) { + return spec instanceof DurationAlarmConditionSpec durationSpec && durationSpec.getType() == AlarmConditionSpecType.DURATION; + } + + private static boolean hasDynamicDurationValueFromCurrentDevice(DurationAlarmConditionSpec spec) { + DynamicValue dynamicValue = spec.getPredicate().getDynamicValue(); + return dynamicValue != null && dynamicValue.getSourceType() == DynamicValueSourceType.CURRENT_DEVICE; + } + public void harvestAlarms(TbContext ctx, long ts) throws ExecutionException, InterruptedException { log.debug("[{}] Going to harvest alarms: {}", ctx.getSelfId(), ts); boolean stateChanged = false; for (AlarmState state : alarmStates.values()) { + state.setDataSnapshot(latestValues); stateChanged |= state.process(ctx, ts); } if (persistState && stateChanged) { @@ -347,7 +384,8 @@ class DeviceState { return EntityKeyType.ATTRIBUTE; } - private DataSnapshot fetchLatestValues(TbContext ctx, EntityId originator) throws ExecutionException, InterruptedException { + @SneakyThrows + private DataSnapshot fetchLatestValues(TbContext ctx, EntityId originator) { Set entityKeysToFetch = deviceProfile.getEntityKeys(); DataSnapshot result = new DataSnapshot(entityKeysToFetch); addEntityKeysToSnapshot(ctx, originator, entityKeysToFetch, result); diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbChangeOriginatorNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbChangeOriginatorNode.java index e3ab60a6e0..a97cc22d5b 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbChangeOriginatorNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbChangeOriginatorNode.java @@ -25,7 +25,6 @@ import org.thingsboard.rule.engine.api.TbNodeException; import org.thingsboard.rule.engine.api.util.TbNodeUtils; import org.thingsboard.rule.engine.util.EntitiesAlarmOriginatorIdAsyncLoader; import org.thingsboard.rule.engine.util.EntitiesByNameAndTypeLoader; -import org.thingsboard.rule.engine.util.EntitiesCustomerIdAsyncLoader; import org.thingsboard.rule.engine.util.EntitiesRelatedEntityIdAsyncLoader; import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.StringUtils; @@ -36,6 +35,7 @@ import org.thingsboard.server.common.msg.TbMsg; import java.util.List; import java.util.NoSuchElementException; +import static com.google.common.util.concurrent.Futures.immediateFuture; import static org.thingsboard.rule.engine.transform.OriginatorSource.ENTITY; import static org.thingsboard.rule.engine.transform.OriginatorSource.RELATED; @@ -74,16 +74,20 @@ public class TbChangeOriginatorNode extends TbAbstractTransformNode getNewOriginator(TbContext ctx, TbMsg msg) { switch (config.getOriginatorSource()) { case CUSTOMER: - return EntitiesCustomerIdAsyncLoader.findEntityIdAsync(ctx, msg.getOriginator()); + if (msg.getOriginator().getEntityType() == EntityType.CUSTOMER) { + return immediateFuture(msg.getOriginator()); + } + return ctx.getEntityService().fetchEntityCustomerIdAsync(ctx.getTenantId(), msg.getOriginator()) + .transform(customerIdOpt -> customerIdOpt.orElse(null), ctx.getDbCallbackExecutor()); case TENANT: - return Futures.immediateFuture(ctx.getTenantId()); + return immediateFuture(ctx.getTenantId()); case RELATED: return EntitiesRelatedEntityIdAsyncLoader.findEntityAsync(ctx, msg.getOriginator(), config.getRelationsQuery()); case ALARM_ORIGINATOR: @@ -93,7 +97,7 @@ public class TbChangeOriginatorNode extends TbAbstractTransformNode findEntityIdAsync(TbContext ctx, EntityId originator) { - switch (originator.getEntityType()) { - case CUSTOMER: - return Futures.immediateFuture((CustomerId) originator); - case USER: - return toCustomerIdAsync(ctx, ctx.getUserService().findUserByIdAsync(ctx.getTenantId(), (UserId) originator)); - case ASSET: - return toCustomerIdAsync(ctx, ctx.getAssetService().findAssetByIdAsync(ctx.getTenantId(), (AssetId) originator)); - case DEVICE: - return toCustomerIdAsync(ctx, Futures.immediateFuture(ctx.getDeviceService().findDeviceById(ctx.getTenantId(), (DeviceId) originator))); - default: - return Futures.immediateFailedFuture(new TbNodeException("Unexpected originator EntityType: " + originator.getEntityType())); - } - } - - private static ListenableFuture toCustomerIdAsync(TbContext ctx, ListenableFuture future) { - return Futures.transform(future, in -> in != null ? in.getCustomerId() : null, ctx.getDbCallbackExecutor()); - } - -} diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/TestDbCallbackExecutor.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/TestDbCallbackExecutor.java index b3afec500c..f27ea73ce6 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/TestDbCallbackExecutor.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/TestDbCallbackExecutor.java @@ -28,7 +28,7 @@ public class TestDbCallbackExecutor implements ListeningExecutor { try { return Futures.immediateFuture(task.call()); } catch (Exception e) { - throw new RuntimeException(e); + return Futures.immediateFailedFuture(e); } } diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetCustomerAttributeNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetCustomerAttributeNodeTest.java index 3f2c58f191..942b1ab5ce 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetCustomerAttributeNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetCustomerAttributeNodeTest.java @@ -16,7 +16,7 @@ package org.thingsboard.rule.engine.metadata; import com.fasterxml.jackson.databind.JsonNode; -import com.google.common.util.concurrent.Futures; +import com.google.common.util.concurrent.FluentFuture; import lombok.RequiredArgsConstructor; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; @@ -53,19 +53,19 @@ import org.thingsboard.server.common.data.msg.TbMsgType; import org.thingsboard.server.common.data.util.TbPair; import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsgMetaData; -import org.thingsboard.server.dao.asset.AssetService; import org.thingsboard.server.dao.attributes.AttributesService; -import org.thingsboard.server.dao.device.DeviceService; +import org.thingsboard.server.dao.entity.EntityService; import org.thingsboard.server.dao.timeseries.TimeseriesService; -import org.thingsboard.server.dao.user.UserService; import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.NoSuchElementException; +import java.util.Optional; import java.util.UUID; +import static com.google.common.util.concurrent.Futures.immediateFuture; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertInstanceOf; @@ -73,19 +73,20 @@ import static org.junit.jupiter.api.Assertions.assertThrows; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.lenient; import static org.mockito.Mockito.never; -import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoInteractions; import static org.mockito.Mockito.when; @ExtendWith(MockitoExtension.class) public class TbGetCustomerAttributeNodeTest { - private static final DeviceId DUMMY_DEVICE_ORIGINATOR = new DeviceId(UUID.randomUUID()); - private static final TenantId TENANT_ID = new TenantId(UUID.randomUUID()); - private static final CustomerId CUSTOMER_ID = new CustomerId(UUID.randomUUID()); - private static final ListeningExecutor DB_EXECUTOR = new TestDbCallbackExecutor(); + private final DeviceId DUMMY_DEVICE_ORIGINATOR = new DeviceId(UUID.randomUUID()); + private final TenantId TENANT_ID = TenantId.fromUUID(UUID.randomUUID()); + private final CustomerId CUSTOMER_ID = new CustomerId(UUID.randomUUID()); + private final ListeningExecutor DB_EXECUTOR = new TestDbCallbackExecutor(); + @Mock private TbContext ctxMock; @Mock @@ -93,21 +94,24 @@ public class TbGetCustomerAttributeNodeTest { @Mock private TimeseriesService timeseriesServiceMock; @Mock - private UserService userServiceMock; - @Mock - private AssetService assetServiceMock; - @Mock - private DeviceService deviceServiceMock; + private EntityService entityServiceMock; + private TbGetCustomerAttributeNode node; private TbGetEntityDataNodeConfiguration config; private TbNodeConfiguration nodeConfiguration; private TbMsg msg; @BeforeEach - public void setUp() { + public void setup() { node = new TbGetCustomerAttributeNode(); config = new TbGetEntityDataNodeConfiguration().defaultConfiguration(); nodeConfiguration = new TbNodeConfiguration(JacksonUtil.valueToTree(config)); + + lenient().when(ctxMock.getTenantId()).thenReturn(TENANT_ID); + lenient().when(ctxMock.getDbCallbackExecutor()).thenReturn(DB_EXECUTOR); + lenient().when(ctxMock.getAttributesService()).thenReturn(attributesServiceMock); + lenient().when(ctxMock.getTimeseriesService()).thenReturn(timeseriesServiceMock); + lenient().when(ctxMock.getEntityService()).thenReturn(entityServiceMock); } @Test @@ -237,12 +241,9 @@ public class TbGetCustomerAttributeNodeTest { .data(TbMsg.EMPTY_JSON_OBJECT) .build(); - when(ctxMock.getTenantId()).thenReturn(TENANT_ID); - - when(ctxMock.getUserService()).thenReturn(userServiceMock); - doReturn(Futures.immediateFuture(null)).when(userServiceMock).findUserByIdAsync(eq(TENANT_ID), eq(userId)); - - when(ctxMock.getDbCallbackExecutor()).thenReturn(DB_EXECUTOR); + when(entityServiceMock.fetchEntityCustomerIdAsync(TENANT_ID, userId)).thenReturn( + FluentFuture.from(immediateFuture(Optional.empty())) + ); // WHEN node.onMsg(ctxMock, msg); @@ -252,18 +253,13 @@ public class TbGetCustomerAttributeNodeTest { var actualExceptionCaptor = ArgumentCaptor.forClass(Throwable.class); verify(ctxMock, never()).tellSuccess(any()); - verify(ctxMock, times(1)) - .tellFailure(actualMessageCaptor.capture(), actualExceptionCaptor.capture()); + verify(ctxMock).tellFailure(actualMessageCaptor.capture(), actualExceptionCaptor.capture()); var actualMessage = actualMessageCaptor.getValue(); var actualException = actualExceptionCaptor.getValue(); - var expectedExceptionMessage = String.format( - "Failed to find customer for entity with id: %s and type: %s", - userId.getId(), userId.getEntityType().getNormalName()); - assertEquals(msg, actualMessage); - assertEquals(expectedExceptionMessage, actualException.getMessage()); + assertEquals("Originator not found", actualException.getMessage()); assertInstanceOf(NoSuchElementException.class, actualException); } @@ -282,16 +278,12 @@ public class TbGetCustomerAttributeNodeTest { ); var expectedPatternProcessedKeysList = List.of("sourceKey1", "sourceKey2", "sourceKey3"); - when(ctxMock.getTenantId()).thenReturn(TENANT_ID); - - when(ctxMock.getDeviceService()).thenReturn(deviceServiceMock); - doReturn(device).when(deviceServiceMock).findDeviceById(eq(TENANT_ID), eq(device.getId())); + when(entityServiceMock.fetchEntityCustomerIdAsync(TENANT_ID, device.getId())).thenReturn( + FluentFuture.from(immediateFuture(Optional.of(CUSTOMER_ID))) + ); - when(ctxMock.getAttributesService()).thenReturn(attributesServiceMock); when(attributesServiceMock.find(eq(TENANT_ID), eq(CUSTOMER_ID), eq(AttributeScope.SERVER_SCOPE), argThat(new ListMatcher<>(expectedPatternProcessedKeysList)))) - .thenReturn(Futures.immediateFuture(attributesList)); - - when(ctxMock.getDbCallbackExecutor()).thenReturn(DB_EXECUTOR); + .thenReturn(immediateFuture(attributesList)); // WHEN node.onMsg(ctxMock, msg); @@ -299,7 +291,7 @@ public class TbGetCustomerAttributeNodeTest { // THEN var actualMessageCaptor = ArgumentCaptor.forClass(TbMsg.class); - verify(ctxMock, times(1)).tellSuccess(actualMessageCaptor.capture()); + verify(ctxMock).tellSuccess(actualMessageCaptor.capture()); verify(ctxMock, never()).tellFailure(any(), any()); var expectedMsgData = "{\"temp\":42," + @@ -329,16 +321,12 @@ public class TbGetCustomerAttributeNodeTest { ); var expectedPatternProcessedKeysList = List.of("sourceKey1", "sourceKey2", "sourceKey3"); - when(ctxMock.getTenantId()).thenReturn(TENANT_ID); - - when(ctxMock.getUserService()).thenReturn(userServiceMock); - doReturn(Futures.immediateFuture(user)).when(userServiceMock).findUserByIdAsync(eq(TENANT_ID), eq(user.getId())); + when(entityServiceMock.fetchEntityCustomerIdAsync(TENANT_ID, user.getId())).thenReturn( + FluentFuture.from(immediateFuture(Optional.of(CUSTOMER_ID))) + ); - when(ctxMock.getAttributesService()).thenReturn(attributesServiceMock); when(attributesServiceMock.find(eq(TENANT_ID), eq(CUSTOMER_ID), eq(AttributeScope.SERVER_SCOPE), argThat(new ListMatcher<>(expectedPatternProcessedKeysList)))) - .thenReturn(Futures.immediateFuture(attributesList)); - - when(ctxMock.getDbCallbackExecutor()).thenReturn(DB_EXECUTOR); + .thenReturn(immediateFuture(attributesList)); // WHEN node.onMsg(ctxMock, msg); @@ -346,7 +334,7 @@ public class TbGetCustomerAttributeNodeTest { // THEN var actualMessageCaptor = ArgumentCaptor.forClass(TbMsg.class); - verify(ctxMock, times(1)).tellSuccess(actualMessageCaptor.capture()); + verify(ctxMock).tellSuccess(actualMessageCaptor.capture()); verify(ctxMock, never()).tellFailure(any(), any()); var expectedMsgMetaData = new TbMsgMetaData(Map.of( @@ -375,21 +363,18 @@ public class TbGetCustomerAttributeNodeTest { ); var expectedPatternProcessedKeysList = List.of("sourceKey1", "sourceKey2", "sourceKey3"); - when(ctxMock.getTenantId()).thenReturn(TENANT_ID); - - when(ctxMock.getTimeseriesService()).thenReturn(timeseriesServiceMock); when(timeseriesServiceMock.findLatest(eq(TENANT_ID), eq(customer.getId()), argThat(new ListMatcher<>(expectedPatternProcessedKeysList)))) - .thenReturn(Futures.immediateFuture(timeseriesList)); - - when(ctxMock.getDbCallbackExecutor()).thenReturn(DB_EXECUTOR); + .thenReturn(immediateFuture(timeseriesList)); // WHEN node.onMsg(ctxMock, msg); // THEN + verifyNoInteractions(entityServiceMock); + var actualMessageCaptor = ArgumentCaptor.forClass(TbMsg.class); - verify(ctxMock, times(1)).tellSuccess(actualMessageCaptor.capture()); + verify(ctxMock).tellSuccess(actualMessageCaptor.capture()); verify(ctxMock, never()).tellFailure(any(), any()); var expectedMsgData = "{\"temp\":42," + @@ -408,7 +393,7 @@ public class TbGetCustomerAttributeNodeTest { public void givenFetchTelemetryToMetaData_whenOnMsg_thenShouldFetchTelemetryToMetaData() { // GIVEN var asset = new Asset(new AssetId(UUID.randomUUID())); - asset.setCustomerId(new CustomerId(UUID.randomUUID())); + asset.setCustomerId(CUSTOMER_ID); prepareMsgAndConfig(TbMsgSource.METADATA, DataToFetch.LATEST_TELEMETRY, asset.getId()); @@ -419,16 +404,12 @@ public class TbGetCustomerAttributeNodeTest { ); var expectedPatternProcessedKeysList = List.of("sourceKey1", "sourceKey2", "sourceKey3"); - when(ctxMock.getTenantId()).thenReturn(TENANT_ID); - - when(ctxMock.getAssetService()).thenReturn(assetServiceMock); - doReturn(Futures.immediateFuture(asset)).when(assetServiceMock).findAssetByIdAsync(eq(TENANT_ID), eq(asset.getId())); - - when(ctxMock.getTimeseriesService()).thenReturn(timeseriesServiceMock); - when(timeseriesServiceMock.findLatest(eq(TENANT_ID), eq(asset.getCustomerId()), argThat(new ListMatcher<>(expectedPatternProcessedKeysList)))) - .thenReturn(Futures.immediateFuture(timeseriesList)); + when(entityServiceMock.fetchEntityCustomerIdAsync(TENANT_ID, asset.getId())).thenReturn( + FluentFuture.from(immediateFuture(Optional.of(CUSTOMER_ID))) + ); - when(ctxMock.getDbCallbackExecutor()).thenReturn(DB_EXECUTOR); + when(timeseriesServiceMock.findLatest(eq(TENANT_ID), eq(CUSTOMER_ID), argThat(new ListMatcher<>(expectedPatternProcessedKeysList)))) + .thenReturn(immediateFuture(timeseriesList)); // WHEN node.onMsg(ctxMock, msg); @@ -436,7 +417,7 @@ public class TbGetCustomerAttributeNodeTest { // THEN var actualMessageCaptor = ArgumentCaptor.forClass(TbMsg.class); - verify(ctxMock, times(1)).tellSuccess(actualMessageCaptor.capture()); + verify(ctxMock).tellSuccess(actualMessageCaptor.capture()); verify(ctxMock, never()).tellFailure(any(), any()); var expectedMsgMetaData = new TbMsgMetaData(Map.of( diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/profile/TbDeviceProfileNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/profile/TbDeviceProfileNodeTest.java index 90c35e59b1..a3d7fffb5d 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/profile/TbDeviceProfileNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/profile/TbDeviceProfileNodeTest.java @@ -16,8 +16,8 @@ package org.thingsboard.rule.engine.profile; import com.fasterxml.jackson.databind.node.ObjectNode; -import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.params.provider.Arguments; @@ -58,8 +58,11 @@ import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.common.data.id.DeviceProfileId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.kv.AttributeKvEntry; +import org.thingsboard.server.common.data.kv.BaseAttributeKvEntry; +import org.thingsboard.server.common.data.kv.BasicTsKvEntry; +import org.thingsboard.server.common.data.kv.DoubleDataEntry; +import org.thingsboard.server.common.data.kv.LongDataEntry; import org.thingsboard.server.common.data.kv.TsKvEntry; -import org.thingsboard.server.common.data.kv.TsKvEntryAggWrapper; import org.thingsboard.server.common.data.msg.TbMsgType; import org.thingsboard.server.common.data.query.BooleanFilterPredicate; import org.thingsboard.server.common.data.query.DynamicValue; @@ -82,19 +85,24 @@ import java.math.BigDecimal; import java.math.RoundingMode; import java.util.ArrayList; import java.util.Arrays; -import java.util.Collections; import java.util.List; import java.util.Optional; -import java.util.Set; import java.util.TreeMap; import java.util.UUID; import java.util.concurrent.TimeUnit; import java.util.stream.Stream; +import static com.google.common.util.concurrent.Futures.immediateFuture; +import static java.util.Collections.emptyList; +import static java.util.Collections.singleton; +import static java.util.Collections.singletonList; +import static java.util.Collections.singletonMap; +import static org.assertj.core.api.Assertions.assertThatNoException; import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.anySet; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.lenient; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import static org.thingsboard.server.common.data.device.profile.AlarmConditionKeyType.ATTRIBUTE; @@ -126,16 +134,26 @@ public class TbDeviceProfileNodeTest extends AbstractRuleNodeUpgradeTest { private final CustomerId customerId = new CustomerId(UUID.randomUUID()); private final DeviceProfileId deviceProfileId = new DeviceProfileId(UUID.randomUUID()); + @BeforeEach + public void setup() { + lenient().when(ctx.getTenantId()).thenReturn(tenantId); + lenient().when(ctx.getDeviceProfileCache()).thenReturn(cache); + lenient().when(ctx.getTimeseriesService()).thenReturn(timeseriesService); + lenient().when(ctx.getAlarmService()).thenReturn(alarmService); + lenient().when(ctx.getDeviceService()).thenReturn(deviceService); + lenient().when(ctx.getAttributesService()).thenReturn(attributesService); + } + @Test public void testRandomMessageType() throws Exception { init(); DeviceProfile deviceProfile = new DeviceProfile(); DeviceProfileData deviceProfileData = new DeviceProfileData(); - deviceProfileData.setAlarms(Collections.emptyList()); + deviceProfileData.setAlarms(emptyList()); deviceProfile.setProfileData(deviceProfileData); - Mockito.when(cache.get(tenantId, deviceId)).thenReturn(deviceProfile); + when(cache.get(tenantId, deviceId)).thenReturn(deviceProfile); ObjectNode data = JacksonUtil.newObjectNode(); data.put("temperature", 42); TbMsg msg = TbMsg.newMsg() @@ -156,10 +174,10 @@ public class TbDeviceProfileNodeTest extends AbstractRuleNodeUpgradeTest { DeviceProfile deviceProfile = new DeviceProfile(); DeviceProfileData deviceProfileData = new DeviceProfileData(); - deviceProfileData.setAlarms(Collections.emptyList()); + deviceProfileData.setAlarms(emptyList()); deviceProfile.setProfileData(deviceProfileData); - Mockito.when(cache.get(tenantId, deviceId)).thenReturn(deviceProfile); + when(cache.get(tenantId, deviceId)).thenReturn(deviceProfile); ObjectNode data = JacksonUtil.newObjectNode(); data.put("temperature", 42); TbMsg msg = TbMsg.newMsg() @@ -187,20 +205,20 @@ public class TbDeviceProfileNodeTest extends AbstractRuleNodeUpgradeTest { DeviceProfileAlarm dpa = new DeviceProfileAlarm(); dpa.setId("highTemperatureAlarmID"); dpa.setAlarmType("highTemperatureAlarm"); - dpa.setCreateRules(new TreeMap<>(Collections.singletonMap(AlarmSeverity.CRITICAL, alarmRule))); + dpa.setCreateRules(new TreeMap<>(singletonMap(AlarmSeverity.CRITICAL, alarmRule))); AlarmRule clearRule = new AlarmRule(); AlarmCondition clearCondition = getNumericAlarmCondition(TIME_SERIES, "temperature", LESS, 10.0); clearRule.setCondition(clearCondition); dpa.setClearRule(clearRule); - deviceProfileData.setAlarms(Collections.singletonList(dpa)); + deviceProfileData.setAlarms(singletonList(dpa)); deviceProfile.setProfileData(deviceProfileData); - Mockito.when(cache.get(tenantId, deviceId)).thenReturn(deviceProfile); - Mockito.when(timeseriesService.findLatest(tenantId, deviceId, Collections.singleton("temperature"))) - .thenReturn(Futures.immediateFuture(Collections.emptyList())); - Mockito.when(alarmService.findLatestActiveByOriginatorAndType(tenantId, deviceId, "highTemperatureAlarm")).thenReturn(null); + when(cache.get(tenantId, deviceId)).thenReturn(deviceProfile); + when(timeseriesService.findLatest(tenantId, deviceId, singleton("temperature"))) + .thenReturn(immediateFuture(emptyList())); + when(alarmService.findLatestActiveByOriginatorAndType(tenantId, deviceId, "highTemperatureAlarm")).thenReturn(null); registerCreateAlarmMock(alarmService.createAlarm(any()), true); TbMsg theMsg = TbMsg.newMsg() @@ -262,7 +280,7 @@ public class TbDeviceProfileNodeTest extends AbstractRuleNodeUpgradeTest { AlarmConditionFilter highTempFilter = getAlarmConditionFilter(TIME_SERIES, "temperature", GREATER, 50.0); AlarmCondition alarmHighTempCondition = new AlarmCondition(); - alarmHighTempCondition.setCondition(Collections.singletonList(highTempFilter)); + alarmHighTempCondition.setCondition(singletonList(highTempFilter)); AlarmRule alarmHighTempRule = new AlarmRule(); alarmHighTempRule.setCondition(alarmHighTempCondition); DeviceProfileAlarm dpa = new DeviceProfileAlarm(); @@ -276,13 +294,13 @@ public class TbDeviceProfileNodeTest extends AbstractRuleNodeUpgradeTest { dpa.setCreateRules(createRules); - deviceProfileData.setAlarms(Collections.singletonList(dpa)); + deviceProfileData.setAlarms(singletonList(dpa)); deviceProfile.setProfileData(deviceProfileData); - Mockito.when(cache.get(tenantId, deviceId)).thenReturn(deviceProfile); - Mockito.when(timeseriesService.findLatest(tenantId, deviceId, Collections.singleton("temperature"))) - .thenReturn(Futures.immediateFuture(Collections.emptyList())); - Mockito.when(alarmService.findLatestActiveByOriginatorAndType(tenantId, deviceId, "highTemperatureAlarm1")).thenReturn(null); + when(cache.get(tenantId, deviceId)).thenReturn(deviceProfile); + when(timeseriesService.findLatest(tenantId, deviceId, singleton("temperature"))) + .thenReturn(immediateFuture(emptyList())); + when(alarmService.findLatestActiveByOriginatorAndType(tenantId, deviceId, "highTemperatureAlarm1")).thenReturn(null); registerCreateAlarmMock(alarmService.createAlarm(any()), true); TbMsg theMsg = TbMsg.newMsg() @@ -366,7 +384,7 @@ public class TbDeviceProfileNodeTest extends AbstractRuleNodeUpgradeTest { attributeKvEntity.setLastUpdateTs(System.currentTimeMillis()); AttributeKvEntry entry = attributeKvEntity.toData(); - ListenableFuture> attrListListenableFuture = Futures.immediateFuture(Collections.singletonList(entry)); + ListenableFuture> attrListListenableFuture = immediateFuture(singletonList(entry)); AlarmConditionFilter alarmEnabledFilter = new AlarmConditionFilter(); alarmEnabledFilter.setKey(new AlarmConditionFilterKey(AlarmConditionKeyType.CONSTANT, "alarmEnabled")); @@ -396,19 +414,19 @@ public class TbDeviceProfileNodeTest extends AbstractRuleNodeUpgradeTest { DeviceProfileAlarm dpa = new DeviceProfileAlarm(); dpa.setId("alarmEnabledAlarmID"); dpa.setAlarmType("alarmEnabledAlarm"); - dpa.setCreateRules(new TreeMap<>(Collections.singletonMap(AlarmSeverity.CRITICAL, alarmRule))); + dpa.setCreateRules(new TreeMap<>(singletonMap(AlarmSeverity.CRITICAL, alarmRule))); - deviceProfileData.setAlarms(Collections.singletonList(dpa)); + deviceProfileData.setAlarms(singletonList(dpa)); deviceProfile.setProfileData(deviceProfileData); - Mockito.when(cache.get(tenantId, deviceId)).thenReturn(deviceProfile); - Mockito.when(timeseriesService.findLatest(tenantId, deviceId, Collections.singleton("temperature"))) - .thenReturn(Futures.immediateFuture(Collections.emptyList())); - Mockito.when(alarmService.findLatestActiveByOriginatorAndType(tenantId, deviceId, "alarmEnabledAlarm")) + when(cache.get(tenantId, deviceId)).thenReturn(deviceProfile); + when(timeseriesService.findLatest(tenantId, deviceId, singleton("temperature"))) + .thenReturn(immediateFuture(emptyList())); + when(alarmService.findLatestActiveByOriginatorAndType(tenantId, deviceId, "alarmEnabledAlarm")) .thenReturn(null); registerCreateAlarmMock(alarmService.createAlarm(any()), true); - Mockito.when(ctx.getAttributesService()).thenReturn(attributesService); - Mockito.when(attributesService.find(eq(tenantId), eq(deviceId), Mockito.any(AttributeScope.class), Mockito.anySet())) + when(ctx.getAttributesService()).thenReturn(attributesService); + when(attributesService.find(eq(tenantId), eq(deviceId), Mockito.any(AttributeScope.class), Mockito.anySet())) .thenReturn(attrListListenableFuture); TbMsg theMsg = TbMsg.newMsg() @@ -417,7 +435,7 @@ public class TbDeviceProfileNodeTest extends AbstractRuleNodeUpgradeTest { .copyMetaData(TbMsgMetaData.EMPTY) .data(TbMsg.EMPTY_STRING) .build(); - Mockito.when(ctx.newMsg(Mockito.any(), Mockito.any(TbMsgType.class), Mockito.any(), Mockito.any(), Mockito.any(), Mockito.anyString())) + when(ctx.newMsg(Mockito.any(), Mockito.any(TbMsgType.class), Mockito.any(), Mockito.any(), Mockito.any(), Mockito.anyString())) .thenReturn(theMsg); ObjectNode data = JacksonUtil.newObjectNode(); @@ -459,7 +477,7 @@ public class TbDeviceProfileNodeTest extends AbstractRuleNodeUpgradeTest { attributeKvEntity.setLastUpdateTs(System.currentTimeMillis()); AttributeKvEntry entry = attributeKvEntity.toData(); - ListenableFuture> attrListListenableFuture = Futures.immediateFuture(Optional.of(entry)); + ListenableFuture> attrListListenableFuture = immediateFuture(Optional.of(entry)); AlarmConditionFilter alarmEnabledFilter = new AlarmConditionFilter(); alarmEnabledFilter.setKey(new AlarmConditionFilterKey(AlarmConditionKeyType.CONSTANT, "alarmEnabled")); @@ -489,24 +507,24 @@ public class TbDeviceProfileNodeTest extends AbstractRuleNodeUpgradeTest { DeviceProfileAlarm dpa = new DeviceProfileAlarm(); dpa.setId("alarmEnabledAlarmID"); dpa.setAlarmType("alarmEnabledAlarm"); - dpa.setCreateRules(new TreeMap<>(Collections.singletonMap(AlarmSeverity.CRITICAL, alarmRule))); + dpa.setCreateRules(new TreeMap<>(singletonMap(AlarmSeverity.CRITICAL, alarmRule))); - deviceProfileData.setAlarms(Collections.singletonList(dpa)); + deviceProfileData.setAlarms(singletonList(dpa)); deviceProfile.setProfileData(deviceProfileData); - Mockito.when(deviceService.findDeviceById(tenantId, deviceId)).thenReturn(device); - Mockito.when(cache.get(tenantId, deviceId)).thenReturn(deviceProfile); - Mockito.when(timeseriesService.findLatest(tenantId, deviceId, Collections.singleton("temperature"))) - .thenReturn(Futures.immediateFuture(Collections.emptyList())); - Mockito.when(alarmService.findLatestActiveByOriginatorAndType(tenantId, deviceId, "alarmEnabledAlarm")) + when(deviceService.findDeviceById(tenantId, deviceId)).thenReturn(device); + when(cache.get(tenantId, deviceId)).thenReturn(deviceProfile); + when(timeseriesService.findLatest(tenantId, deviceId, singleton("temperature"))) + .thenReturn(immediateFuture(emptyList())); + when(alarmService.findLatestActiveByOriginatorAndType(tenantId, deviceId, "alarmEnabledAlarm")) .thenReturn(null); registerCreateAlarmMock(alarmService.createAlarm(any()), true); - Mockito.when(ctx.getAttributesService()).thenReturn(attributesService); - Mockito.when(attributesService.find(eq(tenantId), eq(deviceId), Mockito.any(AttributeScope.class), Mockito.anySet())) - .thenReturn(Futures.immediateFuture(Collections.emptyList())); - Mockito.when(attributesService.find(eq(tenantId), eq(customerId), Mockito.any(AttributeScope.class), Mockito.anyString())) - .thenReturn(Futures.immediateFuture(Optional.empty())); - Mockito.when(attributesService.find(eq(tenantId), eq(tenantId), Mockito.any(AttributeScope.class), Mockito.anyString())) + when(ctx.getAttributesService()).thenReturn(attributesService); + when(attributesService.find(eq(tenantId), eq(deviceId), Mockito.any(AttributeScope.class), Mockito.anySet())) + .thenReturn(immediateFuture(emptyList())); + when(attributesService.find(eq(tenantId), eq(customerId), Mockito.any(AttributeScope.class), Mockito.anyString())) + .thenReturn(immediateFuture(Optional.empty())); + when(attributesService.find(eq(tenantId), eq(tenantId), Mockito.any(AttributeScope.class), Mockito.anyString())) .thenReturn(attrListListenableFuture); TbMsg theMsg = TbMsg.newMsg() @@ -554,7 +572,7 @@ public class TbDeviceProfileNodeTest extends AbstractRuleNodeUpgradeTest { AttributeKvEntry entry = attributeKvEntity.toData(); ListenableFuture> listListenableFutureWithLess = - Futures.immediateFuture(Collections.singletonList(entry)); + immediateFuture(singletonList(entry)); AlarmConditionFilter highTempFilter = new AlarmConditionFilter(); highTempFilter.setKey(new AlarmConditionFilterKey(TIME_SERIES, "temperature")); @@ -568,25 +586,25 @@ public class TbDeviceProfileNodeTest extends AbstractRuleNodeUpgradeTest { )); highTempFilter.setPredicate(highTemperaturePredicate); AlarmCondition alarmCondition = new AlarmCondition(); - alarmCondition.setCondition(Collections.singletonList(highTempFilter)); + alarmCondition.setCondition(singletonList(highTempFilter)); AlarmRule alarmRule = new AlarmRule(); alarmRule.setCondition(alarmCondition); DeviceProfileAlarm dpa = new DeviceProfileAlarm(); dpa.setId("highTemperatureAlarmID"); dpa.setAlarmType("highTemperatureAlarm"); - dpa.setCreateRules(new TreeMap<>(Collections.singletonMap(AlarmSeverity.CRITICAL, alarmRule))); + dpa.setCreateRules(new TreeMap<>(singletonMap(AlarmSeverity.CRITICAL, alarmRule))); - deviceProfileData.setAlarms(Collections.singletonList(dpa)); + deviceProfileData.setAlarms(singletonList(dpa)); deviceProfile.setProfileData(deviceProfileData); - Mockito.when(cache.get(tenantId, deviceId)).thenReturn(deviceProfile); - Mockito.when(timeseriesService.findLatest(tenantId, deviceId, Collections.singleton("temperature"))) - .thenReturn(Futures.immediateFuture(Collections.emptyList())); - Mockito.when(alarmService.findLatestActiveByOriginatorAndType(tenantId, deviceId, "highTemperatureAlarm")) + when(cache.get(tenantId, deviceId)).thenReturn(deviceProfile); + when(timeseriesService.findLatest(tenantId, deviceId, singleton("temperature"))) + .thenReturn(immediateFuture(emptyList())); + when(alarmService.findLatestActiveByOriginatorAndType(tenantId, deviceId, "highTemperatureAlarm")) .thenReturn(null); registerCreateAlarmMock(alarmService.createAlarm(any()), true); - Mockito.when(ctx.getAttributesService()).thenReturn(attributesService); - Mockito.when(attributesService.find(eq(tenantId), eq(deviceId), Mockito.any(AttributeScope.class), Mockito.anySet())) + when(ctx.getAttributesService()).thenReturn(attributesService); + when(attributesService.find(eq(tenantId), eq(deviceId), Mockito.any(AttributeScope.class), Mockito.anySet())) .thenReturn(listListenableFutureWithLess); TbMsg theMsg = TbMsg.newMsg() @@ -648,7 +666,7 @@ public class TbDeviceProfileNodeTest extends AbstractRuleNodeUpgradeTest { AttributeKvEntry alarmDelayAttributeKvEntry = alarmDelayAttributeKvEntity.toData(); ListenableFuture> listListenableFuture = - Futures.immediateFuture(Arrays.asList(entry, alarmDelayAttributeKvEntry)); + immediateFuture(Arrays.asList(entry, alarmDelayAttributeKvEntry)); AlarmConditionFilter highTempFilter = new AlarmConditionFilter(); highTempFilter.setKey(new AlarmConditionFilterKey(TIME_SERIES, "temperature")); @@ -662,7 +680,7 @@ public class TbDeviceProfileNodeTest extends AbstractRuleNodeUpgradeTest { )); highTempFilter.setPredicate(highTemperaturePredicate); AlarmCondition alarmCondition = new AlarmCondition(); - alarmCondition.setCondition(Collections.singletonList(highTempFilter)); + alarmCondition.setCondition(singletonList(highTempFilter)); FilterPredicateValue filterPredicateValue = new FilterPredicateValue<>( 10L, @@ -680,19 +698,19 @@ public class TbDeviceProfileNodeTest extends AbstractRuleNodeUpgradeTest { DeviceProfileAlarm dpa = new DeviceProfileAlarm(); dpa.setId("highTemperatureAlarmID"); dpa.setAlarmType("highTemperatureAlarm"); - dpa.setCreateRules(new TreeMap<>(Collections.singletonMap(AlarmSeverity.CRITICAL, alarmRule))); + dpa.setCreateRules(new TreeMap<>(singletonMap(AlarmSeverity.CRITICAL, alarmRule))); - deviceProfileData.setAlarms(Collections.singletonList(dpa)); + deviceProfileData.setAlarms(singletonList(dpa)); deviceProfile.setProfileData(deviceProfileData); - Mockito.when(cache.get(tenantId, deviceId)).thenReturn(deviceProfile); - Mockito.when(timeseriesService.findLatest(tenantId, deviceId, Collections.singleton("temperature"))) - .thenReturn(Futures.immediateFuture(Collections.emptyList())); - Mockito.when(alarmService.findLatestActiveByOriginatorAndType(tenantId, deviceId, "highTemperatureAlarm")) + when(cache.get(tenantId, deviceId)).thenReturn(deviceProfile); + when(timeseriesService.findLatest(tenantId, deviceId, singleton("temperature"))) + .thenReturn(immediateFuture(emptyList())); + when(alarmService.findLatestActiveByOriginatorAndType(tenantId, deviceId, "highTemperatureAlarm")) .thenReturn(null); registerCreateAlarmMock(alarmService.createAlarm(any()), true); - Mockito.when(ctx.getAttributesService()).thenReturn(attributesService); - Mockito.when(attributesService.find(eq(tenantId), eq(deviceId), Mockito.any(AttributeScope.class), Mockito.anySet())) + when(ctx.getAttributesService()).thenReturn(attributesService); + when(attributesService.find(eq(tenantId), eq(deviceId), Mockito.any(AttributeScope.class), Mockito.anySet())) .thenReturn(listListenableFuture); TbMsg theMsg = TbMsg.newMsg() @@ -740,6 +758,105 @@ public class TbDeviceProfileNodeTest extends AbstractRuleNodeUpgradeTest { verify(ctx, Mockito.never()).tellFailure(Mockito.any(), Mockito.any()); } + @Test + public void testCurrentDeviceAttributeForDynamicDurationValue_noMessagesReceivedFromDeviceBeforeAlarmHarvesting() throws Exception { + init(); + + // 1. Setup device profile that has no alarm rules + var deviceProfileData = new DeviceProfileData(); + deviceProfileData.setAlarms(emptyList()); + + var deviceProfile = new DeviceProfile(deviceProfileId); + deviceProfile.setTenantId(tenantId); + deviceProfile.setName("default"); + deviceProfile.setProfileData(deviceProfileData); + + given(cache.get(tenantId, deviceId)).willReturn(deviceProfile); + + // 2. Initialize device state by sending ENTITY_CREATED event + var device = new Device(deviceId); + device.setTenantId(tenantId); + device.setName("device"); + device.setDeviceProfileId(deviceProfileId); + device.setType("default"); + + var entityCreatedEvent = TbMsg.newMsg() + .type(TbMsgType.ENTITY_CREATED) + .originator(deviceId) + .data(JacksonUtil.toString(device)) + .metaData(TbMsgMetaData.EMPTY) + .build(); + + node.onMsg(ctx, entityCreatedEvent); + + // 3. Update device profile so it now has dynamic duration rule with value taken from current device + var predicate = new NumericFilterPredicate(); + predicate.setOperation(NumericOperation.GREATER_OR_EQUAL); + predicate.setValue(new FilterPredicateValue<>(100.0)); + + var filter = new AlarmConditionFilter(); + filter.setKey(new AlarmConditionFilterKey(AlarmConditionKeyType.TIME_SERIES, "temperature")); + filter.setValueType(EntityKeyValueType.NUMERIC); + filter.setPredicate(predicate); + + var durationSpec = new DurationAlarmConditionSpec(); + durationSpec.setUnit(TimeUnit.SECONDS); + durationSpec.setPredicate( + new FilterPredicateValue<>(10L, null, new DynamicValue<>(DynamicValueSourceType.CURRENT_DEVICE, "duration", false)) + ); + + var alarmCondition = new AlarmCondition(); + alarmCondition.setCondition(singletonList(filter)); + alarmCondition.setSpec(durationSpec); + + var alarmRule = new AlarmRule(); + alarmRule.setCondition(alarmCondition); + + var dpa = new DeviceProfileAlarm(); + dpa.setId("c4486528-84f2-bd72-589e-2f9a60f89c17"); + dpa.setAlarmType("Test alarm"); + dpa.setCreateRules(new TreeMap<>(singletonMap(AlarmSeverity.CRITICAL, alarmRule))); + + deviceProfileData.setAlarms(singletonList(dpa)); + + // 4. Mock DB calls for keys used in alarm rule + given(timeseriesService.findLatest(tenantId, deviceId, singleton("temperature"))).willReturn(immediateFuture( + List.of(new BasicTsKvEntry(123L, new DoubleDataEntry("temperature", 55.6))) + )); + + given(attributesService.find(tenantId, deviceId, AttributeScope.CLIENT_SCOPE, singleton("duration"))).willReturn(immediateFuture(emptyList())); + given(attributesService.find(tenantId, deviceId, AttributeScope.SHARED_SCOPE, singleton("duration"))).willReturn(immediateFuture(emptyList())); + given(attributesService.find(tenantId, deviceId, AttributeScope.SERVER_SCOPE, singleton("duration"))).willReturn(immediateFuture( + List.of(new BaseAttributeKvEntry(123L, new LongDataEntry("duration", 20L))) + )); + + // 5. Send DEVICE_PROFILE_UPDATE_SELF_MSG so alarm state (inside device state) gets initialized + given(cache.get(tenantId, deviceProfileId)).willReturn(deviceProfile); + + var deviceProfileUpdateMsg = TbMsg.newMsg() + .originator(tenantId) + .type(TbMsgType.DEVICE_PROFILE_UPDATE_SELF_MSG) + .data(deviceProfileId.toString()) + .metaData(TbMsgMetaData.EMPTY) + .build(); + + node.onMsg(ctx, deviceProfileUpdateMsg); + + // 6. Not sending anything else to simulate no activity + + // 7. Simulate periodic alarm harvesting by manually sending DEVICE_PROFILE_PERIODIC_SELF_MSG message + var periodicCheck = TbMsg.newMsg() + .type(TbMsgType.DEVICE_PROFILE_PERIODIC_SELF_MSG) + .originator(tenantId) + .customerId(customerId) + .metaData(TbMsgMetaData.EMPTY) + .data(TbMsg.EMPTY_JSON_OBJECT) + .build(); + + // NPE should NOT happen here: dynamic value of duration condition should be correctly resolved + assertThatNoException().isThrownBy(() -> node.onMsg(ctx, periodicCheck)); + } + @Test public void testInheritTenantAttributeForDuration() throws Exception { init(); @@ -779,11 +896,11 @@ public class TbDeviceProfileNodeTest extends AbstractRuleNodeUpgradeTest { AttributeKvEntry alarmDelayAttributeKvEntry = alarmDelayAttributeKvEntity.toData(); ListenableFuture> optionalDurationAttribute = - Futures.immediateFuture(Optional.of(alarmDelayAttributeKvEntry)); + immediateFuture(Optional.of(alarmDelayAttributeKvEntry)); ListenableFuture> listNoDurationAttribute = - Futures.immediateFuture(Collections.singletonList(entry)); + immediateFuture(singletonList(entry)); ListenableFuture> emptyOptional = - Futures.immediateFuture(Optional.empty()); + immediateFuture(Optional.empty()); AlarmConditionFilter highTempFilter = new AlarmConditionFilter(); highTempFilter.setKey(new AlarmConditionFilterKey(TIME_SERIES, "temperature")); @@ -797,7 +914,7 @@ public class TbDeviceProfileNodeTest extends AbstractRuleNodeUpgradeTest { )); highTempFilter.setPredicate(highTemperaturePredicate); AlarmCondition alarmCondition = new AlarmCondition(); - alarmCondition.setCondition(Collections.singletonList(highTempFilter)); + alarmCondition.setCondition(singletonList(highTempFilter)); FilterPredicateValue filterPredicateValue = new FilterPredicateValue<>( 10L, @@ -815,25 +932,25 @@ public class TbDeviceProfileNodeTest extends AbstractRuleNodeUpgradeTest { DeviceProfileAlarm dpa = new DeviceProfileAlarm(); dpa.setId("highTemperatureAlarmID"); dpa.setAlarmType("highTemperatureAlarm"); - dpa.setCreateRules(new TreeMap<>(Collections.singletonMap(AlarmSeverity.CRITICAL, alarmRule))); + dpa.setCreateRules(new TreeMap<>(singletonMap(AlarmSeverity.CRITICAL, alarmRule))); - deviceProfileData.setAlarms(Collections.singletonList(dpa)); + deviceProfileData.setAlarms(singletonList(dpa)); deviceProfile.setProfileData(deviceProfileData); - Mockito.when(cache.get(tenantId, deviceId)).thenReturn(deviceProfile); - Mockito.when(timeseriesService.findLatest(tenantId, deviceId, Collections.singleton("temperature"))) - .thenReturn(Futures.immediateFuture(Collections.emptyList())); - Mockito.when(alarmService.findLatestActiveByOriginatorAndType(tenantId, deviceId, "highTemperatureAlarm")) + when(cache.get(tenantId, deviceId)).thenReturn(deviceProfile); + when(timeseriesService.findLatest(tenantId, deviceId, singleton("temperature"))) + .thenReturn(immediateFuture(emptyList())); + when(alarmService.findLatestActiveByOriginatorAndType(tenantId, deviceId, "highTemperatureAlarm")) .thenReturn(null); registerCreateAlarmMock(alarmService.createAlarm(any()), true); - Mockito.when(ctx.getAttributesService()).thenReturn(attributesService); - Mockito.when(attributesService.find(eq(tenantId), eq(tenantId), Mockito.any(AttributeScope.class), Mockito.anyString())) + when(ctx.getAttributesService()).thenReturn(attributesService); + when(attributesService.find(eq(tenantId), eq(tenantId), Mockito.any(AttributeScope.class), Mockito.anyString())) .thenReturn(optionalDurationAttribute); - Mockito.when(ctx.getDeviceService().findDeviceById(tenantId, deviceId)) + when(ctx.getDeviceService().findDeviceById(tenantId, deviceId)) .thenReturn(device); - Mockito.when(attributesService.find(eq(tenantId), eq(customerId), eq(AttributeScope.SERVER_SCOPE), Mockito.anyString())) + when(attributesService.find(eq(tenantId), eq(customerId), eq(AttributeScope.SERVER_SCOPE), Mockito.anyString())) .thenReturn(emptyOptional); - Mockito.when(attributesService.find(eq(tenantId), eq(deviceId), Mockito.any(AttributeScope.class), Mockito.anySet())) + when(attributesService.find(eq(tenantId), eq(deviceId), Mockito.any(AttributeScope.class), Mockito.anySet())) .thenReturn(listNoDurationAttribute); TbMsg theMsg = TbMsg.newMsg() @@ -915,7 +1032,7 @@ public class TbDeviceProfileNodeTest extends AbstractRuleNodeUpgradeTest { AttributeKvEntry alarmDelayAttributeKvEntry = alarmDelayAttributeKvEntity.toData(); ListenableFuture> listListenableFuture = - Futures.immediateFuture(Arrays.asList(entry, alarmDelayAttributeKvEntry)); + immediateFuture(Arrays.asList(entry, alarmDelayAttributeKvEntry)); AlarmConditionFilter highTempFilter = new AlarmConditionFilter(); highTempFilter.setKey(new AlarmConditionFilterKey(TIME_SERIES, "temperature")); @@ -929,7 +1046,7 @@ public class TbDeviceProfileNodeTest extends AbstractRuleNodeUpgradeTest { )); highTempFilter.setPredicate(highTemperaturePredicate); AlarmCondition alarmCondition = new AlarmCondition(); - alarmCondition.setCondition(Collections.singletonList(highTempFilter)); + alarmCondition.setCondition(singletonList(highTempFilter)); FilterPredicateValue filterPredicateValue = new FilterPredicateValue<>( 10, @@ -947,19 +1064,19 @@ public class TbDeviceProfileNodeTest extends AbstractRuleNodeUpgradeTest { DeviceProfileAlarm dpa = new DeviceProfileAlarm(); dpa.setId("highTemperatureAlarmID"); dpa.setAlarmType("highTemperatureAlarm"); - dpa.setCreateRules(new TreeMap<>(Collections.singletonMap(AlarmSeverity.CRITICAL, alarmRule))); + dpa.setCreateRules(new TreeMap<>(singletonMap(AlarmSeverity.CRITICAL, alarmRule))); - deviceProfileData.setAlarms(Collections.singletonList(dpa)); + deviceProfileData.setAlarms(singletonList(dpa)); deviceProfile.setProfileData(deviceProfileData); - Mockito.when(cache.get(tenantId, deviceId)).thenReturn(deviceProfile); - Mockito.when(timeseriesService.findLatest(tenantId, deviceId, Collections.singleton("temperature"))) - .thenReturn(Futures.immediateFuture(Collections.emptyList())); - Mockito.when(alarmService.findLatestActiveByOriginatorAndType(tenantId, deviceId, "highTemperatureAlarm")) + when(cache.get(tenantId, deviceId)).thenReturn(deviceProfile); + when(timeseriesService.findLatest(tenantId, deviceId, singleton("temperature"))) + .thenReturn(immediateFuture(emptyList())); + when(alarmService.findLatestActiveByOriginatorAndType(tenantId, deviceId, "highTemperatureAlarm")) .thenReturn(null); registerCreateAlarmMock(alarmService.createAlarm(any()), true); - Mockito.when(ctx.getAttributesService()).thenReturn(attributesService); - Mockito.when(attributesService.find(eq(tenantId), eq(deviceId), Mockito.any(AttributeScope.class), Mockito.anySet())) + when(ctx.getAttributesService()).thenReturn(attributesService); + when(attributesService.find(eq(tenantId), eq(deviceId), Mockito.any(AttributeScope.class), Mockito.anySet())) .thenReturn(listListenableFuture); TbMsg theMsg = TbMsg.newMsg() @@ -1039,11 +1156,11 @@ public class TbDeviceProfileNodeTest extends AbstractRuleNodeUpgradeTest { AttributeKvEntry alarmDelayAttributeKvEntry = alarmDelayAttributeKvEntity.toData(); ListenableFuture> optionalDurationAttribute = - Futures.immediateFuture(Optional.of(alarmDelayAttributeKvEntry)); + immediateFuture(Optional.of(alarmDelayAttributeKvEntry)); ListenableFuture> listNoDurationAttribute = - Futures.immediateFuture(Collections.singletonList(entry)); + immediateFuture(singletonList(entry)); ListenableFuture> emptyOptional = - Futures.immediateFuture(Optional.empty()); + immediateFuture(Optional.empty()); AlarmConditionFilter highTempFilter = new AlarmConditionFilter(); highTempFilter.setKey(new AlarmConditionFilterKey(TIME_SERIES, "temperature")); @@ -1057,7 +1174,7 @@ public class TbDeviceProfileNodeTest extends AbstractRuleNodeUpgradeTest { )); highTempFilter.setPredicate(highTemperaturePredicate); AlarmCondition alarmCondition = new AlarmCondition(); - alarmCondition.setCondition(Collections.singletonList(highTempFilter)); + alarmCondition.setCondition(singletonList(highTempFilter)); FilterPredicateValue filterPredicateValue = new FilterPredicateValue<>( 10, @@ -1074,25 +1191,25 @@ public class TbDeviceProfileNodeTest extends AbstractRuleNodeUpgradeTest { DeviceProfileAlarm dpa = new DeviceProfileAlarm(); dpa.setId("highTemperatureAlarmID"); dpa.setAlarmType("highTemperatureAlarm"); - dpa.setCreateRules(new TreeMap<>(Collections.singletonMap(AlarmSeverity.CRITICAL, alarmRule))); + dpa.setCreateRules(new TreeMap<>(singletonMap(AlarmSeverity.CRITICAL, alarmRule))); - deviceProfileData.setAlarms(Collections.singletonList(dpa)); + deviceProfileData.setAlarms(singletonList(dpa)); deviceProfile.setProfileData(deviceProfileData); - Mockito.when(cache.get(tenantId, deviceId)).thenReturn(deviceProfile); - Mockito.when(timeseriesService.findLatest(tenantId, deviceId, Collections.singleton("temperature"))) - .thenReturn(Futures.immediateFuture(Collections.emptyList())); - Mockito.when(alarmService.findLatestActiveByOriginatorAndType(tenantId, deviceId, "highTemperatureAlarm")) + when(cache.get(tenantId, deviceId)).thenReturn(deviceProfile); + when(timeseriesService.findLatest(tenantId, deviceId, singleton("temperature"))) + .thenReturn(immediateFuture(emptyList())); + when(alarmService.findLatestActiveByOriginatorAndType(tenantId, deviceId, "highTemperatureAlarm")) .thenReturn(null); registerCreateAlarmMock(alarmService.createAlarm(any()), true); - Mockito.when(ctx.getAttributesService()).thenReturn(attributesService); - Mockito.when(attributesService.find(eq(tenantId), eq(tenantId), Mockito.any(AttributeScope.class), Mockito.anyString())) + when(ctx.getAttributesService()).thenReturn(attributesService); + when(attributesService.find(eq(tenantId), eq(tenantId), Mockito.any(AttributeScope.class), Mockito.anyString())) .thenReturn(optionalDurationAttribute); - Mockito.when(ctx.getDeviceService().findDeviceById(tenantId, deviceId)) + when(ctx.getDeviceService().findDeviceById(tenantId, deviceId)) .thenReturn(device); - Mockito.when(attributesService.find(eq(tenantId), eq(customerId), eq(AttributeScope.SERVER_SCOPE), Mockito.anyString())) + when(attributesService.find(eq(tenantId), eq(customerId), eq(AttributeScope.SERVER_SCOPE), Mockito.anyString())) .thenReturn(emptyOptional); - Mockito.when(attributesService.find(eq(tenantId), eq(deviceId), Mockito.any(AttributeScope.class), Mockito.anySet())) + when(attributesService.find(eq(tenantId), eq(deviceId), Mockito.any(AttributeScope.class), Mockito.anySet())) .thenReturn(listNoDurationAttribute); TbMsg theMsg = TbMsg.newMsg() @@ -1160,7 +1277,7 @@ public class TbDeviceProfileNodeTest extends AbstractRuleNodeUpgradeTest { AttributeKvEntry entry = attributeKvEntity.toData(); ListenableFuture> listListenableFuture = - Futures.immediateFuture(Collections.singletonList(entry)); + immediateFuture(singletonList(entry)); AlarmConditionFilter highTempFilter = new AlarmConditionFilter(); highTempFilter.setKey(new AlarmConditionFilterKey(TIME_SERIES, "temperature")); @@ -1174,7 +1291,7 @@ public class TbDeviceProfileNodeTest extends AbstractRuleNodeUpgradeTest { )); highTempFilter.setPredicate(highTemperaturePredicate); AlarmCondition alarmCondition = new AlarmCondition(); - alarmCondition.setCondition(Collections.singletonList(highTempFilter)); + alarmCondition.setCondition(singletonList(highTempFilter)); FilterPredicateValue filterPredicateValue = new FilterPredicateValue<>( alarmDelayInSeconds, @@ -1192,19 +1309,19 @@ public class TbDeviceProfileNodeTest extends AbstractRuleNodeUpgradeTest { DeviceProfileAlarm dpa = new DeviceProfileAlarm(); dpa.setId("highTemperatureAlarmID"); dpa.setAlarmType("highTemperatureAlarm"); - dpa.setCreateRules(new TreeMap<>(Collections.singletonMap(AlarmSeverity.CRITICAL, alarmRule))); + dpa.setCreateRules(new TreeMap<>(singletonMap(AlarmSeverity.CRITICAL, alarmRule))); - deviceProfileData.setAlarms(Collections.singletonList(dpa)); + deviceProfileData.setAlarms(singletonList(dpa)); deviceProfile.setProfileData(deviceProfileData); - Mockito.when(cache.get(tenantId, deviceId)).thenReturn(deviceProfile); - Mockito.when(timeseriesService.findLatest(tenantId, deviceId, Collections.singleton("temperature"))) - .thenReturn(Futures.immediateFuture(Collections.emptyList())); - Mockito.when(alarmService.findLatestActiveByOriginatorAndType(tenantId, deviceId, "highTemperatureAlarm")) + when(cache.get(tenantId, deviceId)).thenReturn(deviceProfile); + when(timeseriesService.findLatest(tenantId, deviceId, singleton("temperature"))) + .thenReturn(immediateFuture(emptyList())); + when(alarmService.findLatestActiveByOriginatorAndType(tenantId, deviceId, "highTemperatureAlarm")) .thenReturn(null); registerCreateAlarmMock(alarmService.createAlarm(any()), true); - Mockito.when(ctx.getAttributesService()).thenReturn(attributesService); - Mockito.when(attributesService.find(eq(tenantId), eq(deviceId), Mockito.any(AttributeScope.class), Mockito.anySet())) + when(ctx.getAttributesService()).thenReturn(attributesService); + when(attributesService.find(eq(tenantId), eq(deviceId), Mockito.any(AttributeScope.class), Mockito.anySet())) .thenReturn(listListenableFuture); TbMsg theMsg = TbMsg.newMsg() @@ -1277,7 +1394,7 @@ public class TbDeviceProfileNodeTest extends AbstractRuleNodeUpgradeTest { AttributeKvEntry entry = attributeKvEntity.toData(); ListenableFuture> listListenableFuture = - Futures.immediateFuture(Collections.singletonList(entry)); + immediateFuture(singletonList(entry)); AlarmConditionFilter highTempFilter = new AlarmConditionFilter(); highTempFilter.setKey(new AlarmConditionFilterKey(TIME_SERIES, "temperature")); @@ -1291,7 +1408,7 @@ public class TbDeviceProfileNodeTest extends AbstractRuleNodeUpgradeTest { )); highTempFilter.setPredicate(highTemperaturePredicate); AlarmCondition alarmCondition = new AlarmCondition(); - alarmCondition.setCondition(Collections.singletonList(highTempFilter)); + alarmCondition.setCondition(singletonList(highTempFilter)); RepeatingAlarmConditionSpec repeating = new RepeatingAlarmConditionSpec(); repeating.setPredicate(new FilterPredicateValue<>( @@ -1306,19 +1423,19 @@ public class TbDeviceProfileNodeTest extends AbstractRuleNodeUpgradeTest { DeviceProfileAlarm dpa = new DeviceProfileAlarm(); dpa.setId("highTemperatureAlarmID"); dpa.setAlarmType("highTemperatureAlarm"); - dpa.setCreateRules(new TreeMap<>(Collections.singletonMap(AlarmSeverity.CRITICAL, alarmRule))); + dpa.setCreateRules(new TreeMap<>(singletonMap(AlarmSeverity.CRITICAL, alarmRule))); - deviceProfileData.setAlarms(Collections.singletonList(dpa)); + deviceProfileData.setAlarms(singletonList(dpa)); deviceProfile.setProfileData(deviceProfileData); - Mockito.when(cache.get(tenantId, deviceId)).thenReturn(deviceProfile); - Mockito.when(timeseriesService.findLatest(tenantId, deviceId, Collections.singleton("temperature"))) - .thenReturn(Futures.immediateFuture(Collections.emptyList())); - Mockito.when(alarmService.findLatestActiveByOriginatorAndType(tenantId, deviceId, "highTemperatureAlarm")) + when(cache.get(tenantId, deviceId)).thenReturn(deviceProfile); + when(timeseriesService.findLatest(tenantId, deviceId, singleton("temperature"))) + .thenReturn(immediateFuture(emptyList())); + when(alarmService.findLatestActiveByOriginatorAndType(tenantId, deviceId, "highTemperatureAlarm")) .thenReturn(null); registerCreateAlarmMock(alarmService.createAlarm(any()), true); - Mockito.when(ctx.getAttributesService()).thenReturn(attributesService); - Mockito.when(attributesService.find(eq(tenantId), eq(deviceId), Mockito.any(AttributeScope.class), Mockito.anySet())) + when(ctx.getAttributesService()).thenReturn(attributesService); + when(attributesService.find(eq(tenantId), eq(deviceId), Mockito.any(AttributeScope.class), Mockito.anySet())) .thenReturn(listListenableFuture); TbMsg theMsg = TbMsg.newMsg() @@ -1373,7 +1490,7 @@ public class TbDeviceProfileNodeTest extends AbstractRuleNodeUpgradeTest { AttributeKvEntry entryActiveSchedule = attributeKvEntityActiveSchedule.toData(); ListenableFuture> listListenableFutureActiveSchedule = - Futures.immediateFuture(Collections.singletonList(entryActiveSchedule)); + immediateFuture(singletonList(entryActiveSchedule)); AlarmConditionFilter highTempFilter = new AlarmConditionFilter(); highTempFilter.setKey(new AlarmConditionFilterKey(TIME_SERIES, "temperature")); @@ -1387,10 +1504,10 @@ public class TbDeviceProfileNodeTest extends AbstractRuleNodeUpgradeTest { )); highTempFilter.setPredicate(highTemperaturePredicate); AlarmCondition alarmCondition = new AlarmCondition(); - alarmCondition.setCondition(Collections.singletonList(highTempFilter)); + alarmCondition.setCondition(singletonList(highTempFilter)); CustomTimeSchedule schedule = new CustomTimeSchedule(); - schedule.setItems(Collections.emptyList()); + schedule.setItems(emptyList()); schedule.setDynamicValue(new DynamicValue<>(DynamicValueSourceType.CURRENT_DEVICE, "dynamicValueActiveSchedule", false)); AlarmRule alarmRule = new AlarmRule(); @@ -1399,19 +1516,19 @@ public class TbDeviceProfileNodeTest extends AbstractRuleNodeUpgradeTest { DeviceProfileAlarm deviceProfileAlarmActiveSchedule = new DeviceProfileAlarm(); deviceProfileAlarmActiveSchedule.setId("highTemperatureAlarmID"); deviceProfileAlarmActiveSchedule.setAlarmType("highTemperatureAlarm"); - deviceProfileAlarmActiveSchedule.setCreateRules(new TreeMap<>(Collections.singletonMap(AlarmSeverity.CRITICAL, alarmRule))); + deviceProfileAlarmActiveSchedule.setCreateRules(new TreeMap<>(singletonMap(AlarmSeverity.CRITICAL, alarmRule))); - deviceProfileData.setAlarms(Collections.singletonList(deviceProfileAlarmActiveSchedule)); + deviceProfileData.setAlarms(singletonList(deviceProfileAlarmActiveSchedule)); deviceProfile.setProfileData(deviceProfileData); - Mockito.when(cache.get(tenantId, deviceId)).thenReturn(deviceProfile); - Mockito.when(timeseriesService.findLatest(tenantId, deviceId, Collections.singleton("temperature"))) - .thenReturn(Futures.immediateFuture(Collections.emptyList())); - Mockito.when(alarmService.findLatestActiveByOriginatorAndType(tenantId, deviceId, "highTemperatureAlarm")) + when(cache.get(tenantId, deviceId)).thenReturn(deviceProfile); + when(timeseriesService.findLatest(tenantId, deviceId, singleton("temperature"))) + .thenReturn(immediateFuture(emptyList())); + when(alarmService.findLatestActiveByOriginatorAndType(tenantId, deviceId, "highTemperatureAlarm")) .thenReturn(null); registerCreateAlarmMock(alarmService.createAlarm(any()), true); - Mockito.when(ctx.getAttributesService()).thenReturn(attributesService); - Mockito.when(attributesService.find(eq(tenantId), eq(deviceId), Mockito.any(AttributeScope.class), Mockito.anySet())) + when(ctx.getAttributesService()).thenReturn(attributesService); + when(attributesService.find(eq(tenantId), eq(deviceId), Mockito.any(AttributeScope.class), Mockito.anySet())) .thenReturn(listListenableFutureActiveSchedule); TbMsg theMsg = TbMsg.newMsg() @@ -1470,7 +1587,7 @@ public class TbDeviceProfileNodeTest extends AbstractRuleNodeUpgradeTest { AttributeKvEntry entryInactiveSchedule = attributeKvEntityInactiveSchedule.toData(); ListenableFuture> listListenableFutureInactiveSchedule = - Futures.immediateFuture(Collections.singletonList(entryInactiveSchedule)); + immediateFuture(singletonList(entryInactiveSchedule)); AlarmConditionFilter highTempFilter = new AlarmConditionFilter(); highTempFilter.setKey(new AlarmConditionFilterKey(TIME_SERIES, "temperature")); @@ -1485,7 +1602,7 @@ public class TbDeviceProfileNodeTest extends AbstractRuleNodeUpgradeTest { highTempFilter.setPredicate(highTemperaturePredicate); AlarmCondition alarmCondition = new AlarmCondition(); - alarmCondition.setCondition(Collections.singletonList(highTempFilter)); + alarmCondition.setCondition(singletonList(highTempFilter)); CustomTimeSchedule schedule = new CustomTimeSchedule(); @@ -1508,18 +1625,18 @@ public class TbDeviceProfileNodeTest extends AbstractRuleNodeUpgradeTest { DeviceProfileAlarm deviceProfileAlarmNonactiveSchedule = new DeviceProfileAlarm(); deviceProfileAlarmNonactiveSchedule.setId("highTemperatureAlarmID"); deviceProfileAlarmNonactiveSchedule.setAlarmType("highTemperatureAlarm"); - deviceProfileAlarmNonactiveSchedule.setCreateRules(new TreeMap<>(Collections.singletonMap(AlarmSeverity.CRITICAL, alarmRule))); + deviceProfileAlarmNonactiveSchedule.setCreateRules(new TreeMap<>(singletonMap(AlarmSeverity.CRITICAL, alarmRule))); - deviceProfileData.setAlarms(Collections.singletonList(deviceProfileAlarmNonactiveSchedule)); + deviceProfileData.setAlarms(singletonList(deviceProfileAlarmNonactiveSchedule)); deviceProfile.setProfileData(deviceProfileData); - Mockito.when(cache.get(tenantId, deviceId)).thenReturn(deviceProfile); - Mockito.when(timeseriesService.findLatest(tenantId, deviceId, Collections.singleton("temperature"))) - .thenReturn(Futures.immediateFuture(Collections.emptyList())); - Mockito.when(alarmService.findLatestActiveByOriginatorAndType(tenantId, deviceId, "highTemperatureAlarm")) + when(cache.get(tenantId, deviceId)).thenReturn(deviceProfile); + when(timeseriesService.findLatest(tenantId, deviceId, singleton("temperature"))) + .thenReturn(immediateFuture(emptyList())); + when(alarmService.findLatestActiveByOriginatorAndType(tenantId, deviceId, "highTemperatureAlarm")) .thenReturn(null); - Mockito.when(ctx.getAttributesService()).thenReturn(attributesService); - Mockito.when(attributesService.find(eq(tenantId), eq(deviceId), Mockito.any(AttributeScope.class), Mockito.anySet())) + when(ctx.getAttributesService()).thenReturn(attributesService); + when(attributesService.find(eq(tenantId), eq(deviceId), Mockito.any(AttributeScope.class), Mockito.anySet())) .thenReturn(listListenableFutureInactiveSchedule); TbMsg theMsg = TbMsg.newMsg() @@ -1569,9 +1686,9 @@ public class TbDeviceProfileNodeTest extends AbstractRuleNodeUpgradeTest { AttributeKvEntry entry = attributeKvEntity.toData(); ListenableFuture> listListenableFutureWithLess = - Futures.immediateFuture(Collections.emptyList()); + immediateFuture(emptyList()); ListenableFuture> optionalListenableFutureWithLess = - Futures.immediateFuture(Optional.of(entry)); + immediateFuture(Optional.of(entry)); AlarmConditionFilter lowTempFilter = new AlarmConditionFilter(); lowTempFilter.setKey(new AlarmConditionFilterKey(TIME_SERIES, "temperature")); @@ -1586,29 +1703,29 @@ public class TbDeviceProfileNodeTest extends AbstractRuleNodeUpgradeTest { ); lowTempFilter.setPredicate(lowTempPredicate); AlarmCondition alarmCondition = new AlarmCondition(); - alarmCondition.setCondition(Collections.singletonList(lowTempFilter)); + alarmCondition.setCondition(singletonList(lowTempFilter)); AlarmRule alarmRule = new AlarmRule(); alarmRule.setCondition(alarmCondition); DeviceProfileAlarm dpa = new DeviceProfileAlarm(); dpa.setId("lesstempID"); dpa.setAlarmType("lessTemperatureAlarm"); - dpa.setCreateRules(new TreeMap<>(Collections.singletonMap(AlarmSeverity.CRITICAL, alarmRule))); + dpa.setCreateRules(new TreeMap<>(singletonMap(AlarmSeverity.CRITICAL, alarmRule))); - deviceProfileData.setAlarms(Collections.singletonList(dpa)); + deviceProfileData.setAlarms(singletonList(dpa)); deviceProfile.setProfileData(deviceProfileData); - Mockito.when(cache.get(tenantId, deviceId)).thenReturn(deviceProfile); - Mockito.when(timeseriesService.findLatest(tenantId, deviceId, Collections.singleton("temperature"))) - .thenReturn(Futures.immediateFuture(Collections.emptyList())); - Mockito.when(alarmService.findLatestActiveByOriginatorAndType(tenantId, deviceId, "lessTemperatureAlarm")) + when(cache.get(tenantId, deviceId)).thenReturn(deviceProfile); + when(timeseriesService.findLatest(tenantId, deviceId, singleton("temperature"))) + .thenReturn(immediateFuture(emptyList())); + when(alarmService.findLatestActiveByOriginatorAndType(tenantId, deviceId, "lessTemperatureAlarm")) .thenReturn(null); registerCreateAlarmMock(alarmService.createAlarm(any()), true); - Mockito.when(ctx.getAttributesService()).thenReturn(attributesService); - Mockito.when(attributesService.find(eq(tenantId), eq(deviceId), Mockito.any(AttributeScope.class), Mockito.anySet())) + when(ctx.getAttributesService()).thenReturn(attributesService); + when(attributesService.find(eq(tenantId), eq(deviceId), Mockito.any(AttributeScope.class), Mockito.anySet())) .thenReturn(listListenableFutureWithLess); - Mockito.when(ctx.getDeviceService().findDeviceById(tenantId, deviceId)) + when(ctx.getDeviceService().findDeviceById(tenantId, deviceId)) .thenReturn(device); - Mockito.when(attributesService.find(eq(tenantId), eq(customerId), eq(AttributeScope.SERVER_SCOPE), Mockito.anyString())) + when(attributesService.find(eq(tenantId), eq(customerId), eq(AttributeScope.SERVER_SCOPE), Mockito.anyString())) .thenReturn(optionalListenableFutureWithLess); TbMsg theMsg = TbMsg.newMsg() @@ -1655,9 +1772,9 @@ public class TbDeviceProfileNodeTest extends AbstractRuleNodeUpgradeTest { AttributeKvEntry entry = attributeKvEntity.toData(); ListenableFuture> listListenableFutureWithLess = - Futures.immediateFuture(Collections.emptyList()); + immediateFuture(emptyList()); ListenableFuture> optionalListenableFutureWithLess = - Futures.immediateFuture(Optional.of(entry)); + immediateFuture(Optional.of(entry)); AlarmConditionFilter lowTempFilter = new AlarmConditionFilter(); lowTempFilter.setKey(new AlarmConditionFilterKey(TIME_SERIES, "temperature")); @@ -1672,27 +1789,27 @@ public class TbDeviceProfileNodeTest extends AbstractRuleNodeUpgradeTest { ); lowTempFilter.setPredicate(lowTempPredicate); AlarmCondition alarmCondition = new AlarmCondition(); - alarmCondition.setCondition(Collections.singletonList(lowTempFilter)); + alarmCondition.setCondition(singletonList(lowTempFilter)); AlarmRule alarmRule = new AlarmRule(); alarmRule.setCondition(alarmCondition); DeviceProfileAlarm dpa = new DeviceProfileAlarm(); dpa.setId("lesstempID"); dpa.setAlarmType("lessTemperatureAlarm"); - dpa.setCreateRules(new TreeMap<>(Collections.singletonMap(AlarmSeverity.CRITICAL, alarmRule))); + dpa.setCreateRules(new TreeMap<>(singletonMap(AlarmSeverity.CRITICAL, alarmRule))); - deviceProfileData.setAlarms(Collections.singletonList(dpa)); + deviceProfileData.setAlarms(singletonList(dpa)); deviceProfile.setProfileData(deviceProfileData); - Mockito.when(cache.get(tenantId, deviceId)).thenReturn(deviceProfile); - Mockito.when(timeseriesService.findLatest(tenantId, deviceId, Collections.singleton("temperature"))) - .thenReturn(Futures.immediateFuture(Collections.emptyList())); - Mockito.when(alarmService.findLatestActiveByOriginatorAndType(tenantId, deviceId, "lessTemperatureAlarm")) + when(cache.get(tenantId, deviceId)).thenReturn(deviceProfile); + when(timeseriesService.findLatest(tenantId, deviceId, singleton("temperature"))) + .thenReturn(immediateFuture(emptyList())); + when(alarmService.findLatestActiveByOriginatorAndType(tenantId, deviceId, "lessTemperatureAlarm")) .thenReturn(null); registerCreateAlarmMock(alarmService.createAlarm(any()), true); - Mockito.when(ctx.getAttributesService()).thenReturn(attributesService); - Mockito.when(attributesService.find(eq(tenantId), eq(deviceId), Mockito.any(AttributeScope.class), Mockito.anySet())) + when(ctx.getAttributesService()).thenReturn(attributesService); + when(attributesService.find(eq(tenantId), eq(deviceId), Mockito.any(AttributeScope.class), Mockito.anySet())) .thenReturn(listListenableFutureWithLess); - Mockito.when(attributesService.find(eq(tenantId), eq(tenantId), eq(AttributeScope.SERVER_SCOPE), Mockito.anyString())) + when(attributesService.find(eq(tenantId), eq(tenantId), eq(AttributeScope.SERVER_SCOPE), Mockito.anyString())) .thenReturn(optionalListenableFutureWithLess); TbMsg theMsg = TbMsg.newMsg() @@ -1743,11 +1860,11 @@ public class TbDeviceProfileNodeTest extends AbstractRuleNodeUpgradeTest { AttributeKvEntry entry = attributeKvEntity.toData(); ListenableFuture> listListenableFutureWithLess = - Futures.immediateFuture(Collections.emptyList()); + immediateFuture(emptyList()); ListenableFuture> emptyOptionalFuture = - Futures.immediateFuture(Optional.empty()); + immediateFuture(Optional.empty()); ListenableFuture> optionalListenableFutureWithLess = - Futures.immediateFuture(Optional.of(entry)); + immediateFuture(Optional.of(entry)); AlarmConditionFilter lowTempFilter = new AlarmConditionFilter(); lowTempFilter.setKey(new AlarmConditionFilterKey(TIME_SERIES, "temperature")); @@ -1762,31 +1879,31 @@ public class TbDeviceProfileNodeTest extends AbstractRuleNodeUpgradeTest { ); lowTempFilter.setPredicate(lowTempPredicate); AlarmCondition alarmCondition = new AlarmCondition(); - alarmCondition.setCondition(Collections.singletonList(lowTempFilter)); + alarmCondition.setCondition(singletonList(lowTempFilter)); AlarmRule alarmRule = new AlarmRule(); alarmRule.setCondition(alarmCondition); DeviceProfileAlarm dpa = new DeviceProfileAlarm(); dpa.setId("lesstempID"); dpa.setAlarmType("lessTemperatureAlarm"); - dpa.setCreateRules(new TreeMap<>(Collections.singletonMap(AlarmSeverity.CRITICAL, alarmRule))); + dpa.setCreateRules(new TreeMap<>(singletonMap(AlarmSeverity.CRITICAL, alarmRule))); - deviceProfileData.setAlarms(Collections.singletonList(dpa)); + deviceProfileData.setAlarms(singletonList(dpa)); deviceProfile.setProfileData(deviceProfileData); - Mockito.when(cache.get(tenantId, deviceId)).thenReturn(deviceProfile); - Mockito.when(timeseriesService.findLatest(tenantId, deviceId, Collections.singleton("temperature"))) - .thenReturn(Futures.immediateFuture(Collections.emptyList())); - Mockito.when(alarmService.findLatestActiveByOriginatorAndType(tenantId, deviceId, "lessTemperatureAlarm")) + when(cache.get(tenantId, deviceId)).thenReturn(deviceProfile); + when(timeseriesService.findLatest(tenantId, deviceId, singleton("temperature"))) + .thenReturn(immediateFuture(emptyList())); + when(alarmService.findLatestActiveByOriginatorAndType(tenantId, deviceId, "lessTemperatureAlarm")) .thenReturn(null); registerCreateAlarmMock(alarmService.createAlarm(any()), true); - Mockito.when(ctx.getAttributesService()).thenReturn(attributesService); - Mockito.when(ctx.getDeviceService().findDeviceById(tenantId, deviceId)) + when(ctx.getAttributesService()).thenReturn(attributesService); + when(ctx.getDeviceService().findDeviceById(tenantId, deviceId)) .thenReturn(device); - Mockito.when(attributesService.find(eq(tenantId), eq(deviceId), Mockito.any(AttributeScope.class), Mockito.anySet())) + when(attributesService.find(eq(tenantId), eq(deviceId), Mockito.any(AttributeScope.class), Mockito.anySet())) .thenReturn(listListenableFutureWithLess); - Mockito.when(attributesService.find(eq(tenantId), eq(customerId), Mockito.any(AttributeScope.class), Mockito.anyString())) + when(attributesService.find(eq(tenantId), eq(customerId), Mockito.any(AttributeScope.class), Mockito.anyString())) .thenReturn(emptyOptionalFuture); - Mockito.when(attributesService.find(eq(tenantId), eq(tenantId), eq(AttributeScope.SERVER_SCOPE), Mockito.anyString())) + when(attributesService.find(eq(tenantId), eq(tenantId), eq(AttributeScope.SERVER_SCOPE), Mockito.anyString())) .thenReturn(optionalListenableFutureWithLess); TbMsg theMsg = TbMsg.newMsg() @@ -1839,11 +1956,11 @@ public class TbDeviceProfileNodeTest extends AbstractRuleNodeUpgradeTest { AttributeKvEntry entry = attributeKvEntity.toData(); ListenableFuture> listListenableFutureWithLess = - Futures.immediateFuture(Collections.emptyList()); + immediateFuture(emptyList()); ListenableFuture> emptyOptionalFuture = - Futures.immediateFuture(Optional.empty()); + immediateFuture(Optional.empty()); ListenableFuture> optionalListenableFutureWithLess = - Futures.immediateFuture(Optional.of(entry)); + immediateFuture(Optional.of(entry)); AlarmConditionFilter lowTempFilter = new AlarmConditionFilter(); lowTempFilter.setKey(new AlarmConditionFilterKey(TIME_SERIES, "temperature")); @@ -1858,31 +1975,31 @@ public class TbDeviceProfileNodeTest extends AbstractRuleNodeUpgradeTest { ); lowTempFilter.setPredicate(lowTempPredicate); AlarmCondition alarmCondition = new AlarmCondition(); - alarmCondition.setCondition(Collections.singletonList(lowTempFilter)); + alarmCondition.setCondition(singletonList(lowTempFilter)); AlarmRule alarmRule = new AlarmRule(); alarmRule.setCondition(alarmCondition); DeviceProfileAlarm dpa = new DeviceProfileAlarm(); dpa.setId("lesstempID"); dpa.setAlarmType("greaterTemperatureAlarm"); - dpa.setCreateRules(new TreeMap<>(Collections.singletonMap(AlarmSeverity.CRITICAL, alarmRule))); + dpa.setCreateRules(new TreeMap<>(singletonMap(AlarmSeverity.CRITICAL, alarmRule))); - deviceProfileData.setAlarms(Collections.singletonList(dpa)); + deviceProfileData.setAlarms(singletonList(dpa)); deviceProfile.setProfileData(deviceProfileData); - Mockito.when(cache.get(tenantId, deviceId)).thenReturn(deviceProfile); - Mockito.when(timeseriesService.findLatest(tenantId, deviceId, Collections.singleton("temperature"))) - .thenReturn(Futures.immediateFuture(Collections.emptyList())); - Mockito.when(alarmService.findLatestActiveByOriginatorAndType(tenantId, deviceId, "greaterTemperatureAlarm")) + when(cache.get(tenantId, deviceId)).thenReturn(deviceProfile); + when(timeseriesService.findLatest(tenantId, deviceId, singleton("temperature"))) + .thenReturn(immediateFuture(emptyList())); + when(alarmService.findLatestActiveByOriginatorAndType(tenantId, deviceId, "greaterTemperatureAlarm")) .thenReturn(null); registerCreateAlarmMock(alarmService.createAlarm(any()), true); - Mockito.when(ctx.getAttributesService()).thenReturn(attributesService); - Mockito.when(ctx.getDeviceService().findDeviceById(tenantId, deviceId)) + when(ctx.getAttributesService()).thenReturn(attributesService); + when(ctx.getDeviceService().findDeviceById(tenantId, deviceId)) .thenReturn(device); - Mockito.when(attributesService.find(eq(tenantId), eq(deviceId), Mockito.any(AttributeScope.class), Mockito.anySet())) + when(attributesService.find(eq(tenantId), eq(deviceId), Mockito.any(AttributeScope.class), Mockito.anySet())) .thenReturn(listListenableFutureWithLess); - Mockito.when(attributesService.find(eq(tenantId), eq(customerId), Mockito.any(AttributeScope.class), Mockito.anyString())) + when(attributesService.find(eq(tenantId), eq(customerId), Mockito.any(AttributeScope.class), Mockito.anyString())) .thenReturn(emptyOptionalFuture); - Mockito.when(attributesService.find(eq(tenantId), eq(tenantId), eq(AttributeScope.SERVER_SCOPE), Mockito.anyString())) + when(attributesService.find(eq(tenantId), eq(tenantId), eq(AttributeScope.SERVER_SCOPE), Mockito.anyString())) .thenReturn(optionalListenableFutureWithLess); TbMsg theMsg = TbMsg.newMsg() @@ -1911,15 +2028,12 @@ public class TbDeviceProfileNodeTest extends AbstractRuleNodeUpgradeTest { } private void init() throws TbNodeException { - Mockito.when(ctx.getTenantId()).thenReturn(tenantId); - Mockito.when(ctx.getDeviceProfileCache()).thenReturn(cache); - Mockito.lenient().when(ctx.getTimeseriesService()).thenReturn(timeseriesService); - Mockito.lenient().when(ctx.getAlarmService()).thenReturn(alarmService); - Mockito.when(ctx.getDeviceService()).thenReturn(deviceService); - Mockito.lenient().when(ctx.getAttributesService()).thenReturn(attributesService); - TbNodeConfiguration nodeConfiguration = new TbNodeConfiguration(JacksonUtil.newObjectNode()); + var config = new TbDeviceProfileNodeConfiguration(); + config.setFetchAlarmRulesStateOnStart(false); + config.setPersistAlarmRulesState(false); + node = new TbDeviceProfileNode(); - node.init(ctx, nodeConfiguration); + node.init(ctx, new TbNodeConfiguration(JacksonUtil.valueToTree(config))); } private void registerCreateAlarmMock(AlarmApiCallResult a, boolean created) { @@ -1991,23 +2105,23 @@ public class TbDeviceProfileNodeTest extends AbstractRuleNodeUpgradeTest { DeviceProfileAlarm dpa = new DeviceProfileAlarm(); dpa.setId("highTemperatureAlarmID"); dpa.setAlarmType("highTemperatureAlarm"); - dpa.setCreateRules(new TreeMap<>(Collections.singletonMap(AlarmSeverity.CRITICAL, createRule))); + dpa.setCreateRules(new TreeMap<>(singletonMap(AlarmSeverity.CRITICAL, createRule))); dpa.setClearRule(clearRule); - deviceProfileData.setAlarms(Collections.singletonList(dpa)); + deviceProfileData.setAlarms(singletonList(dpa)); deviceProfile.setProfileData(deviceProfileData); ListenableFuture> tsKvList = - Futures.immediateFuture(Collections.singletonList(getTsKvEntry("temperature", 35L))); + immediateFuture(singletonList(getTsKvEntry("temperature", 35L))); ListenableFuture> attrList = - Futures.immediateFuture(Collections.emptyList()); + immediateFuture(emptyList()); - Mockito.when(cache.get(tenantId, deviceId)).thenReturn(deviceProfile); - Mockito.when(timeseriesService.findLatest(tenantId, deviceId, Collections.singleton("temperature"))) + when(cache.get(tenantId, deviceId)).thenReturn(deviceProfile); + when(timeseriesService.findLatest(tenantId, deviceId, singleton("temperature"))) .thenReturn(tsKvList); - Mockito.when(attributesService.find(eq(tenantId), eq(deviceId), any(), anySet())) + when(attributesService.find(eq(tenantId), eq(deviceId), any(), anySet())) .thenReturn(attrList); - Mockito.when(alarmService.findLatestActiveByOriginatorAndType(tenantId, deviceId, "highTemperatureAlarm")).thenReturn(null); + when(alarmService.findLatestActiveByOriginatorAndType(tenantId, deviceId, "highTemperatureAlarm")).thenReturn(null); registerCreateAlarmMock(alarmService.createAlarm(any()), true); TbMsg theMsg = TbMsg.newMsg() @@ -2046,7 +2160,7 @@ public class TbDeviceProfileNodeTest extends AbstractRuleNodeUpgradeTest { private AlarmCondition getNumericAlarmCondition(AlarmConditionKeyType alarmConditionKeyType, String key, NumericOperation operation, Double value) { AlarmConditionFilter filter = getAlarmConditionFilter(alarmConditionKeyType, key, operation, value); AlarmCondition alarmCondition = new AlarmCondition(); - alarmCondition.setCondition(Collections.singletonList(filter)); + alarmCondition.setCondition(singletonList(filter)); return alarmCondition; } @@ -2076,13 +2190,13 @@ public class TbDeviceProfileNodeTest extends AbstractRuleNodeUpgradeTest { highTemperaturePredicate.setValue(new FilterPredicateValue<>(30.0)); highTempFilter.setPredicate(highTemperaturePredicate); AlarmCondition alarmCondition = new AlarmCondition(); - alarmCondition.setCondition(Collections.singletonList(highTempFilter)); + alarmCondition.setCondition(singletonList(highTempFilter)); AlarmRule alarmRule = new AlarmRule(); alarmRule.setCondition(alarmCondition); DeviceProfileAlarm dpa = new DeviceProfileAlarm(); dpa.setId("highTemperatureAlarmID"); dpa.setAlarmType("highTemperatureAlarm"); - dpa.setCreateRules(new TreeMap<>(Collections.singletonMap(AlarmSeverity.CRITICAL, alarmRule))); + dpa.setCreateRules(new TreeMap<>(singletonMap(AlarmSeverity.CRITICAL, alarmRule))); AlarmConditionFilter lowTempFilter = new AlarmConditionFilter(); lowTempFilter.setKey(new AlarmConditionFilterKey(AlarmConditionKeyType.TIME_SERIES, "temperature")); @@ -2093,17 +2207,17 @@ public class TbDeviceProfileNodeTest extends AbstractRuleNodeUpgradeTest { lowTempFilter.setPredicate(lowTemperaturePredicate); AlarmRule clearRule = new AlarmRule(); AlarmCondition clearCondition = new AlarmCondition(); - clearCondition.setCondition(Collections.singletonList(lowTempFilter)); + clearCondition.setCondition(singletonList(lowTempFilter)); clearRule.setCondition(clearCondition); dpa.setClearRule(clearRule); - deviceProfileData.setAlarms(Collections.singletonList(dpa)); + deviceProfileData.setAlarms(singletonList(dpa)); deviceProfile.setProfileData(deviceProfileData); - Mockito.when(cache.get(tenantId, deviceId)).thenReturn(deviceProfile); - Mockito.when(timeseriesService.findLatest(tenantId, deviceId, Collections.singleton("temperature"))) - .thenReturn(Futures.immediateFuture(Collections.emptyList())); - Mockito.when(alarmService.findLatestActiveByOriginatorAndType(tenantId, deviceId, "highTemperatureAlarm")).thenReturn(null); + when(cache.get(tenantId, deviceId)).thenReturn(deviceProfile); + when(timeseriesService.findLatest(tenantId, deviceId, singleton("temperature"))) + .thenReturn(immediateFuture(emptyList())); + when(alarmService.findLatestActiveByOriginatorAndType(tenantId, deviceId, "highTemperatureAlarm")).thenReturn(null); registerCreateAlarmMock(alarmService.createAlarm(any()), true); TbMsg theMsg = TbMsg.newMsg() diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/transform/TbChangeOriginatorNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/transform/TbChangeOriginatorNodeTest.java index 4826cfe297..da8816e824 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/transform/TbChangeOriginatorNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/transform/TbChangeOriginatorNodeTest.java @@ -15,8 +15,10 @@ */ package org.thingsboard.rule.engine.transform; +import com.google.common.util.concurrent.FluentFuture; import com.google.common.util.concurrent.Futures; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.params.ParameterizedTest; @@ -35,6 +37,7 @@ import org.thingsboard.rule.engine.api.TbNodeConfiguration; import org.thingsboard.rule.engine.api.TbNodeException; import org.thingsboard.rule.engine.api.util.TbNodeUtils; import org.thingsboard.rule.engine.data.RelationsQuery; +import org.thingsboard.server.common.data.Customer; import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.alarm.Alarm; @@ -54,21 +57,24 @@ import org.thingsboard.server.common.data.relation.RelationsSearchParameters; import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsgMetaData; import org.thingsboard.server.dao.asset.AssetService; -import org.thingsboard.server.dao.device.DeviceService; +import org.thingsboard.server.dao.entity.EntityService; import org.thingsboard.server.dao.relation.RelationService; import java.util.Collections; import java.util.Map; import java.util.NoSuchElementException; +import java.util.Optional; import java.util.UUID; import java.util.stream.Stream; +import static com.google.common.util.concurrent.Futures.immediateFuture; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.BDDMockito.given; import static org.mockito.BDDMockito.then; +import static org.mockito.Mockito.lenient; import static org.thingsboard.rule.engine.transform.OriginatorSource.ALARM_ORIGINATOR; import static org.thingsboard.rule.engine.transform.OriginatorSource.CUSTOMER; import static org.thingsboard.rule.engine.transform.OriginatorSource.ENTITY; @@ -93,16 +99,23 @@ public class TbChangeOriginatorNodeTest { @Mock private AssetService assetServiceMock; @Mock - private DeviceService deviceServiceMock; - @Mock private RelationService relationServiceMock; @Mock private RuleEngineAlarmService alarmServiceMock; + @Mock + private EntityService entityServiceMock; @BeforeEach - public void before() throws TbNodeException { + public void setup() { node = new TbChangeOriginatorNode(); config = new TbChangeOriginatorNodeConfiguration().defaultConfiguration(); + + lenient().when(ctxMock.getTenantId()).thenReturn(TENANT_ID); + lenient().when(ctxMock.getDbCallbackExecutor()).thenReturn(dbExecutor); + lenient().when(ctxMock.getAssetService()).thenReturn(assetServiceMock); + lenient().when(ctxMock.getRelationService()).thenReturn(relationServiceMock); + lenient().when(ctxMock.getAlarmService()).thenReturn(alarmServiceMock); + lenient().when(ctxMock.getEntityService()).thenReturn(entityServiceMock); } @Test @@ -172,8 +185,13 @@ public class TbChangeOriginatorNodeTest { } @Test - public void givenOriginatorSourceIsCustomer_whenOnMsg_thenTellSuccess() throws TbNodeException { - Device device = new Device(DEVICE_ID); + @DisplayName(""" + Given a device assigned to a customer and node configured to change originator to customer, + when processing the message, + then should change message originator from device to customer""") + public void givenDeviceAssignedToCustomer_whenProcessingMessage_thenChangesOriginatorToCustomer() throws TbNodeException { + // GIVEN + var device = new Device(DEVICE_ID); device.setCustomerId(CUSTOMER_ID); TbMsg msg = TbMsg.newMsg() @@ -186,16 +204,52 @@ public class TbChangeOriginatorNodeTest { .originator(CUSTOMER_ID) .build(); - given(ctxMock.getDbCallbackExecutor()).willReturn(dbExecutor); - given(ctxMock.getDeviceService()).willReturn(deviceServiceMock); - given(ctxMock.getTenantId()).willReturn(TENANT_ID); - given(deviceServiceMock.findDeviceById(any(TenantId.class), any(DeviceId.class))).willReturn(device); + given(entityServiceMock.fetchEntityCustomerIdAsync(TENANT_ID, device.getId())).willReturn( + FluentFuture.from(immediateFuture(Optional.of(CUSTOMER_ID))) + ); + + given(ctxMock.transformMsgOriginator(any(TbMsg.class), any(EntityId.class))).willReturn(expectedMsg); + + node.init(ctxMock, new TbNodeConfiguration(JacksonUtil.valueToTree(config))); + + // WHEN + node.onMsg(ctxMock, msg); + + // THEN + then(ctxMock).should().transformMsgOriginator(msg, CUSTOMER_ID); + ArgumentCaptor actualMsg = ArgumentCaptor.forClass(TbMsg.class); + then(ctxMock).should().tellSuccess(actualMsg.capture()); + assertThat(actualMsg.getValue()).usingRecursiveComparison().ignoringFields("ctx").isEqualTo(expectedMsg); + } + + @Test + @DisplayName(""" + Given a customer as message originator and node configured to change originator to customer, + when processing the message, + then should keep the customer as originator""") + public void givenCustomerAsOriginator_whenProcessingMessage_thenKeepsCustomerAsOriginator() throws TbNodeException { + // GIVEN + var customer = new Customer(CUSTOMER_ID); + + var msg = TbMsg.newMsg() + .type(TbMsgType.POST_TELEMETRY_REQUEST) + .originator(customer.getId()) + .metaData(TbMsgMetaData.EMPTY) + .data(TbMsg.EMPTY_JSON_OBJECT) + .build(); + + var expectedMsg = msg.transform() + .originator(CUSTOMER_ID) + .build(); + given(ctxMock.transformMsgOriginator(any(TbMsg.class), any(EntityId.class))).willReturn(expectedMsg); node.init(ctxMock, new TbNodeConfiguration(JacksonUtil.valueToTree(config))); + + // WHEN node.onMsg(ctxMock, msg); - then(deviceServiceMock).should().findDeviceById(TENANT_ID, DEVICE_ID); + // THEN then(ctxMock).should().transformMsgOriginator(msg, CUSTOMER_ID); ArgumentCaptor actualMsg = ArgumentCaptor.forClass(TbMsg.class); then(ctxMock).should().tellSuccess(actualMsg.capture()); @@ -216,8 +270,6 @@ public class TbChangeOriginatorNodeTest { .originator(TENANT_ID) .build(); - given(ctxMock.getDbCallbackExecutor()).willReturn(dbExecutor); - given(ctxMock.getTenantId()).willReturn(TENANT_ID); given(ctxMock.transformMsgOriginator(any(TbMsg.class), any(EntityId.class))).willReturn(expectedMsg); node.init(ctxMock, new TbNodeConfiguration(JacksonUtil.valueToTree(config))); @@ -240,9 +292,6 @@ public class TbChangeOriginatorNodeTest { .data(TbMsg.EMPTY_JSON_OBJECT) .build(); - given(ctxMock.getDbCallbackExecutor()).willReturn(dbExecutor); - given(ctxMock.getRelationService()).willReturn(relationServiceMock); - given(ctxMock.getTenantId()).willReturn(TENANT_ID); given(relationServiceMock.findByQuery(any(TenantId.class), any(EntityRelationsQuery.class))).willReturn(Futures.immediateFuture(Collections.emptyList())); node.init(ctxMock, new TbNodeConfiguration(JacksonUtil.valueToTree(config))); @@ -282,9 +331,6 @@ public class TbChangeOriginatorNodeTest { .originator(DEVICE_ID) .build(); - given(ctxMock.getDbCallbackExecutor()).willReturn(dbExecutor); - given(ctxMock.getAlarmService()).willReturn(alarmServiceMock); - given(ctxMock.getTenantId()).willReturn(TENANT_ID); given(alarmServiceMock.findAlarmByIdAsync(any(TenantId.class), any(AlarmId.class))).willReturn(Futures.immediateFuture(alarm)); given(ctxMock.transformMsgOriginator(any(TbMsg.class), any(EntityId.class))).willReturn(expectedMsg); @@ -315,9 +361,6 @@ public class TbChangeOriginatorNodeTest { .originator(ASSET_ID) .build(); - given(ctxMock.getDbCallbackExecutor()).willReturn(dbExecutor); - given(ctxMock.getAssetService()).willReturn(assetServiceMock); - given(ctxMock.getTenantId()).willReturn(TENANT_ID); given(assetServiceMock.findAssetByTenantIdAndName(any(TenantId.class), any(String.class))).willReturn(new Asset(ASSET_ID)); given(ctxMock.transformMsgOriginator(any(TbMsg.class), any(EntityId.class))).willReturn(expectedMsg); @@ -355,9 +398,6 @@ public class TbChangeOriginatorNodeTest { .data(TbMsg.EMPTY_JSON_OBJECT) .build(); - given(ctxMock.getDbCallbackExecutor()).willReturn(dbExecutor); - given(ctxMock.getAssetService()).willReturn(assetServiceMock); - given(ctxMock.getTenantId()).willReturn(TENANT_ID); given(assetServiceMock.findAssetByTenantIdAndName(any(TenantId.class), any(String.class))).willReturn(null); node.init(ctxMock, new TbNodeConfiguration(JacksonUtil.valueToTree(config))); diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/util/EntitiesCustomerIdAsyncLoaderTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/util/EntitiesCustomerIdAsyncLoaderTest.java deleted file mode 100644 index 0be4e64ca2..0000000000 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/util/EntitiesCustomerIdAsyncLoaderTest.java +++ /dev/null @@ -1,154 +0,0 @@ -/** - * Copyright © 2016-2025 The Thingsboard Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.thingsboard.rule.engine.util; - -import com.google.common.util.concurrent.Futures; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; -import org.thingsboard.common.util.ListeningExecutor; -import org.thingsboard.rule.engine.TestDbCallbackExecutor; -import org.thingsboard.rule.engine.api.TbContext; -import org.thingsboard.rule.engine.api.TbNodeException; -import org.thingsboard.server.common.data.Customer; -import org.thingsboard.server.common.data.Device; -import org.thingsboard.server.common.data.EntityType; -import org.thingsboard.server.common.data.User; -import org.thingsboard.server.common.data.asset.Asset; -import org.thingsboard.server.common.data.id.AssetId; -import org.thingsboard.server.common.data.id.CustomerId; -import org.thingsboard.server.common.data.id.DeviceId; -import org.thingsboard.server.common.data.id.EntityIdFactory; -import org.thingsboard.server.common.data.id.UserId; -import org.thingsboard.server.dao.asset.AssetService; -import org.thingsboard.server.dao.device.DeviceService; -import org.thingsboard.server.dao.user.UserService; - -import java.util.EnumSet; -import java.util.UUID; -import java.util.concurrent.ExecutionException; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertInstanceOf; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.when; - -@ExtendWith(MockitoExtension.class) -public class EntitiesCustomerIdAsyncLoaderTest { - - private static final EnumSet SUPPORTED_ENTITY_TYPES = EnumSet.of( - EntityType.CUSTOMER, - EntityType.USER, - EntityType.ASSET, - EntityType.DEVICE - ); - private static final ListeningExecutor DB_EXECUTOR = new TestDbCallbackExecutor(); - @Mock - private TbContext ctxMock; - @Mock - private UserService userServiceMock; - @Mock - private AssetService assetServiceMock; - @Mock - private DeviceService deviceServiceMock; - - @Test - public void givenCustomerEntityType_whenFindEntityIdAsync_thenOK() throws ExecutionException, InterruptedException { - // GIVEN - var customer = new Customer(new CustomerId(UUID.randomUUID())); - - // WHEN - var actualCustomerId = EntitiesCustomerIdAsyncLoader.findEntityIdAsync(ctxMock, customer.getId()).get(); - - // THEN - assertEquals(customer.getId(), actualCustomerId); - } - - @Test - public void givenUserEntityType_whenFindEntityIdAsync_thenOK() throws ExecutionException, InterruptedException { - // GIVEN - var user = new User(new UserId(UUID.randomUUID())); - var expectedCustomerId = new CustomerId(UUID.randomUUID()); - user.setCustomerId(expectedCustomerId); - - when(ctxMock.getUserService()).thenReturn(userServiceMock); - doReturn(Futures.immediateFuture(user)).when(userServiceMock).findUserByIdAsync(any(), any()); - when(ctxMock.getDbCallbackExecutor()).thenReturn(DB_EXECUTOR); - - // WHEN - var actualCustomerId = EntitiesCustomerIdAsyncLoader.findEntityIdAsync(ctxMock, user.getId()).get(); - - // THEN - assertEquals(expectedCustomerId, actualCustomerId); - } - - @Test - public void givenAssetEntityType_whenFindEntityIdAsync_thenOK() throws ExecutionException, InterruptedException { - // GIVEN - var asset = new Asset(new AssetId(UUID.randomUUID())); - var expectedCustomerId = new CustomerId(UUID.randomUUID()); - asset.setCustomerId(expectedCustomerId); - - when(ctxMock.getAssetService()).thenReturn(assetServiceMock); - doReturn(Futures.immediateFuture(asset)).when(assetServiceMock).findAssetByIdAsync(any(), any()); - when(ctxMock.getDbCallbackExecutor()).thenReturn(DB_EXECUTOR); - - // WHEN - var actualCustomerId = EntitiesCustomerIdAsyncLoader.findEntityIdAsync(ctxMock, asset.getId()).get(); - - // THEN - assertEquals(expectedCustomerId, actualCustomerId); - } - - @Test - public void givenDeviceEntityType_whenFindEntityIdAsync_thenOK() throws ExecutionException, InterruptedException { - // GIVEN - var device = new Device(new DeviceId(UUID.randomUUID())); - var expectedCustomerId = new CustomerId(UUID.randomUUID()); - device.setCustomerId(expectedCustomerId); - - when(ctxMock.getDeviceService()).thenReturn(deviceServiceMock); - doReturn(device).when(deviceServiceMock).findDeviceById(any(), any()); - when(ctxMock.getDbCallbackExecutor()).thenReturn(DB_EXECUTOR); - - // WHEN - var actualCustomerId = EntitiesCustomerIdAsyncLoader.findEntityIdAsync(ctxMock, device.getId()).get(); - - // THEN - assertEquals(expectedCustomerId, actualCustomerId); - } - - @Test - public void givenUnsupportedEntityTypes_whenFindEntityIdAsync_thenException() { - for (var entityType : EntityType.values()) { - if (!SUPPORTED_ENTITY_TYPES.contains(entityType)) { - var entityId = EntityIdFactory.getByTypeAndUuid(entityType, UUID.randomUUID()); - - var expectedExceptionMsg = "org.thingsboard.rule.engine.api.TbNodeException: Unexpected originator EntityType: " + entityType; - - var exception = assertThrows(ExecutionException.class, - () -> EntitiesCustomerIdAsyncLoader.findEntityIdAsync(ctxMock, entityId).get()); - - assertInstanceOf(TbNodeException.class, exception.getCause()); - assertEquals(expectedExceptionMsg, exception.getMessage()); - } - } - } - -} diff --git a/tools/pom.xml b/tools/pom.xml index bc78989227..783dc1ee73 100644 --- a/tools/pom.xml +++ b/tools/pom.xml @@ -55,6 +55,10 @@ org.apache.cassandra cassandra-all + + at.yawk.lz4 + lz4-java + commons-io commons-io diff --git a/transport/coap/src/main/resources/tb-coap-transport.yml b/transport/coap/src/main/resources/tb-coap-transport.yml index f40a09c753..02ec421366 100644 --- a/transport/coap/src/main/resources/tb-coap-transport.yml +++ b/transport/coap/src/main/resources/tb-coap-transport.yml @@ -332,6 +332,8 @@ queue: notifications: "${TB_QUEUE_KAFKA_NOTIFICATIONS_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:52428800;retention.bytes:1048576000;partitions:1;min.insync.replicas:1}" # Kafka properties for Housekeeper tasks topic housekeeper: "${TB_QUEUE_KAFKA_HOUSEKEEPER_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:52428800;retention.bytes:1048576000;partitions:10;min.insync.replicas:1}" + # Topics cache TTL in milliseconds. 5 minutes by default + topics_cache_ttl_ms: "${TB_QUEUE_KAFKA_TOPICS_CACHE_TTL_MS:300000}" partitions: hash_function_name: "${TB_QUEUE_PARTITIONS_HASH_FUNCTION_NAME:murmur3_128}" # murmur3_32, murmur3_128 or sha256 transport_api: diff --git a/transport/http/src/main/resources/tb-http-transport.yml b/transport/http/src/main/resources/tb-http-transport.yml index 587894d5ce..7fe35a57d5 100644 --- a/transport/http/src/main/resources/tb-http-transport.yml +++ b/transport/http/src/main/resources/tb-http-transport.yml @@ -281,6 +281,8 @@ queue: notifications: "${TB_QUEUE_KAFKA_NOTIFICATIONS_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:52428800;retention.bytes:1048576000;partitions:1;min.insync.replicas:1}" # Kafka properties for Housekeeper tasks topic housekeeper: "${TB_QUEUE_KAFKA_HOUSEKEEPER_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:52428800;retention.bytes:1048576000;partitions:10;min.insync.replicas:1}" + # Topics cache TTL in milliseconds. 5 minutes by default + topics_cache_ttl_ms: "${TB_QUEUE_KAFKA_TOPICS_CACHE_TTL_MS:300000}" partitions: hash_function_name: "${TB_QUEUE_PARTITIONS_HASH_FUNCTION_NAME:murmur3_128}" # murmur3_32, murmur3_128 or sha256 transport_api: diff --git a/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml b/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml index 0895bfa676..b1718a2099 100644 --- a/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml +++ b/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml @@ -382,6 +382,8 @@ queue: notifications: "${TB_QUEUE_KAFKA_NOTIFICATIONS_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:52428800;retention.bytes:1048576000;partitions:1;min.insync.replicas:1}" # Kafka properties for Housekeeper tasks topic housekeeper: "${TB_QUEUE_KAFKA_HOUSEKEEPER_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:52428800;retention.bytes:1048576000;partitions:10;min.insync.replicas:1}" + # Topics cache TTL in milliseconds. 5 minutes by default + topics_cache_ttl_ms: "${TB_QUEUE_KAFKA_TOPICS_CACHE_TTL_MS:300000}" partitions: hash_function_name: "${TB_QUEUE_PARTITIONS_HASH_FUNCTION_NAME:murmur3_128}" # murmur3_32, murmur3_128 or sha256 transport_api: diff --git a/transport/mqtt/src/main/resources/tb-mqtt-transport.yml b/transport/mqtt/src/main/resources/tb-mqtt-transport.yml index fae10cc892..86e5dc5a5b 100644 --- a/transport/mqtt/src/main/resources/tb-mqtt-transport.yml +++ b/transport/mqtt/src/main/resources/tb-mqtt-transport.yml @@ -315,6 +315,8 @@ queue: notifications: "${TB_QUEUE_KAFKA_NOTIFICATIONS_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:52428800;retention.bytes:1048576000;partitions:1;min.insync.replicas:1}" # Kafka properties for Housekeeper tasks topic housekeeper: "${TB_QUEUE_KAFKA_HOUSEKEEPER_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:52428800;retention.bytes:1048576000;partitions:10;min.insync.replicas:1}" + # Topics cache TTL in milliseconds. 5 minutes by default + topics_cache_ttl_ms: "${TB_QUEUE_KAFKA_TOPICS_CACHE_TTL_MS:300000}" partitions: hash_function_name: "${TB_QUEUE_PARTITIONS_HASH_FUNCTION_NAME:murmur3_128}" # murmur3_32, murmur3_128 or sha256 transport_api: diff --git a/transport/snmp/src/main/resources/tb-snmp-transport.yml b/transport/snmp/src/main/resources/tb-snmp-transport.yml index 79aee31921..9dfb9f0b41 100644 --- a/transport/snmp/src/main/resources/tb-snmp-transport.yml +++ b/transport/snmp/src/main/resources/tb-snmp-transport.yml @@ -151,6 +151,8 @@ transport: ignore_type_cast_errors: "${SNMP_RESPONSE_IGNORE_TYPE_CAST_ERRORS:false}" # Thread pool size for scheduler that executes device querying tasks scheduler_thread_pool_size: "${SNMP_SCHEDULER_THREAD_POOL_SIZE:4}" + # Maximum number of retry attempts for a single SNMP devices batch during bootstrap. + batch_retries: "${SNMP_BOOTSTRAP_RETRIES:8}" sessions: # Session inactivity timeout is a global configuration parameter that defines how long the device transport session will be opened after the last message arrives from the device. # The parameter value is in milliseconds. @@ -268,6 +270,8 @@ queue: print-interval-ms: "${TB_QUEUE_KAFKA_CONSUMER_STATS_MIN_PRINT_INTERVAL_MS:60000}" # Time to wait for the stats-loading requests to Kafka to finis kafka-response-timeout-ms: "${TB_QUEUE_KAFKA_CONSUMER_STATS_RESPONSE_TIMEOUT_MS:1000}" + # Topics cache TTL in milliseconds. 5 minutes by default + topics_cache_ttl_ms: "${TB_QUEUE_KAFKA_TOPICS_CACHE_TTL_MS:300000}" partitions: hash_function_name: "${TB_QUEUE_PARTITIONS_HASH_FUNCTION_NAME:murmur3_128}" # murmur3_32, murmur3_128 or sha256 transport_api: diff --git a/ui-ngx/package.json b/ui-ngx/package.json index ea7d7c80fb..74b4bbbb9c 100644 --- a/ui-ngx/package.json +++ b/ui-ngx/package.json @@ -1,6 +1,6 @@ { "name": "thingsboard", - "version": "4.2.1", + "version": "4.2.1.1", "scripts": { "ng": "ng", "start": "node --max_old_space_size=8048 ./node_modules/@angular/cli/bin/ng serve --configuration development --host 0.0.0.0 --open", @@ -141,6 +141,9 @@ "rollup": "4.22.4", "@babel/core": "7.25.2", "esbuild": "0.23.0", - "jquery.terminal/coveralls-next/form-data": "4.0.4" + "jquery.terminal/coveralls-next/form-data": "4.0.4", + "node-forge": "1.3.3", + "glob": "10.5.0", + "path-to-regexp": "0.1.12" } } diff --git a/ui-ngx/patches/@angular+common+18.2.13.patch b/ui-ngx/patches/@angular+common+18.2.13.patch new file mode 100644 index 0000000000..984562138a --- /dev/null +++ b/ui-ngx/patches/@angular+common+18.2.13.patch @@ -0,0 +1,66 @@ +diff --git a/node_modules/@angular/common/esm2022/http/src/xsrf.mjs b/node_modules/@angular/common/esm2022/http/src/xsrf.mjs +index da69c17..d17f6ad 100755 +--- a/node_modules/@angular/common/esm2022/http/src/xsrf.mjs ++++ b/node_modules/@angular/common/esm2022/http/src/xsrf.mjs +@@ -19,6 +19,10 @@ export const XSRF_HEADER_NAME = new InjectionToken(ngDevMode ? 'XSRF_HEADER_NAME + providedIn: 'root', + factory: () => XSRF_DEFAULT_HEADER_NAME, + }); ++/** ++ * Regex to match absolute URLs, including protocol-relative URLs. ++ */ ++const ABSOLUTE_URL_REGEX = /^(?:https?:)?\/\//i; + /** + * Retrieves the current XSRF token to use with the next outgoing request. + * +@@ -69,7 +73,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImpo + args: [XSRF_COOKIE_NAME] + }] }] }); + export function xsrfInterceptorFn(req, next) { +- const lcUrl = req.url.toLowerCase(); + // Skip both non-mutating requests and absolute URLs. + // Non-mutating requests don't require a token, and absolute URLs require special handling + // anyway as the cookie set +@@ -77,8 +80,7 @@ export function xsrfInterceptorFn(req, next) { + if (!inject(XSRF_ENABLED) || + req.method === 'GET' || + req.method === 'HEAD' || +- lcUrl.startsWith('http://') || +- lcUrl.startsWith('https://')) { ++ ABSOLUTE_URL_REGEX.test(req.url)) { + return next(req); + } + const token = inject(HttpXsrfTokenExtractor).getToken(); +diff --git a/node_modules/@angular/common/fesm2022/http.mjs b/node_modules/@angular/common/fesm2022/http.mjs +index 1655480..d1dbb38 100755 +--- a/node_modules/@angular/common/fesm2022/http.mjs ++++ b/node_modules/@angular/common/fesm2022/http.mjs +@@ -2352,6 +2352,10 @@ const XSRF_HEADER_NAME = new InjectionToken(ngDevMode ? 'XSRF_HEADER_NAME' : '', + providedIn: 'root', + factory: () => XSRF_DEFAULT_HEADER_NAME, + }); ++/** ++ * Regex to match absolute URLs, including protocol-relative URLs. ++ */ ++const ABSOLUTE_URL_REGEX = /^(?:https?:)?\/\//i; + /** + * Retrieves the current XSRF token to use with the next outgoing request. + * +@@ -2402,7 +2406,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImpo + args: [XSRF_COOKIE_NAME] + }] }] }); + function xsrfInterceptorFn(req, next) { +- const lcUrl = req.url.toLowerCase(); + // Skip both non-mutating requests and absolute URLs. + // Non-mutating requests don't require a token, and absolute URLs require special handling + // anyway as the cookie set +@@ -2410,8 +2413,7 @@ function xsrfInterceptorFn(req, next) { + if (!inject(XSRF_ENABLED) || + req.method === 'GET' || + req.method === 'HEAD' || +- lcUrl.startsWith('http://') || +- lcUrl.startsWith('https://')) { ++ ABSOLUTE_URL_REGEX.test(req.url)) { + return next(req); + } + const token = inject(HttpXsrfTokenExtractor).getToken(); diff --git a/ui-ngx/patches/@angular+compiler+18.2.13.patch b/ui-ngx/patches/@angular+compiler+18.2.13.patch new file mode 100644 index 0000000000..a4245cb0e9 --- /dev/null +++ b/ui-ngx/patches/@angular+compiler+18.2.13.patch @@ -0,0 +1,88 @@ +diff --git a/node_modules/@angular/compiler/fesm2022/compiler.mjs b/node_modules/@angular/compiler/fesm2022/compiler.mjs +index a00b189..260e7be 100755 +--- a/node_modules/@angular/compiler/fesm2022/compiler.mjs ++++ b/node_modules/@angular/compiler/fesm2022/compiler.mjs +@@ -18631,6 +18631,7 @@ function SECURITY_SCHEMA() { + 'area|ping', + 'audio|src', + 'a|href', ++ 'a|xlink:href', + 'a|ping', + 'blockquote|cite', + 'body|background', +@@ -18644,6 +18645,75 @@ function SECURITY_SCHEMA() { + 'track|src', + 'video|poster', + 'video|src', ++ ++ // MathML namespace ++ // https://crsrc.org/c/third_party/blink/renderer/core/sanitizer/sanitizer.cc;l=753-768;drc=b3eb16372dcd3317d65e9e0265015e322494edcd;bpv=1;bpt=1 ++ 'annotation|href', ++ 'annotation|xlink:href', ++ 'annotation-xml|href', ++ 'annotation-xml|xlink:href', ++ 'maction|href', ++ 'maction|xlink:href', ++ 'malignmark|href', ++ 'malignmark|xlink:href', ++ 'math|href', ++ 'math|xlink:href', ++ 'mroot|href', ++ 'mroot|xlink:href', ++ 'msqrt|href', ++ 'msqrt|xlink:href', ++ 'merror|href', ++ 'merror|xlink:href', ++ 'mfrac|href', ++ 'mfrac|xlink:href', ++ 'mglyph|href', ++ 'mglyph|xlink:href', ++ 'msub|href', ++ 'msub|xlink:href', ++ 'msup|href', ++ 'msup|xlink:href', ++ 'msubsup|href', ++ 'msubsup|xlink:href', ++ 'mmultiscripts|href', ++ 'mmultiscripts|xlink:href', ++ 'mprescripts|href', ++ 'mprescripts|xlink:href', ++ 'mi|href', ++ 'mi|xlink:href', ++ 'mn|href', ++ 'mn|xlink:href', ++ 'mo|href', ++ 'mo|xlink:href', ++ 'mpadded|href', ++ 'mpadded|xlink:href', ++ 'mphantom|href', ++ 'mphantom|xlink:href', ++ 'mrow|href', ++ 'mrow|xlink:href', ++ 'ms|href', ++ 'ms|xlink:href', ++ 'mspace|href', ++ 'mspace|xlink:href', ++ 'mstyle|href', ++ 'mstyle|xlink:href', ++ 'mtable|href', ++ 'mtable|xlink:href', ++ 'mtd|href', ++ 'mtd|xlink:href', ++ 'mtr|href', ++ 'mtr|xlink:href', ++ 'mtext|href', ++ 'mtext|xlink:href', ++ 'mover|href', ++ 'mover|xlink:href', ++ 'munder|href', ++ 'munder|xlink:href', ++ 'munderover|href', ++ 'munderover|xlink:href', ++ 'semantics|href', ++ 'semantics|xlink:href', ++ 'none|href', ++ 'none|xlink:href', + ]); + registerContext(SecurityContext.RESOURCE_URL, [ + 'applet|code', diff --git a/ui-ngx/src/app/core/http/admin.service.ts b/ui-ngx/src/app/core/http/admin.service.ts index 55eaa16b90..36bb931f93 100644 --- a/ui-ngx/src/app/core/http/admin.service.ts +++ b/ui-ngx/src/app/core/http/admin.service.ts @@ -21,9 +21,9 @@ import { HttpClient } from '@angular/common/http'; import { AdminSettings, AutoCommitSettings, - MailConfigTemplate, FeaturesInfo, JwtSettings, + MailConfigTemplate, MailServerSettings, RepositorySettings, RepositorySettingsInfo, diff --git a/ui-ngx/src/app/core/http/git-hub.service.ts b/ui-ngx/src/app/core/http/git-hub.service.ts new file mode 100644 index 0000000000..b6a927dab3 --- /dev/null +++ b/ui-ngx/src/app/core/http/git-hub.service.ts @@ -0,0 +1,38 @@ +/// +/// Copyright © 2016-2025 The Thingsboard Authors +/// +/// Licensed under the Apache License, Version 2.0 (the "License"); +/// you may not use this file except in compliance with the License. +/// You may obtain a copy of the License at +/// +/// http://www.apache.org/licenses/LICENSE-2.0 +/// +/// Unless required by applicable law or agreed to in writing, software +/// distributed under the License is distributed on an "AS IS" BASIS, +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +/// See the License for the specific language governing permissions and +/// limitations under the License. +/// + +import { Injectable } from '@angular/core'; +import { defaultHttpOptionsFromConfig, RequestConfig } from './http-utils'; +import { Observable, of } from 'rxjs'; +import { HttpClient } from '@angular/common/http'; +import { catchError, map } from 'rxjs/operators'; + +@Injectable({ + providedIn: 'root' +}) +export class GitHubService { + + constructor( + private http: HttpClient + ) { } + + public getGitHubStar(config?: RequestConfig): Observable { + return this.http.get('https://api.github.com/repos/thingsboard/thingsboard', defaultHttpOptionsFromConfig(config)).pipe( + catchError(() => of({})), + map((res: any) => res?.stargazers_count ?? 0) + ) + } +} diff --git a/ui-ngx/src/app/core/http/queue.service.ts b/ui-ngx/src/app/core/http/queue.service.ts index d9bc19ef62..651d26c9dc 100644 --- a/ui-ngx/src/app/core/http/queue.service.ts +++ b/ui-ngx/src/app/core/http/queue.service.ts @@ -75,7 +75,7 @@ export class QueueService { } public getQueueStatisticsByIds(queueStatIds: Array, config?: RequestConfig): Observable> { - return this.http.get>(`/api/queueStats?QueueStatsIds=${queueStatIds.join(',')}`, + return this.http.get>(`/api/queueStats?queueStatsIds=${queueStatIds.join(',')}`, defaultHttpOptionsFromConfig(config)).pipe( map(queueStats => queueStats.map(queueStat => this.parseQueueStatName(queueStat)) ) diff --git a/ui-ngx/src/app/core/interceptors/global-http-interceptor.ts b/ui-ngx/src/app/core/interceptors/global-http-interceptor.ts index dccda985b4..af204fc99b 100644 --- a/ui-ngx/src/app/core/interceptors/global-http-interceptor.ts +++ b/ui-ngx/src/app/core/interceptors/global-http-interceptor.ts @@ -125,6 +125,10 @@ export class GlobalHttpInterceptor implements HttpInterceptor { this.showError(req.method + ': ' + req.url + '
' + errorResponse.status + ': ' + errorResponse.statusText); } + } else if (errorResponse.status === 504) { + if (!ignoreErrors) { + this.showError('Request timeout'); + } } else { unhandled = true; } diff --git a/ui-ngx/src/app/core/utils.ts b/ui-ngx/src/app/core/utils.ts index 8ef3dc074e..5bdb6a48dd 100644 --- a/ui-ngx/src/app/core/utils.ts +++ b/ui-ngx/src/app/core/utils.ts @@ -33,8 +33,10 @@ import { } from '@shared/models/js-function.models'; import { DomSanitizer } from '@angular/platform-browser'; import { SecurityContext } from '@angular/core'; +import { AbstractControl, ValidationErrors, Validators } from '@angular/forms'; const varsRegex = /\${([^}]*)}/g; +const emailRegex = /^[A-Z0-9_!#$%&'*+/=?`{|}~^.-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i; export function onParentScrollOrWindowResize(el: Node): Observable { const scrollSubject = new Subject(); @@ -401,7 +403,7 @@ export function mergeDeep(target: T, ...sources: T[]): T { function ignoreArrayMergeFunc(target: any, sources: any) { if (_.isArray(target)) { - return sources; + return deepClone(sources); } } @@ -988,3 +990,11 @@ export const trimDefaultValues = (input: Record, defaults: Record { + if (isUndefinedOrNull(control.value) || (typeof control.value === 'string' && control.value.length === 0)) { + return null; + } + return emailRegex.test(control.value) ? null : {email: true}; +}; + diff --git a/ui-ngx/src/app/modules/home/components/ai-model/check-connectivity-dialog.component.ts b/ui-ngx/src/app/modules/home/components/ai-model/check-connectivity-dialog.component.ts index dd2c27cb47..cd593b4291 100644 --- a/ui-ngx/src/app/modules/home/components/ai-model/check-connectivity-dialog.component.ts +++ b/ui-ngx/src/app/modules/home/components/ai-model/check-connectivity-dialog.component.ts @@ -56,9 +56,7 @@ export class CheckConnectivityDialogComponent extends DialogComponent implements OnInit { +export class AlarmDetailsDialogComponent extends DialogComponent { alarmId: string; alarmFormGroup: UntypedFormGroup; @@ -128,13 +128,12 @@ export class AlarmDetailsDialogComponent extends DialogComponent> extends EntityComponent implements AfterViewInit { @@ -50,7 +51,7 @@ export abstract class ContactBasedComponent> exten entityForm.addControl('address', this.fb.control(entity ? entity.address : '', [])); entityForm.addControl('address2', this.fb.control(entity ? entity.address2 : '', [])); entityForm.addControl('phone', this.fb.control(entity ? entity.phone : '', [Validators.maxLength(255)])); - entityForm.addControl('email', this.fb.control(entity ? entity.email : '', [Validators.email])); + entityForm.addControl('email', this.fb.control(entity ? entity.email : '', [validateEmail])); return entityForm; } diff --git a/ui-ngx/src/app/modules/home/components/entity/entity-filter.component.html b/ui-ngx/src/app/modules/home/components/entity/entity-filter.component.html index 25bb1d9700..736e716bec 100644 --- a/ui-ngx/src/app/modules/home/components/entity/entity-filter.component.html +++ b/ui-ngx/src/app/modules/home/components/entity/entity-filter.component.html @@ -45,6 +45,7 @@ diff --git a/ui-ngx/src/app/modules/home/components/filter/user-filter-dialog.component.html b/ui-ngx/src/app/modules/home/components/filter/user-filter-dialog.component.html index 4c350beee7..6ec45f2d16 100644 --- a/ui-ngx/src/app/modules/home/components/filter/user-filter-dialog.component.html +++ b/ui-ngx/src/app/modules/home/components/filter/user-filter-dialog.component.html @@ -17,7 +17,7 @@ -->
-

{{ filter.filter }}

+

{{ filter.filter | customTranslate }}

+ + + +} diff --git a/ui-ngx/src/app/modules/home/components/github-badge/github-badge.component.scss b/ui-ngx/src/app/modules/home/components/github-badge/github-badge.component.scss new file mode 100644 index 0000000000..08e130f7ec --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/github-badge/github-badge.component.scss @@ -0,0 +1,50 @@ +/** + * Copyright © 2016-2025 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +:host { + &:has(section) { + height: 100%; + } + --mat-outlined-button-horizontal-padding: 8px; + --mdc-outlined-button-container-height: 30px; + --mdc-outlined-button-label-text-size: 12px; + --mat-outlined-button-hover-state-layer-opacity: 0; + --mat-icon-button-hover-state-layer-opacity: 0; + + .group { + .mdc-button { + background-color: rgba(255, 255, 255, 0.12); + } + + &:hover { + .mdc-button { + background-color: rgba(255, 255, 255, 0.20); + } + } + + .mdc-icon-button { + background-color: #162C41; + + &:hover { + background-color: #DD2C00; + } + } + } + + .button-label { + height: 28px; + --mat-divider-color: var(--mdc-outlined-button-label-text-color); + } +} diff --git a/ui-ngx/src/app/modules/home/components/github-badge/github-badge.component.ts b/ui-ngx/src/app/modules/home/components/github-badge/github-badge.component.ts new file mode 100644 index 0000000000..b561054d10 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/github-badge/github-badge.component.ts @@ -0,0 +1,79 @@ +/// +/// Copyright © 2016-2025 The Thingsboard Authors +/// +/// Licensed under the Apache License, Version 2.0 (the "License"); +/// you may not use this file except in compliance with the License. +/// You may obtain a copy of the License at +/// +/// http://www.apache.org/licenses/LICENSE-2.0 +/// +/// Unless required by applicable law or agreed to in writing, software +/// distributed under the License is distributed on an "AS IS" BASIS, +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +/// See the License for the specific language governing permissions and +/// limitations under the License. +/// + +import { Component, OnDestroy } from '@angular/core'; +import { GitHubService } from '@core/http/git-hub.service'; +import { Store } from '@ngrx/store'; +import { selectAuthUser, selectIsAuthenticated } from '@core/auth/auth.selectors'; +import { distinctUntilChanged, filter, map, switchMap, take, takeUntil } from 'rxjs/operators'; +import { Authority } from '@shared/models/authority.enum'; +import { AppState } from '@core/core.state'; +import { LocalStorageService } from '@core/local-storage/local-storage.service'; +import { Subject } from 'rxjs'; + +const SETTINGS_KEY = 'HIDE_GITHUB_STAR_BUTTON'; + +@Component({ + selector: 'tb-github-badge', + templateUrl: './github-badge.component.html', + styleUrl: './github-badge.component.scss' +}) +export class GithubBadgeComponent implements OnDestroy { + + githubStar = 0; + + private stopWatch$ = new Subject(); + + constructor(private gitHubService: GitHubService, + private localStorageService: LocalStorageService, + private store: Store,) { + const hide = this.localStorageService.getItem(SETTINGS_KEY) ?? false; + + if (!hide) { + this.store.select(selectIsAuthenticated).pipe( + filter((data) => data), + switchMap(() => this.store.select(selectAuthUser).pipe(take(1))), + map((authUser) => { + return [Authority.TENANT_ADMIN, Authority.SYS_ADMIN].includes(authUser?.authority ?? Authority.ANONYMOUS) + }), + distinctUntilChanged(), + takeUntil(this.stopWatch$), + ).subscribe(value => { + if (value) { + this.gitHubService.getGitHubStar().subscribe(star => { + this.githubStar = star; + }); + } else { + this.githubStar = 0 + } + }); + } + } + + hideGithubStar($event: Event) { + $event?.stopPropagation(); + this.localStorageService.setItem(SETTINGS_KEY, true); + this.githubStar = 0; + + this.stopWatch$.next(); + this.stopWatch$.complete(); + } + + ngOnDestroy() { + this.stopWatch$.next(); + this.stopWatch$.complete(); + } +} diff --git a/ui-ngx/src/app/modules/home/components/vc/auto-commit-settings.component.html b/ui-ngx/src/app/modules/home/components/vc/auto-commit-settings.component.html index d80892664d..2bf50da468 100644 --- a/ui-ngx/src/app/modules/home/components/vc/auto-commit-settings.component.html +++ b/ui-ngx/src/app/modules/home/components/vc/auto-commit-settings.component.html @@ -38,7 +38,7 @@
- +
@@ -60,6 +60,7 @@
-
{{ 'version-control.export-credentials' | translate }} diff --git a/ui-ngx/src/app/modules/home/components/vc/auto-commit-settings.component.scss b/ui-ngx/src/app/modules/home/components/vc/auto-commit-settings.component.scss index a72bd2ca77..e925c79b0d 100644 --- a/ui-ngx/src/app/modules/home/components/vc/auto-commit-settings.component.scss +++ b/ui-ngx/src/app/modules/home/components/vc/auto-commit-settings.component.scss @@ -52,7 +52,6 @@ padding: 0 8px 8px; tb-branch-autocomplete { min-width: 200px; - max-width: 200px; display: block; } } diff --git a/ui-ngx/src/app/modules/home/components/vc/complex-version-create.component.html b/ui-ngx/src/app/modules/home/components/vc/complex-version-create.component.html index e97e02190a..c4ddc88301 100644 --- a/ui-ngx/src/app/modules/home/components/vc/complex-version-create.component.html +++ b/ui-ngx/src/app/modules/home/components/vc/complex-version-create.component.html @@ -39,7 +39,7 @@
- + version-control.default-sync-strategy diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/alarm/alarms-table-widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/alarm/alarms-table-widget.component.ts index 3972ceecb0..1f1cbd4964 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/alarm/alarms-table-widget.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/alarm/alarms-table-widget.component.ts @@ -330,6 +330,15 @@ export class AlarmsTableWidgetComponent extends PageComponent implements OnInit, if (this.displayPagination) { this.sort.sortChange.pipe(takeUntil(this.destroy$)).subscribe(() => this.paginator.pageIndex = 0); + + this.ctx.aliasController?.filtersChanged.pipe( + takeUntil(this.destroy$) + ).subscribe((filters) => { + let currentFilterId = this.ctx.defaultSubscription.options.alarmSource?.filterId; + if (currentFilterId && filters.includes(currentFilterId)) { + this.paginator.firstPage(); + } + }); } ((this.displayPagination ? merge(this.sort.sortChange, this.paginator.page) : this.sort.sortChange) as Observable).pipe( takeUntil(this.destroy$) diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/entity/entities-table-widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/entity/entities-table-widget.component.ts index f95c8c26d7..87acdd686b 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/entity/entities-table-widget.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/entity/entities-table-widget.component.ts @@ -265,6 +265,15 @@ export class EntitiesTableWidgetComponent extends PageComponent implements OnIni if (this.displayPagination) { this.sort.sortChange.pipe(takeUntil(this.destroy$)).subscribe(() => this.paginator.pageIndex = 0); + + this.ctx.aliasController?.filtersChanged.pipe( + takeUntil(this.destroy$) + ).subscribe((filters) => { + let currentFilterId = this.ctx.defaultSubscription.options.datasources?.[0]?.filterId; + if (currentFilterId && filters.includes(currentFilterId)) { + this.paginator.firstPage(); + } + }); } ((this.displayPagination ? merge(this.sort.sortChange, this.paginator.page) : this.sort.sortChange) as Observable).pipe( takeUntil(this.destroy$) diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/rpc/led-indicator.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/rpc/led-indicator.component.html index 7e57b83091..b961c9c87e 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/rpc/led-indicator.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/rpc/led-indicator.component.html @@ -17,7 +17,7 @@ -->
- {{title}} + {{title | customTranslate}}
widgets.maps.data-layer.circle.circle-key
-
-
+
+
+
+ +
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/map/map-data-layers.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/map/map-data-layers.component.ts index 747ef21681..6ddc984fc4 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/map/map-data-layers.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/map/map-data-layers.component.ts @@ -38,6 +38,7 @@ import { } from '@shared/models/widget/maps/map.models'; import { MapSettingsComponent } from '@home/components/widget/lib/settings/common/map/map-settings.component'; import { MapSettingsContext } from '@home/components/widget/lib/settings/common/map/map-settings.component.models'; +import { CdkDragDrop } from '@angular/cdk/drag-drop'; @Component({ selector: 'tb-map-data-layers', @@ -79,6 +80,10 @@ export class MapDataLayersComponent implements ControlValueAccessor, OnInit, Val noDataLayersText: string; + get dragEnabled(): boolean { + return this.dataLayersFormArray().controls.length > 1; + } + private propagateChange = (_val: any) => {}; constructor(private mapSettingsComponent: MapSettingsComponent, @@ -162,6 +167,13 @@ export class MapDataLayersComponent implements ControlValueAccessor, OnInit, Val removeDataLayer(index: number) { (this.dataLayersFormGroup.get('dataLayers') as UntypedFormArray).removeAt(index); } + + layerDrop(event: CdkDragDrop) { + const layersArray = this.dataLayersFormArray(); + const layer = layersArray.at(event.previousIndex); + layersArray.removeAt(event.previousIndex); + layersArray.insert(event.currentIndex, layer); + } addDataLayer() { const dataLayer = mergeDeep({} as MapDataLayerSettings, diff --git a/ui-ngx/src/app/modules/home/home.component.html b/ui-ngx/src/app/modules/home/home.component.html index 48b6105bf9..3d4e35f1d0 100644 --- a/ui-ngx/src/app/modules/home/home.component.html +++ b/ui-ngx/src/app/modules/home/home.component.html @@ -62,6 +62,7 @@ placeholder="{{ 'common.enter-search' | translate }}"/>
+
- - + + {{ recipientTitle }} - - + +
diff --git a/ui-ngx/src/app/modules/home/pages/notification/template/configuration/notification-template-configuration.component.ts b/ui-ngx/src/app/modules/home/pages/notification/template/configuration/notification-template-configuration.component.ts index ee92ec3539..c21603b240 100644 --- a/ui-ngx/src/app/modules/home/pages/notification/template/configuration/notification-template-configuration.component.ts +++ b/ui-ngx/src/app/modules/home/pages/notification/template/configuration/notification-template-configuration.component.ts @@ -95,6 +95,37 @@ export class NotificationTemplateConfigurationComponent implements OnDestroy, Co autofocus: false, branding: false, promotion: false, + setup: (editor) => { + editor.on('PostRender', function() { + const container = document.querySelector('.tox.tox-tinymce-aux'); + const styleSheet = document.createElement('style'); + styleSheet.innerText = ` + .tox-tiered-menu .tox-menu { + width: fit-content; + max-width: min(80%, 440px); + @media screen and (max-width: 510px) { + max-width: calc(100% - 64px); + } + media screen and (min-width: 511px) and (max-width: 548px) { + max-width: calc(100% - 84px); + } + media screen and (min-width: 549px) and (max-width: 599px) { + max-width: calc(100% - 104px); + } + } + .tox-tiered-menu .tox-menu .tox-collection__item-label { + word-break: normal; + } + @media screen and (max-width: 890px) { + .tox-tiered-menu > .tox-collection--list:not(:first-child) { + left: auto !important; + right: 0 !important; + } + } + `; + container.prepend(styleSheet); + }); + }, relative_urls: false, urlconverter_callback: (url) => url }; diff --git a/ui-ngx/src/app/modules/home/pages/profile/profile.component.html b/ui-ngx/src/app/modules/home/pages/profile/profile.component.html index 44eea5865e..f27bccdf4e 100644 --- a/ui-ngx/src/app/modules/home/pages/profile/profile.component.html +++ b/ui-ngx/src/app/modules/home/pages/profile/profile.component.html @@ -37,7 +37,7 @@
user.email - + {{ 'user.email-required' | translate }} diff --git a/ui-ngx/src/app/modules/home/pages/profile/profile.component.ts b/ui-ngx/src/app/modules/home/pages/profile/profile.component.ts index 7d1aa2aa4e..3a8b99f166 100644 --- a/ui-ngx/src/app/modules/home/pages/profile/profile.component.ts +++ b/ui-ngx/src/app/modules/home/pages/profile/profile.component.ts @@ -28,7 +28,7 @@ import { environment as env } from '@env/environment'; import { TranslateService } from '@ngx-translate/core'; import { ActionSettingsChangeLanguage } from '@core/settings/settings.actions'; import { ActivatedRoute } from '@angular/router'; -import { isDefinedAndNotNull, isNotEmptyStr } from '@core/utils'; +import { isDefinedAndNotNull, isNotEmptyStr, validateEmail } from '@core/utils'; import { getCurrentAuthUser } from '@core/auth/auth.selectors'; import { AuthService } from '@core/auth/auth.service'; import { UnitSystem, UnitSystems } from '@shared/models/unit.models'; @@ -66,7 +66,7 @@ export class ProfileComponent extends PageComponent implements OnInit, HasConfir private buildProfileForm() { this.profile = this.fb.group({ - email: ['', [Validators.required, Validators.email]], + email: ['', [Validators.required, validateEmail]], firstName: [''], lastName: [''], phone: [''], diff --git a/ui-ngx/src/app/modules/home/pages/security/authentication-dialog/email-auth-dialog.component.html b/ui-ngx/src/app/modules/home/pages/security/authentication-dialog/email-auth-dialog.component.html index 0175c85f56..6eba3f8cf7 100644 --- a/ui-ngx/src/app/modules/home/pages/security/authentication-dialog/email-auth-dialog.component.html +++ b/ui-ngx/src/app/modules/home/pages/security/authentication-dialog/email-auth-dialog.component.html @@ -39,7 +39,7 @@
{{ 'user.email-required' | translate }} diff --git a/ui-ngx/src/app/modules/home/pages/security/authentication-dialog/email-auth-dialog.component.ts b/ui-ngx/src/app/modules/home/pages/security/authentication-dialog/email-auth-dialog.component.ts index 601c2e9277..6ed9099522 100644 --- a/ui-ngx/src/app/modules/home/pages/security/authentication-dialog/email-auth-dialog.component.ts +++ b/ui-ngx/src/app/modules/home/pages/security/authentication-dialog/email-auth-dialog.component.ts @@ -28,6 +28,7 @@ import { TwoFactorAuthProviderType } from '@shared/models/two-factor-auth.models'; import { MatStepper } from '@angular/material/stepper'; +import { validateEmail } from '@app/core/utils'; export interface EmailAuthDialogData { email: string; @@ -57,7 +58,7 @@ export class EmailAuthDialogComponent extends DialogComponent { } onTenantProfileUpdated() { - this.entitiesTableConfig.updateData(false); + this.entitiesTableConfig.updateData(false, false); } } diff --git a/ui-ngx/src/app/modules/home/pages/user/user.component.html b/ui-ngx/src/app/modules/home/pages/user/user.component.html index 658b361255..a50f466027 100644 --- a/ui-ngx/src/app/modules/home/pages/user/user.component.html +++ b/ui-ngx/src/app/modules/home/pages/user/user.component.html @@ -76,7 +76,7 @@
user.email - + {{ 'user.invalid-email-format' | translate }} diff --git a/ui-ngx/src/app/modules/home/pages/user/user.component.ts b/ui-ngx/src/app/modules/home/pages/user/user.component.ts index da0a001b5d..8142f4823a 100644 --- a/ui-ngx/src/app/modules/home/pages/user/user.component.ts +++ b/ui-ngx/src/app/modules/home/pages/user/user.component.ts @@ -23,7 +23,7 @@ import { User } from '@shared/models/user.model'; import { selectAuth } from '@core/auth/auth.selectors'; import { map } from 'rxjs/operators'; import { Authority } from '@shared/models/authority.enum'; -import { isDefinedAndNotNull } from '@core/utils'; +import { isDefinedAndNotNull, validateEmail } from '@core/utils'; import { EntityTableConfig } from '@home/models/entity/entities-table-config.models'; import { ActionNotificationShow } from '@app/core/notification/notification.actions'; import { TranslateService } from '@ngx-translate/core'; @@ -33,7 +33,7 @@ import { TranslateService } from '@ngx-translate/core'; templateUrl: './user.component.html', styleUrls: ['./user.component.scss'] }) -export class UserComponent extends EntityComponent { +export class UserComponent extends EntityComponent{ authority = Authority; @@ -70,7 +70,7 @@ export class UserComponent extends EntityComponent { buildForm(entity: User): UntypedFormGroup { return this.fb.group( { - email: [entity ? entity.email : '', [Validators.required, Validators.email]], + email: [entity ? entity.email : '', [Validators.required, validateEmail]], firstName: [entity ? entity.firstName : ''], lastName: [entity ? entity.lastName : ''], phone: [entity ? entity.phone : ''], diff --git a/ui-ngx/src/app/modules/login/pages/login/login.component.html b/ui-ngx/src/app/modules/login/pages/login/login.component.html index 65b82023fe..c1a4b17a3c 100644 --- a/ui-ngx/src/app/modules/login/pages/login/login.component.html +++ b/ui-ngx/src/app/modules/login/pages/login/login.component.html @@ -43,7 +43,7 @@
login.username - + email {{ 'login.invalid-email-format' | translate }} diff --git a/ui-ngx/src/app/modules/login/pages/login/login.component.ts b/ui-ngx/src/app/modules/login/pages/login/login.component.ts index aa7642b654..a4bd2853b9 100644 --- a/ui-ngx/src/app/modules/login/pages/login/login.component.ts +++ b/ui-ngx/src/app/modules/login/pages/login/login.component.ts @@ -19,11 +19,12 @@ import { AuthService } from '@core/auth/auth.service'; import { Store } from '@ngrx/store'; import { AppState } from '@core/core.state'; import { PageComponent } from '@shared/components/page.component'; -import { UntypedFormBuilder } from '@angular/forms'; +import { UntypedFormBuilder, Validators } from '@angular/forms'; import { HttpErrorResponse } from '@angular/common/http'; import { Constants } from '@shared/models/constants'; import { Router } from '@angular/router'; import { OAuth2ClientLoginInfo } from '@shared/models/oauth2.models'; +import { validateEmail } from '@app/core/utils'; @Component({ selector: 'tb-login', @@ -35,8 +36,8 @@ export class LoginComponent extends PageComponent implements OnInit { passwordViolation = false; loginFormGroup = this.fb.group({ - username: '', - password: '' + username: ['', [Validators.required, validateEmail]], + password: [''] }); oauth2Clients: Array = null; diff --git a/ui-ngx/src/app/modules/login/pages/login/reset-password-request.component.html b/ui-ngx/src/app/modules/login/pages/login/reset-password-request.component.html index 96b85f2e47..abf2e6c61c 100644 --- a/ui-ngx/src/app/modules/login/pages/login/reset-password-request.component.html +++ b/ui-ngx/src/app/modules/login/pages/login/reset-password-request.component.html @@ -33,7 +33,7 @@ login.email - + email {{ 'user.invalid-email-format' | translate }} diff --git a/ui-ngx/src/app/modules/login/pages/login/reset-password-request.component.ts b/ui-ngx/src/app/modules/login/pages/login/reset-password-request.component.ts index 98b3d97398..3daeaa693d 100644 --- a/ui-ngx/src/app/modules/login/pages/login/reset-password-request.component.ts +++ b/ui-ngx/src/app/modules/login/pages/login/reset-password-request.component.ts @@ -22,6 +22,7 @@ import { PageComponent } from '@shared/components/page.component'; import { UntypedFormBuilder, Validators } from '@angular/forms'; import { ActionNotificationShow } from '@core/notification/notification.actions'; import { TranslateService } from '@ngx-translate/core'; +import { validateEmail } from '@app/core/utils'; @Component({ selector: 'tb-reset-password-request', @@ -33,7 +34,7 @@ export class ResetPasswordRequestComponent extends PageComponent implements OnIn clicked: boolean = false; requestPasswordRequest = this.fb.group({ - email: ['', [Validators.email, Validators.required]] + email: ['', [Validators.required, validateEmail]], }, {updateOn: 'submit'}); constructor(protected store: Store, diff --git a/ui-ngx/src/app/shared/components/entity/entity-list.component.ts b/ui-ngx/src/app/shared/components/entity/entity-list.component.ts index 9d1de180e9..26f89076d5 100644 --- a/ui-ngx/src/app/shared/components/entity/entity-list.component.ts +++ b/ui-ngx/src/app/shared/components/entity/entity-list.component.ts @@ -209,16 +209,18 @@ export class EntityListComponent implements ControlValueAccessor, OnInit, OnChan this.searchText = ''; if (value != null && value.length > 0) { this.modelValue = [...value]; - this.entityService.getEntities(this.entityType, value).subscribe( - (entities) => { - this.entities = entities; + this.entityService.getEntities(this.entityType, value) + .subscribe(resolvedEntities => { + this.entities = resolvedEntities; this.entityListFormGroup.get('entities').setValue(this.entities); - if (this.syncIdsWithDB && this.modelValue.length !== entities.length) { - this.modelValue = entities.map(entity => entity.id.id); + if (this.syncIdsWithDB && this.modelValue.length !== this.entities.length) { + this.modelValue = this.entities.map(entity => entity.id.id); + if (!this.modelValue.length) { + this.modelValue = null; + } this.propagateChange(this.modelValue); } - } - ); + }); } else { this.entities = []; this.entityListFormGroup.get('entities').setValue(this.entities); diff --git a/ui-ngx/src/app/shared/components/entity/entity-subtype-list.component.html b/ui-ngx/src/app/shared/components/entity/entity-subtype-list.component.html index 6635921d7f..fb2888c636 100644 --- a/ui-ngx/src/app/shared/components/entity/entity-subtype-list.component.html +++ b/ui-ngx/src/app/shared/components/entity/entity-subtype-list.component.html @@ -47,7 +47,7 @@ (optionSelected)="selected($event)" [displayWith]="displayEntitySubtypeFn"> - +
diff --git a/ui-ngx/src/app/shared/components/file-input.component.html b/ui-ngx/src/app/shared/components/file-input.component.html index 105257dd24..1f46ea1e34 100644 --- a/ui-ngx/src/app/shared/components/file-input.component.html +++ b/ui-ngx/src/app/shared/components/file-input.component.html @@ -39,11 +39,13 @@ [flow]="flow.flowJs">
cloud_upload - {{ dropLabel }} - +
+ {{ dropLabel }} + +
diff --git a/ui-ngx/src/app/shared/components/phone-input.component.html b/ui-ngx/src/app/shared/components/phone-input.component.html index 6bf61ae4b8..e10800483b 100644 --- a/ui-ngx/src/app/shared/components/phone-input.component.html +++ b/ui-ngx/src/app/shared/components/phone-input.component.html @@ -27,7 +27,7 @@
- + {{ label }} - + {{ 'version-control.branch' | translate }} ; diff --git a/ui-ngx/src/app/shared/models/ai-model.models.ts b/ui-ngx/src/app/shared/models/ai-model.models.ts index d3b70f9a74..410f7ad900 100644 --- a/ui-ngx/src/app/shared/models/ai-model.models.ts +++ b/ui-ngx/src/app/shared/models/ai-model.models.ts @@ -110,6 +110,7 @@ export const AiModelMap = new Map'{{title}}' blev ikke slettet, fordi den bruges af følgende entiteter:", + "resources-are-in-use-text": "Ikke alle ressourcer blev slettet, fordi de bruges af andre entiteter.
Du kan se de refererede entiteter ved at klikke på knappen Referencer i den tilsvarende ressource-række.
Hvis du stadig ønsker at slette disse ressourcer, skal du vælge dem i tabellen nedenfor og klikke på knappen Slet valgte.", + "delete-resource-in-use-text": "Hvis du stadig ønsker at slette ressourcen, skal du klikke på knappen Slet alligevel." }, "javascript": { "add": "Tilføj JavaScript-ressource", @@ -4700,13 +4725,13 @@ "customer-cache-expiration-hint": "Angiver maksimumsinterval for gemte kundedata. 0 = aldrig udløber.", "customer-cache-expiration-required": "Cache udløbstid for kunder er påkrævet.", "customer-cache-expiration-range": "Udløbstiden skal være ≥ 0.", - "interval-start": "Interval start", - "interval-end": "Interval slut", + "interval-start": "Start af interval", + "interval-end": "Intervalslut", "time-unit": "Tidsenhed", - "fetch-mode": "Hentetilstand", + "fetch-mode": "Hentemåde", "order-by-timestamp": "Sorter efter tidsstempel", "limit": "Grænse", - "limit-hint": "Min: 2, maks: 1000. Vælg 'First' eller 'Last' for én post.", + "limit-hint": "Min. grænseværdi er 2, maks. 1000. Hvis du vil hente én enkelt post, skal du vælge hentemåde 'Første' eller 'Sidste'.", "limit-required": "Grænse er påkrævet.", "limit-range": "Grænsen skal være mellem 2 og 1000.", "time-unit-milliseconds": "Millisekunder", @@ -4714,9 +4739,9 @@ "time-unit-minutes": "Minutter", "time-unit-hours": "Timer", "time-unit-days": "Dage", - "time-value-range": "Værdien skal være mellem 1 og 2147483647.", - "start-interval-value-required": "Interval start er påkrævet.", - "end-interval-value-required": "Interval slut er påkrævet.", + "time-value-range": "Tilladt område er fra 1 til 2147483647.", + "start-interval-value-required": "Intervalstart er påkrævet.", + "end-interval-value-required": "Intervalslut er påkrævet.", "filter": "Filter", "switch": "Skift", "math-templatization-tooltip": "Understøtter templatisering via $[messageKey] og ${metadataKey}.", @@ -4759,7 +4784,7 @@ "copy-from": "Kopiér fra", "data-to-metadata": "Data til metadata", "metadata-to-data": "Metadata til data", - "use-regular-expression-hint": "Brug regulært udtryk for at kopiere nøgler efter mønster.\n\nTips:\nTryk 'Enter' for at bekræfte feltinput.\nTryk 'Backspace' for at slette felt. Flere felter understøttes.", + "use-regular-expression-hint": "Brug regulært udtryk til at kopiere nøgler efter mønster.\n\nTips og tricks:\nTryk på 'Enter' for at fuldføre indtastning af feltnavn.\nTryk på 'Backspace' for at slette feltnavn. Flere feltnavne understøttes.", "interval": "Interval", "interval-required": "Interval er påkrævet", "interval-hint": "Dedupliceringsinterval i sekunder.", @@ -4812,7 +4837,7 @@ "latest-telemetry": "Seneste telemetri", "add-telemetry-key": "Tilføj telemetrinøgle", "delete-from": "Slet fra", - "use-regular-expression-delete-hint": "Brug regulært udtryk til sletning efter mønster.\n\nTips:\nTryk 'Enter' for at bekræfte.\nTryk 'Backspace' for at slette.", + "use-regular-expression-delete-hint": "Brug regulært udtryk til at slette nøgler efter mønster.\n\nTips og tricks:\nTryk på 'Enter' for at afslutte feltindtastning.\nTryk på 'Backspace' for at slette feltnavn.\nFlere feltnavne understøttes.", "fetch-into": "Hent til", "attr-mapping": "Attributmapping:", "source-attribute": "Kildeattribut", @@ -4823,11 +4848,11 @@ "target-key-required": "Målnøgle er påkrævet.", "attr-mapping-required": "Mindst én mapping skal angives.", "fields-mapping": "Feltermapping", - "fields-mapping-hint": "Brug $entityId for at gemme afsenderens id.", + "fields-mapping-hint": "Hvis beskedfeltet er sat til $entityId, vil oprindelses-id for beskeden blive gemt i den angivne tabelkolonne.", "relations-query-config-direction-suffix": "afsender", "profile-name": "Profilnavn", - "fetch-circle-parameter-info-from-metadata-hint": "Metadatafelt '{{perimeterKeyName}}' skal være i formatet: {\"latitude\":48.196, \"longitude\":24.6532, \"radius\":100.0, \"radiusUnit\":\"METER\"}", - "fetch-poligon-parameter-info-from-metadata-hint": "Metadatafelt '{{perimeterKeyName}}' skal være i formatet: [[48.19736,24.65235],...]", + "fetch-circle-parameter-info-from-metadata-hint": "Metadatafeltet '{{perimeterKeyName}}' skal være i følgende format: {\"latitude\":48.196, \"longitude\":24.6532, \"radius\":100.0, \"radiusUnit\":\"METER\"}", + "fetch-poligon-parameter-info-from-metadata-hint": "Metadatafeltet '{{perimeterKeyName}}' skal være i følgende format: [[48.19736,24.65235],[48.19800,24.65060],...,[48.19849,24.65420]]", "short-templatization-tooltip": "Brug $[messageKey] og ${metadataKey} til at hente værdier.", "fields-mapping-required": "Mindst én feltmapping er påkrævet.", "at-least-one-field-required": "Mindst ét inputfelt skal have en værdi.", @@ -4918,8 +4943,8 @@ "mail-body-type": "Indholdstype", "body-type-template": "Indholdstypemønster", "reply-routing-configuration": "Svarrute-konfiguration", - "rpc-reply-routing-configuration-hint": "Konfiguration for at identificere tjeneste, session og anmodning i metadata.", - "reply-routing-configuration-hint": "Konfiguration for at identificere tjeneste og anmodning i metadata.", + "rpc-reply-routing-configuration-hint": "Disse konfigurationsparametre angiver metadata-nøglenavne, der bruges til at identificere tjenesten, sessionen og anmodningen til at sende et svar tilbage.", + "reply-routing-configuration-hint": "Disse konfigurationsparametre angiver metadata-nøglenavne, der bruges til at identificere tjenesten og anmodningen til at sende et svar tilbage.", "request-id-metadata-attribute": "Anmodnings-id", "service-id-metadata-attribute": "Tjeneste-id", "session-id-metadata-attribute": "Session-id", @@ -4947,7 +4972,7 @@ "value-required": "Værdi er påkrævet", "topic-pattern": "Emnemønster", "key-pattern": "Nøglemønster", - "key-pattern-hint": "Valgfri. Angiv partition eller nøgle til brug ved sending.", + "key-pattern-hint": "Valgfrit. Hvis et gyldigt partitionsnummer er angivet, vil det blive brugt ved afsendelse af posten. Hvis ingen partition er angivet, vil nøglen blive brugt i stedet. Hvis ingen af delene er angivet, tildeles en partition i en round-robin-rækkefølge.", "topic-pattern-required": "Emnemønster er påkrævet", "topic": "Emne", "topic-required": "Emne er påkrævet", @@ -4956,18 +4981,18 @@ "other-properties": "Andre egenskaber", "key": "Nøgle", "key-required": "Nøgle er påkrævet", - "retries": "Antal genforsøg ved fejl", - "min-retries-message": "Kun 0 genforsøg tilladt som minimum", - "batch-size-bytes": "Batchstørrelse i bytes", - "min-batch-size-bytes-message": "Minimum batchstørrelse er 0", - "linger-ms": "Buffer-tid lokalt (ms)", - "min-linger-ms-message": "Minimum 0 ms tilladt", - "buffer-memory-bytes": "Maks. bufferstørrelse (bytes)", - "min-buffer-memory-message": "Minimum bufferstørrelse er 0", - "memory-buffer-size-range": "Bufferstørrelse skal være mellem 0 og {{max}} KB", - "acks": "Antal kvitteringer", - "topic-arn-pattern": "ARN-emnemønster", - "topic-arn-pattern-required": "ARN-emnemønster er påkrævet", + "retries": "Antal automatiske forsøg ved fejl", + "min-retries-message": "Kun 0 som minimumsantal forsøg er tilladt.", + "batch-size-bytes": "Batchstørrelse ved afsendelse (i bytes)", + "min-batch-size-bytes-message": "Kun 0 som minimum batchstørrelse er tilladt.", + "linger-ms": "Tidsbuffer lokalt (ms)", + "min-linger-ms-message": "Kun 0 ms som minimumværdi er tilladt.", + "buffer-memory-bytes": "Maksimal klientbufferstørrelse (i bytes)", + "min-buffer-memory-message": "Kun 0 som minimum bufferstørrelse er tilladt.", + "memory-buffer-size-range": "Bufferstørrelsen skal være mellem 0 og {{max}} KB", + "acks": "Antal bekræftelser", + "topic-arn-pattern": "Emne-ARN-mønster", + "topic-arn-pattern-required": "Emne-ARN-mønster er påkrævet", "aws-access-key-id": "AWS Access Key ID", "aws-access-key-id-required": "AWS Access Key ID er påkrævet", "aws-secret-access-key": "AWS Secret Access Key", @@ -4987,35 +5012,35 @@ "password": "Adgangskode", "automatic-recovery": "Automatisk gendannelse", "connection-timeout-ms": "Forbindelsestimeout (ms)", - "min-connection-timeout-ms-message": "Minimum værdi er 0 ms", - "handshake-timeout-ms": "Handshake-timeout (ms)", - "min-handshake-timeout-ms-message": "Minimum værdi er 0 ms", + "min-connection-timeout-ms-message": "Kun 0 ms som minimumværdi er tilladt.", + "handshake-timeout-ms": "Tidsgrænse for håndtryk (ms)", + "min-handshake-timeout-ms-message": "Kun 0 ms som minimumværdi er tilladt.", "client-properties": "Klientegenskaber", - "queue-url-pattern": "Kø-URL mønster", - "queue-url-pattern-required": "Kø-URL mønster er påkrævet", + "queue-url-pattern": "Køens URL-mønster", + "queue-url-pattern-required": "Køens URL-mønster er påkrævet", "delay-seconds": "Forsinkelse (sekunder)", - "min-delay-seconds-message": "Minimum forsinkelse er 0 sekunder", - "max-delay-seconds-message": "Maksimal forsinkelse er 900 sekunder", + "min-delay-seconds-message": "Kun 0 sekunder som minimumværdi er tilladt.", + "max-delay-seconds-message": "Maksimum tilladt værdi er 900 sekunder.", "name": "Navn", - "name-required": "Navn er påkrævet", + "name-required": "Navn er påkrævet.", "queue-type": "Køtype", "sqs-queue-standard": "Standard", "sqs-queue-fifo": "FIFO", "gcp-project-id": "GCP-projekt-ID", "gcp-project-id-required": "GCP-projekt-ID er påkrævet", - "gcp-service-account-key": "GCP servicekonto-nøglefil", - "gcp-service-account-key-required": "GCP servicekonto-nøglefil er påkrævet", + "gcp-service-account-key": "GCP-servicekonto-nøglefil", + "gcp-service-account-key-required": "GCP-servicekonto-nøglefil er påkrævet", "pubsub-topic-name": "Emnenavn", "pubsub-topic-name-required": "Emnenavn er påkrævet", "message-attributes": "Beskedattributter", - "message-attributes-hint": "Brug ${metadataKey} for værdi fra metadata, $[messageKey] for værdi fra meddelelsesindhold i navn-/værdifelter", - "connect-timeout": "Forbindelsestimeout (sek)", - "connect-timeout-required": "Forbindelsestimeout er påkrævet.", - "connect-timeout-range": "Timeout skal være mellem 1 og 200.", + "message-attributes-hint": "Brug ${metadataKey} for værdi fra metadata, $[messageKey] for værdi fra beskedens indhold i felterne navn/værdi.", + "connect-timeout": "Forbindelsestidsgrænse (sek.)", + "connect-timeout-required": "Forbindelsestidsgrænse er påkrævet.", + "connect-timeout-range": "Forbindelsestidsgrænsen skal være mellem 1 og 200.", "client-id": "Klient-ID", - "client-id-hint": "Valgfri. Lad være tomt for automatisk generering. For at undgå konflikter i mikrotjenester, brug unikke ID’er.", - "append-client-id-suffix": "Tilføj service-ID som suffix til klient-ID", - "client-id-suffix-hint": "Valgfrit. Anvendes når \"Client ID\" er angivet eksplicit. Hvis valgt, tilføjes Service ID som et suffiks til Client ID. Hjælper med at undgå fejl, når platformen kører i microservices-tilstand.", + "client-id-hint": "Valgfrit. Lad stå tomt for automatisk genereret Klient-ID. Vær forsigtig ved angivelse af Klient-ID. De fleste MQTT-brokere tillader ikke flere forbindelser med samme Klient-ID. Hvis du forbinder til sådanne brokere, skal din MQTT Klient-ID være unik. Når platformen kører i mikroservicetilstand, startes en kopi af regelnoden i hver mikroservice. Dette vil automatisk føre til flere MQTT-klienter med samme ID og kan forårsage fejl i regelnoden. For at undgå sådanne fejl skal du aktivere \"Tilføj Service-ID som suffiks til Klient-ID\" nedenfor.", + "append-client-id-suffix": "Tilføj Service-ID som suffiks til Klient-ID", + "client-id-suffix-hint": "Valgfrit. Anvendes når \"Klient-ID\" er angivet manuelt. Hvis valgt, tilføjes Service-ID som suffiks til Klient-ID. Hjælper med at undgå fejl, når platformen kører i mikroservicetilstand.", "device-id": "Enheds-ID", "device-id-required": "Enheds-ID er påkrævet.", "clean-session": "Ren session", @@ -5043,23 +5068,23 @@ "private-key-password": "Adgangskode til privat nøgle", "use-system-smtp-settings": "Brug systemets SMTP-indstillinger", "use-metadata-dynamic-interval": "Brug dynamisk interval", - "metadata-dynamic-interval-hint": "Intervalstart og -slut felterne understøtter skabeloner. Brug $[messageKey] eller ${metadataKey}.", - "use-metadata-interval-patterns-hint": "Hvis valgt, bruges mønstre fra metadata eller data til interval.", + "metadata-dynamic-interval-hint": "Indtastningsfelterne for intervalstart og -slut understøtter skabelonbrug. Bemærk, at den indsatte skabelonværdi skal være angivet i millisekunder. Brug $[messageKey] for at hente værdi fra beskeden og ${metadataKey} for at hente værdi fra metadata.", + "use-metadata-interval-patterns-hint": "Hvis valgt, bruger regelnoden start- og slutmønstre for interval fra beskedens metadata eller data, forudsat at intervallerne er i millisekunder.", "use-message-alarm-data": "Brug alarmdata fra besked", "overwrite-alarm-details": "Overskriv alarmdetaljer", - "use-alarm-severity-pattern": "Brug mønster for alarmens alvorlighed", - "check-all-keys": "Tjek at alle specificerede felter er til stede", - "check-all-keys-hint": "Tjekker at alle nøgler findes i data og metadata.", - "check-relation-to-specific-entity": "Tjek relation til specifik enhed", - "check-relation-to-specific-entity-tooltip": "Tjekker om relation eksisterer til en specifik eller hvilken som helst enhed baseret på type og retning.", - "check-relation-hint": "Tjek for relation til bestemt eller vilkårlig enhed.", - "delete-relation-with-specific-entity": "Slet relation med specifik enhed", - "delete-relation-with-specific-entity-hint": "Sletter relation med en bestemt enhed. Ellers slettes alle matchende relationer.", - "delete-relation-hint": "Sletter relation fra oprindelsen til den angivne enhed eller liste af enheder.", + "use-alarm-severity-pattern": "Brug mønster for alarmens alvorlighedsgrad", + "check-all-keys": "Tjek, at alle angivne felter er til stede", + "check-all-keys-hint": "Hvis valgt, kontrolleres det, at alle angivne nøgler er til stede i beskeddata og metadata.", + "check-relation-to-specific-entity": "Tjek relation til specifik entitet", + "check-relation-to-specific-entity-tooltip": "Hvis aktiveret, kontrolleres tilstedeværelsen af relation til en specifik entitet. Ellers kontrolleres tilstedeværelsen af relation til en vilkårlig entitet. I begge tilfælde foretages relationsopslag baseret på konfigureret retning og type.", + "check-relation-hint": "Kontrollerer eksistensen af relation til en specifik eller vilkårlig entitet baseret på retning og relationstype.", + "delete-relation-with-specific-entity": "Slet relation til specifik entitet", + "delete-relation-with-specific-entity-hint": "Hvis aktiveret, slettes kun relationen til én specifik entitet. Ellers fjernes relationer til alle matchende entiteter.", + "delete-relation-hint": "Sletter relation fra afsenderen af den indgående besked til den angivne entitet eller entitetsliste baseret på retning og type.", "remove-current-relations": "Fjern nuværende relationer", - "remove-current-relations-hint": "Fjerner nuværende relationer baseret på type og retning.", - "change-originator-to-related-entity": "Skift oprindelse til relateret enhed", - "change-originator-to-related-entity-hint": "Behandler beskeden som om den kommer fra en anden enhed.", + "remove-current-relations-hint": "Fjerner nuværende relationer fra afsenderen af den indgående besked baseret på retning og type.", + "change-originator-to-related-entity": "Skift afsender til relateret entitet", + "change-originator-to-related-entity-hint": "Anvendes til at behandle en besked som om den kommer fra en anden entitet.", "start-interval": "Interval start", "end-interval": "Interval slut", "start-interval-required": "Interval start er påkrævet.", @@ -5119,31 +5144,31 @@ "email-sender": "Email afsender", "fields-to-check": "Felter der skal kontrolleres", "add-detail": "Tilføj detalje", - "check-all-keys-tooltip": "Kontrollerer, at alle angivne felter findes i besked og metadata.", - "fields-to-check-hint": "Tryk på \"Enter\" for at afslutte. Flere felter understøttes.", - "entity-details-list-empty": "Mindst én detalje skal vælges.", + "check-all-keys-tooltip": "Hvis aktiveret, kontrolleres tilstedeværelsen af alle felter, der er angivet i besked- og metadatafeltnavne, i den indgående besked og dens metadata.", + "fields-to-check-hint": "Tryk på \"Enter\" for at afslutte indtastning af feltnavn. Flere feltnavne understøttes.", + "entity-details-list-empty": "Mindst ét detaljefelt skal vælges.", "alarm-status": "Alarmstatus", "alarm-required": "Mindst én alarmstatus skal vælges.", - "no-entity-details-matching": "Ingen tilsvarende entitetsdetaljer fundet.", - "custom-table-name": "Brugertabelnavn", + "no-entity-details-matching": "Ingen matchende entitetsdetaljer blev fundet.", + "custom-table-name": "Brugertilpasset tabelnavn", "custom-table-name-required": "Tabelnavn er påkrævet", - "custom-table-hint": "Skal starte med 'cs_tb_'. Angiv uden præfikset.", + "custom-table-hint": "Tabellen skal være oprettet i din Cassandra-klynge, og dens navn skal starte med præfikset 'cs_tb_' for at undgå indsættelse af data i de fælles TB-tabeller. Indtast tabelnavnet her uden 'cs_tb_'-præfikset.", "message-field": "Beskedfelt", "message-field-required": "Beskedfelt er påkrævet.", "table-col": "Tabelkolonne", "table-col-required": "Tabelkolonne er påkrævet.", - "latitude-field-name": "Navn på breddegradsfelt", - "longitude-field-name": "Navn på længdegradsfelt", - "latitude-field-name-required": "Navn på breddegradsfelt er påkrævet.", - "longitude-field-name-required": "Navn på længdegradsfelt er påkrævet.", - "fetch-perimeter-info-from-metadata": "Hent perimeteroplysninger fra metadata", - "fetch-perimeter-info-from-metadata-tooltip": "Parser metadatafelt for cirkel eller polygon afhængigt af perimeter-typen.", - "perimeter-key-name": "Perimeter nøgle navn", - "perimeter-key-name-hint": "Metadata felt med perimeter info.", - "perimeter-key-name-required": "Perimeter nøgle navn er påkrævet.", + "latitude-field-name": "Feltnavn for breddegrad", + "longitude-field-name": "Feltnavn for længdegrad", + "latitude-field-name-required": "Feltnavn for breddegrad er påkrævet.", + "longitude-field-name-required": "Feltnavn for længdegrad er påkrævet.", + "fetch-perimeter-info-from-metadata": "Hent perimeterinformation fra metadata", + "fetch-perimeter-info-from-metadata-tooltip": "Hvis perimeter-typen er sat til 'Polygon', vil værdien af metadatafeltet '{{perimeterKeyName}}' blive brugt direkte som definitionsværdi uden yderligere parsing. Hvis perimeter-typen er sat til 'Circle', vil værdien af '{{perimeterKeyName}}'-metadatafeltet blive parseret for at udtrække felterne 'latitude', 'longitude', 'radius', og 'radiusUnit', som bruges til at definere cirkelperimeteren.", + "perimeter-key-name": "Perimeter-nøgle", + "perimeter-key-name-hint": "Navn på metadatafelt, der indeholder perimeterinformation.", + "perimeter-key-name-required": "Perimeter-nøgle er påkrævet.", "perimeter-circle": "Cirkel", "perimeter-polygon": "Polygon", - "perimeter-type": "Perimeter type", + "perimeter-type": "Perimeter-type", "circle-center-latitude": "Cirkelens center breddegrad", "circle-center-latitude-required": "Center breddegrad er påkrævet.", "circle-center-longitude": "Cirkelens center længdegrad", @@ -5155,25 +5180,25 @@ "range-unit-nautical-mile": "Sømil", "range-units": "Afstandsenheder", "range-units-required": "Afstandsenheder er påkrævet.", - "range": "Rækkevidde", - "range-required": "Rækkevidde er påkrævet.", + "range": "Interval", + "range-required": "Interval er påkrævet.", "polygon-definition": "Polygondefinition", "polygon-definition-required": "Polygondefinition er påkrævet.", - "polygon-definition-hint": "Format: [[lat1,lon1],[lat2,lon2],...,[latN,lonN]].", + "polygon-definition-hint": "Brug følgende format til manuel definition af polygon: [[lat1,lon1],[lat2,lon2], ... ,[latN,lonN]].", "min-inside-duration": "Minimal varighed indenfor", - "min-inside-duration-value-required": "Værdi er påkrævet", + "min-inside-duration-value-required": "Minimal varighed indenfor er påkrævet", "min-inside-duration-time-unit": "Tidsenhed for minimal varighed indenfor", "min-outside-duration": "Minimal varighed udenfor", - "min-outside-duration-value-required": "Værdi er påkrævet", + "min-outside-duration-value-required": "Minimal varighed udenfor er påkrævet", "min-outside-duration-time-unit": "Tidsenhed for minimal varighed udenfor", - "tell-failure-if-absent": "Rapporter fejl ved fravær", - "tell-failure-if-absent-hint": "Hvis mindst én af de valgte nøgler ikke findes, vil udgående besked rapportere \"Fejl\".", - "get-latest-value-with-ts": "Hent tidsstempel for de seneste telemetriværdier", + "tell-failure-if-absent": "Rapportér fejl", + "tell-failure-if-absent-hint": "Hvis mindst én valgt nøgle ikke findes, vil den udgående besked rapportere \"Fejl\".", + "get-latest-value-with-ts": "Hent tidsstempel for seneste telemetriværdier", "get-latest-value-with-ts-hint": "Hvis valgt, vil de seneste telemetriværdier også inkludere tidsstempel, f.eks.: \"temp\": \"{\"ts\":1574329385897, \"value\":42}\"", "ignore-null-strings": "Ignorér tomme strenge", - "ignore-null-strings-hint": "Ignorerer felter med tomme værdier.", - "add-metadata-key-values-as-kafka-headers": "Tilføj nøgle-værdi par fra metadata til Kafka headers", - "add-metadata-key-values-as-kafka-headers-hint": "Hvis valgt, tilføjes metadataens nøgle-værdi par som byte arrays med foruddefineret tegnkodning.", + "ignore-null-strings-hint": "Hvis valgt, vil regelnoden ignorere entitetsfelter med tom værdi.", + "add-metadata-key-values-as-kafka-headers": "Tilføj metadata nøgle-værdi-par til Kafka header", + "add-metadata-key-values-as-kafka-headers-hint": "Hvis valgt, tilføjes nøgle-værdi-par fra beskedmetadata til headers i udgående Kafka-poster som byte-arrays med foruddefineret tegnkodning.", "charset-encoding": "Tegnkodning", "charset-encoding-required": "Tegnkodning er påkrævet.", "charset-us-ascii": "US-ASCII", @@ -5182,63 +5207,63 @@ "charset-utf-16be": "UTF-16BE", "charset-utf-16le": "UTF-16LE", "charset-utf-16": "UTF-16", - "select-queue-hint": "Vælg et kønavn fra rullemenu eller angiv et brugerdefineret navn.", - "device-profile-node-hint": "Nyttigt ved varighed eller gentagne betingelser for at sikre fortsat evaluering af alarmtilstand.", - "persist-alarm-rules": "Gem tilstand for alarmregler", - "persist-alarm-rules-hint": "Gemmer behandlingsstatus i databasen.", + "select-queue-hint": "Kønavnet kan vælges fra en rullemenu eller angives manuelt.", + "device-profile-node-hint": "Nyttigt, hvis du har varigheds- eller gentagelsesbetingelser for at sikre kontinuitet i evalueringen af alarmtilstand.", + "persist-alarm-rules": "Bevar tilstand for alarmregler", + "persist-alarm-rules-hint": "Hvis aktiveret, vil regelnoden gemme behandlingstilstanden i databasen.", "fetch-alarm-rules": "Hent tilstand for alarmregler", - "fetch-alarm-rules-hint": "Genskaber tilstand ved opstart for at sikre korrekt alarmstatus.", - "input-value-key": "Input nøgle", - "input-value-key-required": "Input nøgle er påkrævet.", - "output-value-key": "Output nøgle", - "output-value-key-required": "Output nøgle er påkrævet.", - "number-of-digits-after-floating-point": "Antal decimaler", - "number-of-digits-after-floating-point-range": "Antal decimaler skal være mellem 0 og 15.", - "failure-if-delta-negative": "Rapportér fejl ved negativ delta", - "failure-if-delta-negative-tooltip": "Fejl ved negativ forskel mellem værdier.", + "fetch-alarm-rules-hint": "Hvis aktiveret, vil regelnoden gendanne behandlingstilstanden ved initialisering og sikre, at alarmer udløses selv efter servergenstart. Ellers vil tilstanden blive gendannet, når den første besked fra enheden modtages.", + "input-value-key": "Inputværdinøgle", + "input-value-key-required": "Inputværdinøgle er påkrævet.", + "output-value-key": "Outputværdinøgle", + "output-value-key-required": "Outputværdinøgle er påkrævet.", + "number-of-digits-after-floating-point": "Antal decimaler efter komma", + "number-of-digits-after-floating-point-range": "Antallet af decimaler skal være mellem 0 og 15.", + "failure-if-delta-negative": "Rapportér fejl, hvis delta er negativ", + "failure-if-delta-negative-tooltip": "Regelnoden tvinger beskedbehandling til at fejle, hvis delta-værdien er negativ.", "use-caching": "Brug caching", - "use-caching-tooltip": "Regelknuden vil cache værdien af \"{{inputValueKey}}\" fra den indkommende besked for at forbedre ydeevnen. Bemærk, at cachen ikke opdateres, hvis \"{{inputValueKey}}\" ændres et andet sted.", + "use-caching-tooltip": "Regelnoden vil cache værdien af \"{{inputValueKey}}\", som modtages fra den indgående besked, for at forbedre ydeevnen. Bemærk, at cachen ikke opdateres, hvis du ændrer værdien af \"{{inputValueKey}}\" andre steder.", "add-time-difference-between-readings": "Tilføj tidsforskel mellem aflæsninger af \"{{inputValueKey}}\"", - "add-time-difference-between-readings-tooltip": "Hvis aktiveret, tilføjer regelknuden \"{{periodValueKey}}\" til den udgående besked.", - "period-value-key": "Tidsintervalnøgle", - "period-value-key-required": "Tidsintervalnøgle er påkrævet.", - "general-pattern-hint": "Brug ${metadataKey} for værdi fra metadata, $[messageKey] for værdi fra meddelelsesindhold.", - "alarm-severity-pattern-hint": "Brug ${metadataKey} for værdi fra metadata, $[messageKey] for værdi fra meddelelsesindhold. Alarmens alvorlighed skal være et systemniveau (CRITICAL, MAJOR osv.)", - "output-node-name-hint": "Regelknudens navn svarer til relationstypen for den udgående besked og bruges til at videresende beskeder til andre regelknuder i den kaldende regelkæde.", + "add-time-difference-between-readings-tooltip": "Hvis aktiveret, tilføjer regelnoden \"{{periodValueKey}}\" til den udgående besked.", + "period-value-key": "Periodeværdinøgle", + "period-value-key-required": "Periodeværdinøgle er påkrævet.", + "general-pattern-hint": "Brug ${metadataKey} for værdi fra metadata, $[messageKey] for værdi fra beskedens indhold.", + "alarm-severity-pattern-hint": "Brug ${metadataKey} for værdi fra metadata, $[messageKey] for værdi fra beskedens indhold. Alarmernes alvorlighed skal være systemdefineret (CRITICAL, MAJOR osv.)", + "output-node-name-hint": "Regelnodens navn svarer til relationstypen for den udgående besked og bruges til at videresende beskeder til andre regelnoder i den kaldende regelkæde.", "use-server-ts": "Brug serverens tidsstempel", - "use-server-ts-hint": "Brug serverens aktuelle tidsstempel for tidsseriedata, der mangler et eksplicit tidsstempel. Dette hjælper med korrekt rækkefølge, når der behandles beskeder fra flere kilder eller ved uordnet ankomst.", - "kv-map-pattern-hint": "Alle inputfelter understøtter skabelonisering. Brug $[messageKey] for værdi fra beskeden og ${metadataKey} for værdi fra metadata.", - "kv-map-single-pattern-hint": "Inputfelt understøtter skabelonisering. Brug $[messageKey] for værdi fra beskeden og ${metadataKey} for værdi fra metadata.", + "use-server-ts-hint": "Brug serverens aktuelle tidsstempel for tidsseriedata uden eksplicit tidsstempel. Dette hjælper med at bevare korrekt rækkefølge ved behandling af beskeder fra flere kilder eller når beskeder ankommer ude af rækkefølge.", + "kv-map-pattern-hint": "Alle inputfelter understøtter skabeloner. Brug $[messageKey] for værdi fra beskeden og ${metadataKey} for værdi fra metadata.", + "kv-map-single-pattern-hint": "Inputfeltet understøtter skabeloner. Brug $[messageKey] for værdi fra beskeden og ${metadataKey} for værdi fra metadata.", "shared-scope": "Delt område", "server-scope": "Serverområde", "client-scope": "Klientområde", - "attribute-type": "Attribute", - "attribute-type-description": "Hent attributværdi fra database", - "attribute-type-result-description": "Gem som attribut i database", + "attribute-type": "Attribut", + "attribute-type-description": "Hent attributværdi fra databasen", + "attribute-type-result-description": "Gem resultatet som en entitetsattribut i databasen", "constant-type": "Konstant", "constant-type-description": "Definér konstant værdi", "time-series-type": "Tidsserie", - "time-series-type-description": "Hent seneste værdi fra database", - "time-series-type-result-description": "Gem som tidsserie i database", + "time-series-type-description": "Hent seneste tidsserieværdi fra databasen", + "time-series-type-result-description": "Gem resultatet som en entitets tidsserie i databasen", "message-body-type": "Besked", - "message-body-type-description": "Hent argumentværdi fra besked", - "message-body-type-result-description": "Tilføj resultat til besked", + "message-body-type-description": "Hent argumentværdi fra den indgående besked", + "message-body-type-result-description": "Tilføj resultat til den udgående besked", "message-metadata-type": "Metadata", - "message-metadata-type-description": "Hent argumentværdi fra metadata", - "message-metadata-result-description": "Tilføj resultat til metadata", + "message-metadata-type-description": "Hent argumentværdi fra den indgående beskeds metadata", + "message-metadata-result-description": "Tilføj resultat til metadata for den udgående besked", "argument-tile": "Argumenter", "no-arguments-prompt": "Ingen argumenter konfigureret", "result-title": "Resultat", "functions-field-input": "Funktioner", - "no-option-found": "Ingen muligheder fundet", + "no-option-found": "Ingen valgmuligheder fundet", "argument-source-field-input": "Kilde", - "argument-source-field-input-required": "Kilde er påkrævet.", + "argument-source-field-input-required": "Argumentkilde er påkrævet.", "argument-key-field-input": "Nøgle", - "argument-key-field-input-required": "Nøgle er påkrævet.", + "argument-key-field-input-required": "Argumentnøgle er påkrævet.", "constant-value-field-input": "Konstant værdi", "constant-value-field-input-required": "Konstant værdi er påkrævet.", - "attribute-scope-field-input": "Attribut område", - "attribute-scope-field-input-required": "Område er påkrævet.", + "attribute-scope-field-input": "Attributområde", + "attribute-scope-field-input-required": "Attributområde er påkrævet.", "default-value-field-input": "Standardværdi", "type-field-input": "Type", "type-field-input-required": "Type er påkrævet.", @@ -5266,21 +5291,21 @@ "clear-selected-keys": "Ryd valgte nøgler", "geofence-configuration": "Geofence-konfiguration", "coordinate-field-names": "Koordinatfeltnavne", - "coordinate-field-hint": "Forsøger at hente felter fra besked. Hvis ikke til stede, bruges metadata.", + "coordinate-field-hint": "Regelnoden forsøger at hente de angivne felter fra beskeden. Hvis de ikke findes, vil den forsøge at hente dem fra metadata.", "presence-monitoring-strategy": "Strategi for tilstedeværelsesovervågning", "presence-monitoring-strategy-on-first-message": "Ved første besked", "presence-monitoring-strategy-on-each-message": "Ved hver besked", - "presence-monitoring-strategy-on-first-message-hint": "Rapporterer status 'Inde' eller 'Ude' ved første besked efter minimumsvarighed siden sidste status.", - "presence-monitoring-strategy-on-each-message-hint": "Rapporterer status ved hver besked efter statusændring.", + "presence-monitoring-strategy-on-first-message-hint": "Rapporterer tilstedeværelsesstatus 'Inde' eller 'Ude' ved første besked efter den konfigurerede minimumsvarighed er opnået siden sidste status 'Gået ind' eller 'Gået ud'.", + "presence-monitoring-strategy-on-each-message-hint": "Rapporterer tilstedeværelsesstatus 'Inde' eller 'Ude' ved hver besked efter statusopdatering 'Gået ind' eller 'Gået ud'.", "fetch-credentials-to": "Hent legitimationsoplysninger til", - "add-originator-attributes-to": "Tilføj afsenders attributter til", - "originator-attributes": "Afsenders attributter", - "fetch-latest-telemetry-with-timestamp": "Hent seneste telemetry med tidsstempel", - "fetch-latest-telemetry-with-timestamp-tooltip": "Inkluderer tidsstempel i metadata, f.eks.: \"{{latestTsKeyName}}\": \"{\"ts\":1574329385897, \"value\":42}\"", - "tell-failure": "Rapportér fejl hvis attribut mangler", - "tell-failure-tooltip": "Rapporterer fejl hvis mindst én valgt nøgle mangler.", - "created-time": "Oprettelsestid", - "chip-help": "Tryk på 'Enter' for at fuldføre {{inputName}}-indtastning. \nTryk på 'Backspace' for at slette {{inputName}}. \nFlere værdier understøttes.", + "add-originator-attributes-to": "Tilføj afsenderattributter til", + "originator-attributes": "Afsenderattributter", + "fetch-latest-telemetry-with-timestamp": "Hent seneste telemetri med tidsstempel", + "fetch-latest-telemetry-with-timestamp-tooltip": "Hvis valgt, tilføjes de seneste telemetriværdier med tidsstempel til metadata, f.eks.: \"{{latestTsKeyName}}\": \"{\\\"ts\\\":1574329385897, \\\"value\\\":42}\"", + "tell-failure": "Rapportér fejl, hvis en eller flere attributter mangler", + "tell-failure-tooltip": "Hvis mindst én valgt nøgle ikke findes, vil den udgående besked rapportere \"Fejl\".", + "created-time": "Oprettelsestidspunkt", + "chip-help": "Tryk på 'Enter' for at afslutte indtastning af {{inputName}}. \nTryk på 'Backspace' for at slette {{inputName}}. \nFlere værdier understøttes.", "detail": "detalje", "field-name": "feltnavn", "device-profile": "enhedsprofil", @@ -5291,19 +5316,19 @@ "first-name": "Fornavn", "last-name": "Efternavn", "label": "Etiket", - "originator-fields-mapping": "Afsender felttilknytning", - "add-mapped-originator-fields-to": "Tilføj mappede afsenderfelter til", + "originator-fields-mapping": "Kortlægning af afsenderfelter", + "add-mapped-originator-fields-to": "Tilføj kortlagte afsenderfelter til", "fields": "Felter", "skip-empty-fields": "Spring tomme felter over", - "skip-empty-fields-tooltip": "Tomme felter tilføjes ikke til uddata.", - "fetch-interval": "Hentningsinterval", - "fetch-strategy": "Hentningsstrategi", - "fetch-timeseries-from-to": "Hent tidsserier fra {{startInterval}} {{startIntervalTimeUnit}} siden til {{endInterval}} {{endIntervalTimeUnit}} siden.", - "fetch-timeseries-from-to-invalid": "Ugyldig hentning af tidsserier (\"Intervalstart\" skal være mindre end \"Intervalslut\").", - "use-metadata-dynamic-interval-tooltip": "Hvis valgt, vil rule node bruge dynamisk intervalstart og -slut baseret på mønstre i beskeden og metadata.", - "all-mode-hint": "Hvis hentningstilstand \"Alle\" er valgt, vil rule node hente telemetri fra intervallet med konfigurerbare forespørgselsparametre.", - "first-mode-hint": "Hvis hentningstilstand \"Første\" er valgt, vil rule node hente den telemetri, der ligger tættest på intervallets start.", - "last-mode-hint": "Hvis hentningstilstand \"Sidste\" er valgt, vil rule node hente den telemetri, der ligger tættest på intervallets slutning.", + "skip-empty-fields-tooltip": "Felter med tomme værdier tilføjes ikke til udgående besked eller metadata.", + "fetch-interval": "Henteinterval", + "fetch-strategy": "Hentestrategi", + "fetch-timeseries-from-to": "Hent tidsserie fra {{startInterval}} {{startIntervalTimeUnit}} siden til {{endInterval}} {{endIntervalTimeUnit}} siden.", + "fetch-timeseries-from-to-invalid": "Ugyldig tidsseriehentning (\"Interval start\" skal være mindre end \"Interval slut\").", + "use-metadata-dynamic-interval-tooltip": "Hvis valgt, bruger regelnoden dynamisk start og slut på intervallet baseret på besked- og metadatamønstre.", + "all-mode-hint": "Hvis hentemåde \"Alle\" er valgt, vil regelnoden hente telemetri fra hele intervallet baseret på konfigurerbare forespørgselsparametre.", + "first-mode-hint": "Hvis hentemåde \"Første\" er valgt, hentes den telemetri, der ligger tættest på intervalstarten.", + "last-mode-hint": "Hvis hentemåde \"Sidste\" er valgt, hentes den telemetri, der ligger tættest på intervalslutningen.", "ascending": "Stigende", "descending": "Faldende", "min": "Min", @@ -5312,39 +5337,39 @@ "sum": "Sum", "count": "Antal", "none": "Ingen", - "last-level-relation-tooltip": "Søger kun relationer på det maksimale niveau.", - "last-level-device-relation-tooltip": "Søger kun enheder på det maksimale niveau.", + "last-level-relation-tooltip": "Hvis valgt, vil regelnoden kun søge relaterede enheder på det niveau, der er angivet som maksimal relation.", + "last-level-device-relation-tooltip": "Hvis valgt, vil regelnoden kun søge relaterede enheder på det niveau, der er angivet som maksimal relation.", "data-to-fetch": "Data der skal hentes", - "mapping-of-customers": "Kundemapping", - "map-fields-required": "Alle felter skal udfyldes.", + "mapping-of-customers": "Kortlægning af kunde", + "map-fields-required": "Alle kortlægningsfelter er påkrævede.", "attributes": "Attributter", - "related-device-attributes": "Attributter for relateret enhed", + "related-device-attributes": "Attributter for relaterede enheder", "add-selected-attributes-to": "Tilføj valgte attributter til", "device-profiles": "Enhedsprofiler", - "mapping-of-tenant": "Tenant-mapping", + "mapping-of-tenant": "Kortlægning af tenant", "add-attribute-key": "Tilføj attributnøgle", "message-template": "Beskedskabelon", "message-template-required": "Beskedskabelon er påkrævet", "use-system-slack-settings": "Brug systemets Slack-indstillinger", "slack-api-token": "Slack API-token", "slack-api-token-required": "Slack API-token er påkrævet", - "keys-mapping": "Nøgletilknytning", + "keys-mapping": "Nøglekortlægning", "add-key": "Tilføj nøgle", "recipients": "Modtagere", - "message-subject-and-content": "Besked emne og indhold", - "template-rules-hint": "Brug $[messageKey] eller ${metadataKey} til værdier.", - "originator-customer-desc": "Brug kundens oprindelige afsender.", - "originator-tenant-desc": "Brug nuværende tenant.", - "originator-related-entity-desc": "Brug relateret entitet som afsender.", - "originator-alarm-originator-desc": "Brug alarmens afsender (kun hvis besked er alarm).", - "originator-entity-by-name-pattern-desc": "Find og brug entitet ud fra navn og type.", - "email-from-template-hint": "Brug $[messageKey] eller ${metadataKey} for at trække værdier.", - "recipients-block-main-hint": "Kommasepareret liste, understøtter templatization.", - "forward-msg-default-rule-chain": "Videresend besked til standard regelkæde", - "forward-msg-default-rule-chain-tooltip": "Bruger standard regelkæde for afsender eller konfigureret kæde.", - "exclude-zero-deltas": "Udelad nul-delta værdier", - "exclude-zero-deltas-hint": "Tilføj kun nøgle hvis værdi ikke er nul.", - "exclude-zero-deltas-time-difference-hint": "Tilføj kun hvis outputværdi ≠ 0.", + "message-subject-and-content": "Beskedens emne og indhold", + "template-rules-hint": "Begge inputfelter understøtter skabeloner. Brug $[messageKey] for værdi fra besked og ${metadataKey} for værdi fra metadata.", + "originator-customer-desc": "Brug kunde tilhørende beskedens afsender som ny afsender.", + "originator-tenant-desc": "Brug nuværende tenant som ny afsender.", + "originator-related-entity-desc": "Brug relateret enhed som ny afsender. Opslag baseret på konfigureret relationstype og retning.", + "originator-alarm-originator-desc": "Brug alarmens afsender som ny afsender. Kun hvis afsenderen er en alarmenhed.", + "originator-entity-by-name-pattern-desc": "Brug enhed hentet fra databasen som ny afsender. Opslag baseret på enhedstype og angivet navnemønster.", + "email-from-template-hint": "Brug $[messageKey] for værdi fra besked og ${metadataKey} for værdi fra metadata.", + "recipients-block-main-hint": "Kommasepareret adresseliste. Alle inputfelter understøtter skabeloner. Brug $[messageKey] for værdi fra besked og ${metadataKey} for værdi fra metadata.", + "forward-msg-default-rule-chain": "Videresend besked til afsenders standardregel-kæde", + "forward-msg-default-rule-chain-tooltip": "Hvis aktiveret, videresendes besked til afsenders standardregel-kæde, eller den i konfigurationen angivne, hvis ingen standard er defineret i enhedsprofilen.", + "exclude-zero-deltas": "Ekskludér nul-deltaer fra udgående besked", + "exclude-zero-deltas-hint": "Hvis aktiveret, tilføjes nøglen \"{{outputValueKey}}\" kun, hvis værdien ikke er nul.", + "exclude-zero-deltas-time-difference-hint": "Hvis aktiveret, tilføjes \"{{outputValueKey}}\" og \"{{periodValueKey}}\" kun, hvis \"{{outputValueKey}}\" ikke er nul.", "search-direction-from": "Fra afsender til målentitet", "search-direction-to": "Fra målentitet til afsender", "del-relation-direction-from": "Fra afsender", @@ -5354,33 +5379,33 @@ "function-name": "Funktionsnavn", "function-name-required": "Funktionsnavn er påkrævet.", "qualifier": "Kvalifikator", - "qualifier-hint": "Hvis kvalifikatoren ikke er angivet, vil standardkvalifikatoren \"$LATEST\" blive brugt.", + "qualifier-hint": "Hvis kvalifikator ikke er angivet, bruges standardkvalifikatoren \"$LATEST\".", "aws-credentials": "AWS-legitimationsoplysninger", - "connection-timeout": "Forbindelsestimeout", - "connection-timeout-required": "Forbindelsestimeout er påkrævet.", - "connection-timeout-min": "Minimum forbindelsestimeout er 0.", - "connection-timeout-hint": "Ventetid ved etablering af forbindelse. 0 betyder uendelig og frarådes.", - "request-timeout": "Anmodningstimeout", - "request-timeout-required": "Anmodningstimeout er påkrævet", - "request-timeout-min": "Minimum anmodningstimeout er 0", - "request-timeout-hint": "Ventetid for anmodning, før timeout. 0 betyder uendelig og frarådes.", + "connection-timeout": "Forbindelsestidsgrænse", + "connection-timeout-required": "Forbindelsestidsgrænse er påkrævet.", + "connection-timeout-min": "Minimum forbindelsestidsgrænse er 0.", + "connection-timeout-hint": "Tiden i sekunder, der ventes ved etablering af forbindelse, før timeout. En værdi på 0 betyder uendelig, hvilket ikke anbefales.", + "request-timeout": "Forespørgsels-timeout", + "request-timeout-required": "Forespørgsels-timeout er påkrævet.", + "request-timeout-min": "Minimum forespørgsels-timeout er 0.", + "request-timeout-hint": "Tiden i sekunder, der ventes på at gennemføre forespørgslen, før timeout. En værdi på 0 betyder uendelig, hvilket ikke anbefales.", "units": "Enheder", - "tell-failure-aws-lambda": "Rapportér fejl hvis AWS Lambda-funktion kaster en undtagelse", - "tell-failure-aws-lambda-hint": "Tvinger fejl hvis Lambda-funktionen fejler.", - "basic-mode": "Grundlæggende", + "tell-failure-aws-lambda": "Rapportér fejl, hvis AWS Lambda-funktion kaster en undtagelse", + "tell-failure-aws-lambda-hint": "Regelnoden tvinger fejl i beskedbehandling, hvis AWS Lambda-funktion udløser en undtagelse.", + "basic-mode": "Basis", "advanced-mode": "Avanceret", "save-time-series": { "processing-settings": "Behandlingsindstillinger", - "processing-settings-hint": "Definér hvordan beskeder behandles. Grundlæggende eller avancerede strategier.", - "advanced-settings-hint": "Vær forsigtig – visse kombinationer kan føre til uventet adfærd.", + "processing-settings-hint": "Definér, hvordan indgående beskeder behandles. Basisindstillinger lader dig vælge forudkonfigurerede strategier, mens avancerede indstillinger tillader valg af individuelle strategier for hver handling.", + "advanced-settings-hint": "Vær forsigtig ved konfiguration af behandlingsstrategier. Visse kombinationer kan føre til uforudset opførsel.", "strategy": "Strategi", - "deduplication-interval": "Deduplikeringsinterval", - "deduplication-interval-required": "Dedupliceringsinterval er påkrævet", - "deduplication-interval-min-max-range": "Skal være mellem 1 sekund og 1 dag", + "deduplication-interval": "Deduplikationsinterval", + "deduplication-interval-required": "Deduplikationsinterval er påkrævet", + "deduplication-interval-min-max-range": "Deduplikationsinterval skal være mindst 1 sekund og højst 1 dag", "strategy-type": { "every-message": "Ved hver besked", "skip": "Spring over", - "deduplicate": "Dedupliker", + "deduplicate": "Deduplikér", "web-sockets-only": "Kun WebSockets" }, "time-series": "Tidsserier", @@ -5390,17 +5415,17 @@ }, "save-attribute": { "processing-settings": "Behandlingsindstillinger", - "processing-settings-hint": "Definér hvordan beskeder behandles. Grundlæggende eller avancerede strategier.", - "advanced-settings-hint": "Vær forsigtig – visse kombinationer kan føre til uventet adfærd.", + "processing-settings-hint": "Definér, hvordan indgående beskeder behandles. Basisindstillinger lader dig vælge forudkonfigurerede strategier, mens avancerede indstillinger tillader valg af individuelle strategier for hver handling.", + "advanced-settings-hint": "Vær forsigtig ved konfiguration af behandlingsstrategier. Visse kombinationer kan føre til uforudset opførsel.", "strategy": "Strategi", - "deduplication-interval": "Deduplikeringsinterval", - "deduplication-interval-required": "Deduplikeringsinterval er påkrævet", - "deduplication-interval-min-max-range": "Skal være mellem 1 sekund og 1 dag", + "deduplication-interval": "Deduplikationsinterval", + "deduplication-interval-required": "Deduplikationsinterval er påkrævet", + "deduplication-interval-min-max-range": "Deduplikationsinterval skal være mindst 1 sekund og højst 1 dag", "scope": "Omfang", "strategy-type": { "every-message": "Ved hver besked", "skip": "Spring over", - "deduplicate": "Dedupliker", + "deduplicate": "Deduplikér", "web-sockets-only": "Kun WebSockets" }, "attributes": "Attributter" @@ -5432,32 +5457,33 @@ "ai": { "ai-model": "AI-model", "model": "Model", - "ai-model-hint": "Vælg den forudkonfigurerede AI-model til at behandle forespørgsler sendt af denne rule node, eller brug \"Opret ny\" for at konfigurere en ny.", - "prompt-settings": "Promptindstillinger", - "prompt-settings-hint": "Den valgfrie systemprompt angiver AI'ens generelle rolle og begrænsninger, mens brugerprompten definerer den specifikke opgave. Begge felter understøtter også skabelonfunktionalitet.", + "ai-model-hint": "Vælg den forudkonfigurerede AI-model til at behandle anmodninger sendt af denne regelnode, eller brug \"Opret ny\" for at konfigurere en ny.", + "prompt-settings": "Prompt-indstillinger", + "prompt-settings-hint": "Den valgfrie systemprompt angiver AI'ens generelle rolle og begrænsninger, mens brugerprompten definerer den specifikke opgave, der skal udføres. Begge felter understøtter også skabeloner.", "system-prompt": "Systemprompt", - "system-prompt-max-length": "Systemprompt må højst være 500000 tegn.", + "system-prompt-max-length": "Systemprompt må højst indeholde 500000 tegn.", "system-prompt-blank": "Systemprompt må ikke være tom.", "user-prompt": "Brugerprompt", "user-prompt-required": "Brugerprompt er påkrævet.", - "user-prompt-max-length": "Brugerprompt må højst være 500000 tegn.", + "user-prompt-max-length": "Brugerprompt må højst indeholde 500000 tegn.", "user-prompt-blank": "Brugerprompt må ikke være tom.", - "response-format": "Svarformat", + "response-format": "Svartype", "response-text": "Tekst", "response-json": "JSON", "response-json-schema": "JSON-skema", - "response-format-hint-TEXT": "Tillader modellen at generere vilkårlig tekst, som måske eller måske ikke er gyldig JSON. Hvis output ikke er gyldig JSON, bliver det automatisk pakket ind i en JSON med nøglen \"response\".", - "response-format-hint-JSON": "Modellen skal generere et svar, der er gyldig JSON. Hvis output ikke er gyldig JSON, bliver det automatisk pakket ind i en JSON med nøglen \"response\".", - "response-format-hint-JSON_SCHEMA": "Modellen skal generere en JSON, der matcher strukturen og datatyperne defineret i det angivne skema. Hvis output ikke er gyldig JSON, bliver det automatisk pakket ind i en JSON med nøglen \"response\".", - "response-json-schema-hint": "Selvom enhver gyldig JSON-skema kan indtastes, understøtter denne rule node kun et begrænset sæt funktioner. Se dokumentationen for detaljer.", + "response-format-hint-TEXT": "Tillader modellen at generere vilkårlig tekst, som muligvis ikke er et gyldigt JSON-objekt. Hvis output ikke er gyldigt JSON, vil det automatisk blive pakket ind i et JSON-objekt under nøglen \"response\".", + "response-format-hint-JSON": "Modellen skal generere et svar, der er gyldigt JSON. Hvis output ikke er gyldigt JSON, vil det automatisk blive pakket ind i et JSON-objekt under nøglen \"response\".", + "response-format-hint-JSON_SCHEMA": "Modellen skal generere JSON, der matcher den specifikke struktur og datatyper defineret i det angivne skema. Hvis output ikke er gyldigt JSON, vil det automatisk blive pakket ind i et JSON-objekt under nøglen \"response\".", + "response-json-schema-hint": "Selvom enhver gyldig JSON-skema kan indtastes, understøtter denne regelnode kun et begrænset sæt af dets funktioner. Se node-dokumentationen for detaljer.", "response-json-schema-required": "JSON-skema er påkrævet", "advanced-settings": "Avancerede indstillinger", "timeout": "Timeout", - "timeout-hint": "Maksimalt tidsrum at vente på svar \nfra AI-modellen, før forespørgslen afsluttes.", + "timeout-hint": "Maksimal ventetid på svar fra AI-modellen, før anmodningen afbrydes.", "timeout-required": "Timeout er påkrævet", "timeout-validation": "Skal være mellem 1 sekund og 10 minutter.", "force-acknowledgement": "Tving kvittering", - "force-acknowledgement-hint": "Hvis aktiveret, kvitteres der straks for den indgående besked. Modellens svar bliver derefter sat i kø som en separat, ny besked." + "force-acknowledgement-hint": "Hvis aktiveret, kvitteres den indgående besked straks. Modellens svar sættes derefter i kø som en separat, ny besked.", + "ai-resources": "AI-ressourcer" } }, "timezone": { @@ -5757,9 +5783,9 @@ "rule-engine-exceptions-ttl-days": "Rule Engine-undtagelser TTL dage", "rule-engine-exceptions-ttl-days-required": "Rule Engine-undtagelser TTL dage er påkrævet", "rule-engine-exceptions-ttl-days-range": "Rule Engine-undtagelser TTL dage må ikke være negativt", - "max-rule-node-executions-per-message": "Maksimalt antal regelnode-udførelser pr. besked", - "max-rule-node-executions-per-message-required": "Maksimalt antal regelnode-udførelser pr. besked er påkrævet.", - "max-rule-node-executions-per-message-range": "Maksimalt antal regelnode-udførelser pr. besked må ikke være negativt", + "max-rule-node-executions-per-message": "Maks. antal regelnodekørsler pr. besked", + "max-rule-node-executions-per-message-required": "Maks. antal regelnodekørsler pr. besked er påkrævet.", + "max-rule-node-executions-per-message-range": "Maks. antal regelnodekørsler pr. besked må ikke være negativ", "max-emails": "Maksimalt antal sendte e-mails", "max-emails-required": "Maksimalt antal sendte e-mails er påkrævet.", "max-emails-range": "Maksimalt antal sendte e-mails må ikke være negativt", @@ -5987,9 +6013,10 @@ "label": "Etiket", "value": "Værdi", "date": "Dato", - "show-date-time-interval": "Vis datotidsinterval", - "show-date-time-interval-hint": "Vis datotidsinterval i henhold til dataaggregering.", + "show-date-time-interval": "Vis dato-/tidsinterval", + "show-date-time-interval-hint": "Vis dato-/tidsinterval i henhold til dataaggregering.", "hide-zero-tooltip-values": "Skjul nulværdier", + "show-stack-total": "Vis totalværdi i stablet tilstand", "background-color": "Baggrundsfarve", "background-blur": "Baggrundssløring" }, @@ -6702,15 +6729,15 @@ "no-widgets-text": "Ingen widgets fundet", "management": "Widgetadministration", "editor": "Widget-editor", - "confirm-to-exit-editor-html": "Du har ikke gemt dine widgetindstillinger.
Er du sikker på, at du vil forlade denne side?", - "widget-type-not-found": "Problem med at indlæse widgetkonfiguration.
Den tilknyttede widgettype er sandsynligvis blevet fjernet.", + "confirm-to-exit-editor-html": "Du har ikke gemte widget-indstillinger.
Er du sikker på, at du vil forlade denne side?", + "widget-type-not-found": "Problem med indlæsning af widget-konfiguration.
Den tilknyttede widget-type er\n sandsynligvis blevet fjernet.", "widget-type-load-error": "Widget blev ikke indlæst på grund af følgende fejl:", "remove": "Fjern widget", "delete": "Slet widget", "edit": "Rediger widget", "remove-widget-title": "Er du sikker på, at du vil fjerne widgetten '{{widgetTitle}}'?", - "remove-widget-text": "Efter bekræftelse vil widgetten og alle tilknyttede data ikke kunne gendannes.", - "replace-reference-with-widget-copy": "Erstat reference med kopi af widget", + "remove-widget-text": "Efter bekræftelse bliver widgetten og alle relaterede data uigenkaldeligt slettet.", + "replace-reference-with-widget-copy": "Erstat reference med en kopi af widget", "timeseries": "Tidsserier", "search-data": "Søg data", "no-data-found": "Ingen data fundet", @@ -7550,8 +7577,8 @@ "October": "Oktober", "November": "November", "December": "December", - "Custom Date Range": "Brugerdefineret datoområde", - "Date Range Template": "Skabelon for datoområde", + "Custom Date Range": "Brugerdefineret datointerval", + "Date Range Template": "Datointervalskabelon", "Today": "I dag", "Yesterday": "I går", "This Week": "Denne uge", @@ -7572,7 +7599,7 @@ "Custom interval": "Brugerdefineret interval", "Interval": "Interval", "Step size": "Trinstørrelse", - "Ok": "OK" + "Ok": "Ok" } }, "doughnut": { @@ -7784,11 +7811,11 @@ "gpio-switches": "GPIO-kontakter", "no-gpio-switches": "Ingen GPIO-kontakter konfigureret", "add-gpio-switch": "Tilføj GPIO-kontakt", - "gpio-status-request": "GPIO-statusanmodning", + "gpio-status-request": "GPIO-statusforespørgsel", "method-name": "Metodenavn", "method-body": "Metodeindhold", "gpio-status-change-request": "Anmodning om ændring af GPIO-status", - "parse-gpio-status-function": "Funktion til at fortolke GPIO-status", + "parse-gpio-status-function": "Parse-funktion for GPIO-status", "gpio-leds": "GPIO-LED'er", "no-gpio-leds": "Ingen GPIO-LED'er konfigureret", "add-gpio-led": "Tilføj GPIO-LED" @@ -9522,4 +9549,4 @@ "language": { "language": "Sprog" } -} +} \ No newline at end of file diff --git a/ui-ngx/src/assets/locale/locale.constant-de_DE.json b/ui-ngx/src/assets/locale/locale.constant-de_DE.json index 8df5966d60..4e3a41e488 100644 --- a/ui-ngx/src/assets/locale/locale.constant-de_DE.json +++ b/ui-ngx/src/assets/locale/locale.constant-de_DE.json @@ -163,39 +163,39 @@ "aws-secret-access-key-required": "AWS Secret Access Key ist erforderlich", "aws-region": "AWS-Region", "aws-region-required": "AWS-Region ist erforderlich", - "number-from": "Absendernummer", - "number-from-required": "Absendernummer ist erforderlich.", - "number-to": "Empfängernummer", - "number-to-required": "Empfängernummer ist erforderlich.", - "phone-number-hint": "Telefonnummer im E.164-Format, z. B. +19995550123", - "phone-number-hint-twilio": "Telefonnummer im E.164-Format/SID der Telefonnummer/Messaging Service SID, z. B. +19995550123/PNXXX/MGXXX", - "phone-number-pattern": "Ungültige Telefonnummer. Sollte im E.164-Format sein, z. B. +19995550123.", - "phone-number-pattern-twilio": "Ungültige Telefonnummer. Sollte im E.164-Format/SID der Telefonnummer/Messaging Service SID sein.", + "number-from": "Telefonnummer Von", + "number-from-required": "Telefonnummer Von ist erforderlich.", + "number-to": "Telefonnummer An", + "number-to-required": "Telefonnummer An ist erforderlich.", + "phone-number-hint": "Telefonnummer im E.164-Format, z. B. +19995550123", + "phone-number-hint-twilio": "Telefonnummer im E.164-Format/SID der Telefonnummer/SID des Messaging-Dienstes, z. B. +19995550123/PNXXX/MGXXX", + "phone-number-pattern": "Ungültige Telefonnummer. Sollte im E.164-Format vorliegen, z. B. +19995550123.", + "phone-number-pattern-twilio": "Ungültige Telefonnummer. Sollte im E.164-Format/SID der Telefonnummer/SID des Messaging-Dienstes vorliegen, z. B. +19995550123/PNXXX/MGXXX.", "sms-message": "SMS-Nachricht", "sms-message-required": "SMS-Nachricht ist erforderlich.", "sms-message-max-length": "SMS-Nachricht darf nicht länger als 1600 Zeichen sein", - "twilio-account-sid": "Twilio Account SID", - "twilio-account-sid-required": "Twilio Account SID ist erforderlich", - "twilio-account-token": "Twilio Account Token", - "twilio-account-token-required": "Twilio Account Token ist erforderlich", + "twilio-account-sid": "Twilio-Konto SID", + "twilio-account-sid-required": "Twilio-Konto SID ist erforderlich", + "twilio-account-token": "Twilio-Konto-Token", + "twilio-account-token-required": "Twilio-Konto-Token ist erforderlich", "send-test-sms": "Test-SMS senden", "test-sms-sent": "Test-SMS wurde erfolgreich gesendet!", "security-settings": "Sicherheitseinstellungen", "password-policy": "Passwortrichtlinie", "minimum-password-length": "Minimale Passwortlänge", "minimum-password-length-required": "Minimale Passwortlänge ist erforderlich", - "minimum-password-length-range": "Minimale Passwortlänge sollte zwischen 6 und 50 Zeichen liegen", + "minimum-password-length-range": "Die minimale Passwortlänge muss zwischen 6 und 50 liegen", "maximum-password-length": "Maximale Passwortlänge", - "maximum-password-length-min": "Maximale Passwortlänge sollte mindestens 6 betragen", - "maximum-password-length-less-min": "Maximale Passwortlänge muss größer als die minimale Länge sein", - "minimum-uppercase-letters": "Minimale Anzahl an Großbuchstaben", - "minimum-uppercase-letters-range": "Minimale Anzahl an Großbuchstaben darf nicht negativ sein", - "minimum-lowercase-letters": "Minimale Anzahl an Kleinbuchstaben", - "minimum-lowercase-letters-range": "Minimale Anzahl an Kleinbuchstaben darf nicht negativ sein", - "minimum-digits": "Minimale Anzahl an Ziffern", - "minimum-digits-range": "Minimale Anzahl an Ziffern darf nicht negativ sein", - "minimum-special-characters": "Minimale Anzahl an Sonderzeichen", - "minimum-special-characters-range": "Minimale Anzahl an Sonderzeichen darf nicht negativ sein", + "maximum-password-length-min": "Die maximale Passwortlänge muss mindestens 6 betragen", + "maximum-password-length-less-min": "Die maximale Passwortlänge muss größer als die minimale sein", + "minimum-uppercase-letters": "Mindestanzahl an Großbuchstaben", + "minimum-uppercase-letters-range": "Die Mindestanzahl an Großbuchstaben darf nicht negativ sein", + "minimum-lowercase-letters": "Mindestanzahl an Kleinbuchstaben", + "minimum-lowercase-letters-range": "Die Mindestanzahl an Kleinbuchstaben darf nicht negativ sein", + "minimum-digits": "Mindestanzahl an Ziffern", + "minimum-digits-range": "Die Mindestanzahl an Ziffern darf nicht negativ sein", + "minimum-special-characters": "Mindestanzahl an Sonderzeichen", + "minimum-special-characters-range": "Die Mindestanzahl an Sonderzeichen darf nicht negativ sein", "password-expiration-period-days": "Passwort-Ablaufzeitraum in Tagen", "password-expiration-period-days-range": "Passwort-Ablaufzeitraum darf nicht negativ sein", "password-reuse-frequency-days": "Häufigkeit der Passwortwiederverwendung in Tagen", @@ -676,8 +676,8 @@ "alias": { "add": "Alias hinzufügen", "edit": "Alias bearbeiten", - "name": "Aliasname", - "name-required": "Aliasname ist erforderlich", + "name": "Alias-Name", + "name-required": "Alias-Name ist erforderlich", "duplicate-alias": "Ein Alias mit demselben Namen existiert bereits.", "filter-type-single-entity": "Einzelne Entität", "filter-type-entity-list": "Entitätsliste", @@ -864,15 +864,15 @@ "api-features": "API-Funktionen", "api-usage": "API-Nutzung", "alarm": "Alarm", - "alarms-created": "Erstellte Alarme", + "alarms-created": "Alarme erstellt", "queue-stats": "Warteschlangenstatistiken", "processing-failures-and-timeouts": "Verarbeitungsfehler und Zeitüberschreitungen", "exceptions": "Ausnahmen", - "alarms-created-daily-activity": "Tägliche Aktivität der Alarmerstellung", - "alarms-created-hourly-activity": "Stündliche Aktivität der Alarmerstellung", - "alarms-created-monthly-activity": "Monatliche Aktivität der Alarmerstellung", + "alarms-created-daily-activity": "Tägliche Aktivität der Alarm-Erstellung", + "alarms-created-hourly-activity": "Stündliche Aktivität der Alarm-Erstellung", + "alarms-created-monthly-activity": "Monatliche Aktivität der Alarm-Erstellung", "data-points": "Datenpunkte", - "data-points-storage-days": "Speichertage der Datenpunkte", + "data-points-storage-days": "Speicherzeitraum der Datenpunkte (in Tagen)", "device-api": "Geräte-API", "email": "E-Mail", "email-messages": "E-Mail-Nachrichten", @@ -1111,13 +1111,15 @@ "mistral-ai": "Mistral AI", "anthropic": "Anthropic", "amazon-bedrock": "Amazon Bedrock", - "github-models": "GitHub-Modelle" + "github-models": "GitHub-Modelle", + "ollama": "Ollama" }, "name-required": "Name ist erforderlich.", "name-max-length": "Der Name darf höchstens 255 Zeichen lang sein.", "provider": "Anbieter", "api-key": "API-Schlüssel", "api-key-required": "API-Schlüssel ist erforderlich.", + "api-key-open-ai-required": "API-Schlüssel ist erforderlich, wenn die offizielle OpenAI-API verwendet wird.", "project-id": "Projekt-ID", "project-id-required": "Projekt-ID ist erforderlich.", "location": "Standort", @@ -1147,24 +1149,41 @@ "top-p-hint": "Erstellt einen Pool der wahrscheinlichsten Tokens, aus denen das Modell auswählt. Höhere Werte erweitern den Pool, niedrigere verkleinern ihn.", "top-p-min-max": "Muss größer als 0 und maximal 1 sein.", "top-k": "Top K", - "top-k-hint": "Begrenzt die Auswahl des Modells auf die „K“ wahrscheinlichsten Tokens.", + "top-k-hint": "Begrenzt die Auswahl des Modells auf die \"K\" wahrscheinlichsten Tokens.", "top-k-min": "Muss 0 oder größer sein.", - "presence-penalty": "Strafe für Anwesenheit", + "presence-penalty": "Präsenzstrafe", "presence-penalty-hint": "Wendet eine feste Strafe auf die Wahrscheinlichkeit eines Tokens an, wenn es bereits im Text erschienen ist.", - "frequency-penalty": "Strafe für Häufigkeit", - "frequency-penalty-hint": "Verringert die Wahrscheinlichkeit eines Tokens basierend auf seiner Häufigkeit im Text.", + "frequency-penalty": "Frequenzstrafe", + "frequency-penalty-hint": "Reduziert die Wahrscheinlichkeit eines Tokens abhängig von seiner Häufigkeit im Text.", "max-output-tokens": "Maximale Ausgabetokens", - "max-output-tokens-min": "Muss größer als 0 sein.", - "max-output-tokens-hint": "Legt die maximale Anzahl an Tokens fest, die das Modell in einer Antwort generieren kann.", + "max-output-tokens-hint": "Legt die maximale Anzahl an Tokens fest, die das \nModell in einer Antwort generieren kann.", + "context-length": "Kontextlänge", + "context-length-hint": "Definiert die Größe des Kontextfensters in Tokens. Dieser Wert legt das Gesamtspeicherlimit für das Modell fest – einschließlich Benutzereingabe und generierter Antwort.", "endpoint": "Endpunkt", "endpoint-required": "Endpunkt ist erforderlich.", + "baseurl": "Basis-URL", + "baseurl-required": "Basis-URL ist erforderlich.", "service-version": "Service-Version", "check-connectivity": "Konnektivität prüfen", "check-connectivity-success": "Testanfrage war erfolgreich", "check-connectivity-failed": "Testanfrage fehlgeschlagen", - "no-model-matching": "Keine mit '{{entity}}' übereinstimmenden Modelle gefunden.", + "no-model-matching": "Keine Modelle gefunden, die mit '{{entity}}' übereinstimmen.", "model-required": "Modell ist erforderlich.", - "no-model-text": "Keine Modelle gefunden." + "no-model-text": "Keine Modelle gefunden.", + "authentication": "Authentifizierung", + "authentication-basic-hint": "Verwendet die Standard-HTTP-Basis-Authentifizierung. Benutzername und Passwort werden kombiniert, Base64-codiert und im \"Authorization\"-Header an den Ollama-Server gesendet.", + "authentication-token-hint": "Verwendet die Bearer-Token-Authentifizierung. Das bereitgestellte Token wird direkt im \"Authorization\"-Header an den Ollama-Server gesendet.", + "authentication-type": { + "none": "Keine", + "basic": "Basis", + "token": "Token" + }, + "username": "Benutzername", + "username-required": "Benutzername ist erforderlich.", + "password": "Passwort", + "password-required": "Passwort ist erforderlich.", + "token": "Token", + "token-required": "Token ist erforderlich." }, "confirm-on-exit": { "message": "Sie haben ungespeicherte Änderungen. Möchten Sie diese Seite wirklich verlassen?", @@ -1228,7 +1247,7 @@ "required-fields": "Erforderliche Felder fehlen" }, "content-type": { - "json": "Json", + "json": "JSON", "text": "Text", "binary": "Binär (Base64)" }, @@ -1261,11 +1280,11 @@ "add-customer-text": "Neuen Kunden hinzufügen", "no-customers-text": "Keine Kunden gefunden", "customer-details": "Kundendetails", - "delete-customer-title": "Möchten Sie den Kunden '{{customerTitle}}' wirklich löschen?", - "delete-customer-text": "Achtung, nach der Bestätigung werden der Kunde und alle zugehörigen Daten unwiederbringlich gelöscht.", - "delete-customers-title": "Möchten Sie { count, plural, =1 {1 Kunden} other {# Kunden} } wirklich löschen?", + "delete-customer-title": "Sind Sie sicher, dass Sie den Kunden '{{customerTitle}}' löschen möchten?", + "delete-customer-text": "Achtung: Nach der Bestätigung werden der Kunde und alle zugehörigen Daten unwiderruflich gelöscht.", + "delete-customers-title": "Sind Sie sicher, dass Sie { count, plural, =1 {1 Kunden} other {# Kunden} } löschen möchten?", "delete-customers-action-title": "{ count, plural, =1 {1 Kunden löschen} other {# Kunden löschen} }", - "delete-customers-text": "Achtung, nach der Bestätigung werden alle ausgewählten Kunden und alle zugehörigen Daten gelöscht.", + "delete-customers-text": "Achtung: Nach der Bestätigung werden alle ausgewählten Kunden und deren zugehörige Daten unwiderruflich gelöscht.", "manage-users": "Benutzer verwalten", "manage-assets": "Assets verwalten", "manage-devices": "Geräte verwalten", @@ -1578,13 +1597,13 @@ "time-prev-description": "Zeitstempel des vorherigen Werts;", "prev-orig-value-description": "ursprünglicher vorheriger Wert;", "aggregation": "Aggregation", - "aggregation-type-hint-common": "Aus Leistungsgründen ist die Berechnung aggregierter Werte nur für feste Zeitintervalle wie 'heutiger Tag', 'aktueller Monat' usw. verfügbar, nicht jedoch für gleitende Zeitfenster wie 'letzte 30 Minuten'.", + "aggregation-type-hint-common": "Aus Leistungsgründen ist die Aggregationsberechnung nur für feste Zeitintervalle wie \"aktueller Tag\", \"aktueller Monat\" usw. verfügbar und nicht für gleitende Zeitfenster wie \"letzte 30 Minuten\" oder \"letzte 24 Stunden\".", "aggregation-type-none-hint": "Letzten Wert übernehmen.", - "aggregation-type-min-hint": "Mindestwert innerhalb des ausgewählten Zeitfensters finden.", - "aggregation-type-max-hint": "Höchstwert innerhalb des ausgewählten Zeitfensters finden.", - "aggregation-type-avg-hint": "Durchschnittswert innerhalb des ausgewählten Zeitfensters berechnen.", - "aggregation-type-sum-hint": "Alle Werte der Datenpunkte im Zeitfenster summieren.", - "aggregation-type-count-hint": "Gesamtanzahl der Datenpunkte im Zeitfenster.", + "aggregation-type-min-hint": "Minimalwert unter den Datenpunkten innerhalb eines ausgewählten Zeitfensters ermitteln.", + "aggregation-type-max-hint": "Maximalwert unter den Datenpunkten innerhalb eines ausgewählten Zeitfensters ermitteln.", + "aggregation-type-avg-hint": "Durchschnittswert der Datenpunkte innerhalb eines ausgewählten Zeitfensters berechnen.", + "aggregation-type-sum-hint": "Summe aller Werte der Datenpunkte innerhalb eines ausgewählten Zeitfensters berechnen.", + "aggregation-type-count-hint": "Gesamtanzahl der Datenpunkte innerhalb eines ausgewählten Zeitfensters.", "delta-calculation": "Delta-Berechnung", "enable-delta-calculation": "Delta-Berechnung aktivieren", "enable-delta-calculation-hint": "Wenn aktiviert, wird der Wert basierend auf aggregierten Werten für ein ausgewähltes Zeitfenster und einen Vergleichszeitraum berechnet. Delta-Berechnung ist nur für historische Zeitfenster verfügbar, nicht für Echtzeitwerte.", @@ -1991,19 +2010,19 @@ "create-new-device-profile": "Neues erstellen!", "mqtt-device-topic-filters": "MQTT-Gerät-Topic-Filter", "mqtt-device-topic-filters-unique": "MQTT-Gerät-Topic-Filter müssen eindeutig sein.", - "mqtt-device-topic-filters-spark-plug": "MQTT Sparkplug B Edge-of-Network (EoN) Node.", - "mqtt-device-topic-filters-spark-plug-hint": "Erlaubt Verbindungen von EoN-Nodes mit Sparkplug B Nutzlast und Topic-Format.", - "mqtt-device-topic-filters-spark-plug-attribute-metric-names": "SparkPlug-Metriken zur Speicherung als Attribute.", - "mqtt-device-topic-filters-spark-plug-attribute-metric-names-hint": "Namen der SparkPlug-Metriken, die als Geräteattribute gespeichert werden. Alle anderen Metriken werden als Telemetrie gespeichert.", - "mqtt-device-payload-type": "MQTT-Geräte-Nutzlast", + "mqtt-device-topic-filters-spark-plug": "MQTT Sparkplug B Edge-of-Network (EoN)-Knoten.", + "mqtt-device-topic-filters-spark-plug-hint": "Erlaubt Verbindungen von EoN-Knoten mit Sparkplug B Payload- und Topic-Format.", + "mqtt-device-topic-filters-spark-plug-attribute-metric-names": "SparkPlug-Metriken, die als Attribute gespeichert werden.", + "mqtt-device-topic-filters-spark-plug-attribute-metric-names-hint": "Namen der SparkPlug-Metriken, die als Geräteattribute gespeichert werden. Alle anderen Metriken werden als Gerätetelemetrie gespeichert.", + "mqtt-device-payload-type": "MQTT-Geräte-Payload", "mqtt-device-payload-type-json": "JSON", "mqtt-device-payload-type-proto": "Protobuf", - "mqtt-enable-compatibility-with-json-payload-format": "Kompatibilität mit anderen Nutzlast-Formaten aktivieren.", - "mqtt-enable-compatibility-with-json-payload-format-hint": "Wenn aktiviert, wird standardmäßig das Protobuf-Format verwendet. Bei Parsing-Fehlern wird JSON genutzt. Nützlich für die Abwärtskompatibilität bei Firmware-Updates. Dieser Modus kann die Leistung leicht beeinträchtigen und sollte nach Abschluss der Updates deaktiviert werden.", - "mqtt-use-json-format-for-default-downlink-topics": "JSON-Format für Standard-Downlink-Themen verwenden", - "mqtt-use-json-format-for-default-downlink-topics-hint": "Wenn aktiviert, wird das JSON-Format für die Standard-Downlink-Themen verwendet, z.B.: v1/devices/me/attributes/response/$request_id. Neue v2-Themen sind davon nicht betroffen.", - "mqtt-send-ack-on-validation-exception": "PUBACK bei Validierungsfehler senden", - "mqtt-send-ack-on-validation-exception-hint": "Standardmäßig wird die Sitzung bei einem Validierungsfehler geschlossen. Wenn aktiviert, wird stattdessen eine Bestätigung gesendet.", + "mqtt-enable-compatibility-with-json-payload-format": "Kompatibilität mit anderen Payload-Formaten aktivieren.", + "mqtt-enable-compatibility-with-json-payload-format-hint": "Wenn aktiviert, verwendet die Plattform standardmäßig das Protobuf-Payload-Format. Falls das Parsing fehlschlägt, versucht die Plattform, das JSON-Format zu verwenden. Nützlich für Abwärtskompatibilität bei Firmware-Updates. Beispielsweise nutzt die ursprüngliche Firmware-Version JSON, während die neue Version Protobuf verwendet. Während des Firmware-Update-Prozesses für die gesamte Geräteflotte ist es erforderlich, beide Formate gleichzeitig zu unterstützen. Der Kompatibilitätsmodus führt zu einer geringen Performanceeinbuße und sollte deaktiviert werden, sobald alle Geräte aktualisiert sind.", + "mqtt-use-json-format-for-default-downlink-topics": "JSON-Format für Standard-Downlink-Topics verwenden", + "mqtt-use-json-format-for-default-downlink-topics-hint": "Wenn aktiviert, verwendet die Plattform das JSON-Payload-Format zum Übertragen von Attributen und RPC über folgende Topics: v1/devices/me/attributes/response/$request_id, v1/devices/me/attributes, v1/devices/me/rpc/request/$request_id, v1/devices/me/rpc/response/$request_id. Diese Einstellung beeinflusst nicht die Verwendung neuer (v2) Topics: v2/a/res/$request_id, v2/a, v2/r/req/$request_id, v2/r/res/$request_id. Dabei ist $request_id ein ganzzahliger Anfrage-Identifier.", + "mqtt-send-ack-on-validation-exception": "PUBACK bei PUBLISH-Validierungsfehler senden", + "mqtt-send-ack-on-validation-exception-hint": "Standardmäßig beendet die Plattform die MQTT-Sitzung bei einem Validierungsfehler. Wenn aktiviert, sendet die Plattform stattdessen eine Bestätigung (PUBACK), anstatt die Sitzung zu schließen.", "mqtt-protocol-version": "Protokollversion", "snmp-add-mapping": "SNMP-Zuordnung hinzufügen", "snmp-mapping-not-configured": "Keine Zuordnung für OID zu Zeitreihen/Telemetrie konfiguriert", @@ -2038,11 +2057,11 @@ "rpc-request-proto-schema": "RPC-Anfrage-Protoschema", "rpc-request-proto-schema-required": "RPC-Anfrage-Protoschema ist erforderlich.", "rpc-request-proto-schema-hint": "RPC-Anforderungsnachrichten müssen die Felder 'string method = 1;', 'int32 requestId = 2;' und 'params = 3' enthalten.", - "not-valid-pattern-topic-filter": "Ungültiges Muster im Topic-Filter", - "not-valid-single-character": "Ungültige Verwendung eines Single-Level-Wildcards", - "not-valid-multi-character": "Ungültige Verwendung eines Multi-Level-Wildcards", - "single-level-wildcards-hint": "[+] kann jedes Topic-Level ersetzen. Beispiel: v1/devices/+/telemetry.", - "multi-level-wildcards-hint": "[#] ersetzt mehrere Ebenen und muss am Ende des Topics stehen. Beispiel: # oder v1/devices/me/#.", + "not-valid-pattern-topic-filter": "Ungültiges Topic-Filter-Muster", + "not-valid-single-character": "Ungültige Verwendung eines einstelligen Platzhalters", + "not-valid-multi-character": "Ungültige Verwendung eines mehrstufigen Platzhalters", + "single-level-wildcards-hint": "[+] eignet sich für jede Ebene eines Topic-Filters. Beispiel: v1/devices/+/telemetry oder +/devices/+/attributes.", + "multi-level-wildcards-hint": "[#] kann das gesamte Topic-Filter ersetzen und muss das letzte Symbol im Topic sein. Beispiel: # oder v1/devices/me/#.", "alarm-rules": "Alarmregeln", "alarm-rules-with-count": "Alarmregeln ({{count}})", "no-alarm-rules": "Keine Alarmregeln konfiguriert", @@ -2050,8 +2069,8 @@ "edit-alarm-rule": "Alarmregel bearbeiten", "alarm-type": "Alarmtyp", "alarm-type-required": "Alarmtyp ist erforderlich.", - "alarm-type-unique": "Alarmtyp muss innerhalb der Alarmregeln des Geräteprofils eindeutig sein.", - "alarm-type-max-length": "Alarmtyp sollte weniger als 256 Zeichen enthalten", + "alarm-type-unique": "Der Alarmtyp muss innerhalb der Geräteprofil-Alarmregeln eindeutig sein.", + "alarm-type-max-length": "Alarmtyp darf maximal 256 Zeichen lang sein", "create-alarm-pattern": "{{alarmType}} Alarm erstellen", "create-alarm-rules": "Alarmregeln erstellen", "no-create-alarm-rules": "Keine Erstellungsbedingungen konfiguriert", @@ -2072,16 +2091,16 @@ "advanced-settings": "Erweiterte Einstellungen", "alarm-rule-additional-info": "Zusätzliche Informationen", "edit-alarm-rule-additional-info": "Zusätzliche Informationen bearbeiten", - "alarm-rule-additional-info-placeholder": "Bitte Kommentare und Anpassungen angeben, die unter 'Zusätzliche Informationen' bei Alarmdetails angezeigt werden.", - "alarm-rule-additional-info-hint": "Hinweis: Verwenden Sie ${keyName} zur Ersetzung von Attribut- oder Telemetriedaten.", + "alarm-rule-additional-info-placeholder": "Bitte geben Sie hier Ihre Kommentare und Anpassungen ein, um sie unter 'Zusätzliche Informationen' in den Alarmdetails anzuzeigen.", + "alarm-rule-additional-info-hint": "Hinweis: Verwenden Sie ${keyName}, um Werte von Attribut- oder Telemetrie-Schlüsseln zu ersetzen, die in der Alarmregel-Bedingung verwendet werden.", "alarm-rule-mobile-dashboard": "Mobiles Dashboard", - "alarm-rule-mobile-dashboard-hint": "Wird von der mobilen App als Alarminformationen-Dashboard genutzt", + "alarm-rule-mobile-dashboard-hint": "Wird von der mobilen Anwendung als Dashboard für Alarmdetails verwendet", "alarm-rule-no-mobile-dashboard": "Kein Dashboard ausgewählt", - "propagate-alarm": "Alarm auf verbundene Entitäten propagieren", + "propagate-alarm": "Alarm an zugehörige Entitäten weiterleiten", "alarm-rule-relation-types-list": "Beziehungstypen", - "alarm-rule-relation-types-list-hint": "Definiert Beziehungstypen zur Filterung der verbundenen Entitäten. Wenn nicht gesetzt, wird der Alarm an alle verbundenen Entitäten propagiert.", - "propagate-alarm-to-owner": "Alarm an Eigentümer der Entität (Kunde oder Mandant) propagieren", - "propagate-alarm-to-tenant": "Alarm an Mandant propagieren", + "alarm-rule-relation-types-list-hint": "Definiert Beziehungstypen zur Filterung der zugehörigen Entitäten. Wenn nicht gesetzt, wird der Alarm an alle zugehörigen Entitäten weitergeleitet.", + "propagate-alarm-to-owner": "Alarm an Eigentümer der Entität weiterleiten (Kunde oder Tenant)", + "propagate-alarm-to-tenant": "Alarm an den Tenant weiterleiten", "alarm-rule-condition": "Alarmregelbedingung", "enter-alarm-rule-condition-prompt": "Bitte fügen Sie eine Alarmregelbedingung hinzu", "edit-alarm-rule-condition": "Alarmregelbedingung bearbeiten", @@ -2237,28 +2256,28 @@ "tqs": "TQS: Sowohl TCP- als auch SMS-Verbindungen aktiv; TCP im Queue-Modus, SMS im Standardmodus (nicht unterstützt seit LWM2M 1.1)", "sq": "SQ: SMS-Verbindung im Queue-Modus (nicht unterstützt seit LWM2M 1.1)" }, - "binding-tooltip": "Liste der unterstützten Bindungsmodi im \"binding\"-Ressourcenelement des LwM2M-Serverobjekts - /1/x/7.\nMehrere Übertragungsmodi sind möglich, aber nur einer wird während einer Transport-Session genutzt.", + "binding-tooltip": "Dies ist die Liste im \"binding\"-Ressourcenelement des LwM2M-Serverobjekts – /1/x/7.\nGibt die unterstützten Binding-Modi im LwM2M-Client an.\nDieser Wert SOLLTE mit dem Wert in der Ressource „Supported Binding and Modes“ im Geräteobjekt (/3/0/16) übereinstimmen.\nObwohl mehrere Transports unterstützt werden, kann während einer gesamten Transportsitzung nur ein Transport-Binding verwendet werden.\nBeispiel: Wenn sowohl UDP als auch SMS unterstützt werden, können der LwM2M-Client und der LwM2M-Server während der gesamten Transportsitzung entweder über UDP oder SMS kommunizieren.", "bootstrap-server": "Bootstrap-Server", "lwm2m-server": "LwM2M-Server", "include-bootstrap-server": "Bootstrap-Server-Updates einbeziehen", "bootstrap-update-title": "Bootstrap-Server ist bereits konfiguriert. Möchten Sie die Updates wirklich ausschließen?", - "bootstrap-update-text": "Vorsicht: Nach der Bestätigung gehen die Konfigurationsdaten des Bootstrap-Servers verloren.", + "bootstrap-update-text": "Achtung: Nach der Bestätigung werden die Konfigurationsdaten des Bootstrap-Servers unwiderruflich gelöscht.", "server-host": "Host", "server-host-required": "Host ist erforderlich.", "server-port": "Port", "server-port-required": "Port ist erforderlich.", - "server-port-pattern": "Port muss eine positive Ganzzahl sein.", - "server-port-range": "Port sollte im Bereich von 1 bis 65535 liegen.", + "server-port-pattern": "Port muss eine positive ganze Zahl sein.", + "server-port-range": "Port muss im Bereich von 1 bis 65535 liegen.", "server-public-key": "Öffentlicher Schlüssel des Servers", "server-public-key-required": "Öffentlicher Schlüssel des Servers ist erforderlich.", - "client-hold-off-time": "Wartezeit des Clients", - "client-hold-off-time-required": "Wartezeit des Clients ist erforderlich.", - "client-hold-off-time-pattern": "Wartezeit des Clients muss eine positive Ganzzahl sein.", - "client-hold-off-time-tooltip": "Client-Wartezeit nur bei Verwendung eines Bootstrap-Servers", - "account-after-timeout": "Konto nach Zeitüberschreitung", - "account-after-timeout-required": "Konto nach Zeitüberschreitung ist erforderlich.", - "account-after-timeout-pattern": "Konto nach Zeitüberschreitung muss eine positive Ganzzahl sein.", - "account-after-timeout-tooltip": "Wert für Konto nach Zeitüberschreitung beim Bootstrap-Server.", + "client-hold-off-time": "Verzögerungszeit (Hold Off Time)", + "client-hold-off-time-required": "Verzögerungszeit ist erforderlich.", + "client-hold-off-time-pattern": "Verzögerungszeit muss eine positive ganze Zahl sein.", + "client-hold-off-time-tooltip": "Verzögerungszeit für den Einsatz mit einem Bootstrap-Server", + "account-after-timeout": "Aktivierung nach Zeitüberschreitung", + "account-after-timeout-required": "Aktivierung nach Zeitüberschreitung ist erforderlich.", + "account-after-timeout-pattern": "Der Wert muss eine positive ganze Zahl sein.", + "account-after-timeout-tooltip": "Bootstrap-Server-Aktivierung nach dem durch diese Ressource angegebenen Timeout-Wert.", "server-type": "Servertyp", "add-new-server-title": "Neue Serverkonfiguration hinzufügen", "add-server-config": "Serverkonfiguration hinzufügen", @@ -2267,25 +2286,25 @@ "others-tab": "Weitere Einstellungen", "ota-update": "OTA-Update", "use-object-19-for-ota-update": "Objekt 19 für OTA-Dateimetadaten verwenden (Prüfsumme, Größe, Version, Name)", - "use-object-19-for-ota-update-hint": "Verwenden Sie Resource ObjectId = 19 für OTA-Updates: Firmware → InstanceId = 65534, Software → InstanceId = 65535. Das Datenformat ist JSON, codiert in Base64. Dieses JSON enthält OTA-Dateimetadaten (Dateiinformationen): „Checksum“ (SHA256). Zusätzliche Felder: „Title“ (OTA-Name), „Version“ (OTA-Version), „File Name“ (Dateiname zur Speicherung auf dem Client), „File Size“ (OTA-Größe in Bytes).", - "client-strategy": "Client-Strategie beim Verbinden", + "use-object-19-for-ota-update-hint": "Verwenden Sie Resource ObjectId = 19 für OTA-Updates: FirmWare → InstanceId = 65534, SoftWare → InstanceId = 65535. Das Datenformat ist JSON, eingebettet in Base64. Dieses JSON enthält OTA-Dateimetadaten (Dateiinformationen): \"Prüfsumme\" (SHA256). Zusätzliche Felder: \"Titel\" (OTA-Name), \"Version\" (OTA-Version), \"Dateiname\" (Dateiname für die Speicherung auf dem Client), \"Dateigröße\" (OTA-Größe in Byte).", + "client-strategy": "Client-Strategie beim Verbindungsaufbau", "client-strategy-label": "Strategie", - "client-strategy-only-observe": "Nur Beobachtungsanfragen nach der ersten Verbindung", - "client-strategy-read-all": "Alle Ressourcen lesen und beobachten nach der Registrierung", + "client-strategy-only-observe": "Nur Observe-Anfrage an den Client nach der ersten Verbindung", + "client-strategy-read-all": "Alle Ressourcen lesen und Observe-Anfrage nach der Registrierung senden", "fw-update": "Firmware-Update", - "fw-update-strategy": "Firmware-Update-Strategie", - "fw-update-strategy-data": "Firmware-Update als Binärdatei mit Objekt 19 und Ressource 0 (Daten) übertragen", - "fw-update-strategy-package": "Firmware-Update als Binärdatei mit Objekt 5 und Ressource 0 (Paket) übertragen", - "fw-update-strategy-package-uri": "Automatisch eindeutige CoAP-URL generieren, um das Paket herunterzuladen, und als Objekt 5 und Ressource 1 (Paket-URI) übertragen", + "fw-update-strategy": "Strategie für Firmware-Update", + "fw-update-strategy-data": "Firmware-Update als Binärdatei über Objekt 19 und Ressource 0 (Data) übertragen", + "fw-update-strategy-package": "Firmware-Update als Binärdatei über Objekt 5 und Ressource 0 (Package) übertragen", + "fw-update-strategy-package-uri": "Automatisch eindeutige CoAP-URL generieren und Firmware-Update über Objekt 5 und Ressource 1 (Package URI) übertragen", "sw-update": "Software-Update", - "sw-update-strategy": "Software-Update-Strategie", - "sw-update-strategy-package": "Binärdatei mit Objekt 9 und Ressource 2 (Paket) übertragen", - "sw-update-strategy-package-uri": "Automatisch eindeutige CoAP-URL generieren, um das Paket herunterzuladen, und Software-Update mit Objekt 9 und Ressource 3 (Paket-URI) übertragen", - "fw-update-resource": "Firmware-Update CoAP-Ressource", - "fw-update-resource-required": "Firmware-Update CoAP-Ressource ist erforderlich.", - "sw-update-resource": "Software-Update CoAP-Ressource", - "sw-update-resource-required": "Software-Update CoAP-Ressource ist erforderlich.", - "config-json-tab": "JSON-Konfigurationsprofil Gerät", + "sw-update-strategy": "Strategie für Software-Update", + "sw-update-strategy-package": "Binärdatei über Objekt 9 und Ressource 2 (Package) übertragen", + "sw-update-strategy-package-uri": "Automatisch eindeutige CoAP-URL generieren und Software-Update über Objekt 9 und Ressource 3 (Package URI) übertragen", + "fw-update-resource": "CoAP-Ressource für Firmware-Update", + "fw-update-resource-required": "CoAP-Ressource für Firmware-Update ist erforderlich.", + "sw-update-resource": "CoAP-Ressource für Software-Update", + "sw-update-resource-required": "CoAP-Ressource für Software-Update ist erforderlich.", + "config-json-tab": "JSON-Konfigurationsprofil für Gerät", "attributes-name": { "min-period": "Minimale Periode", "max-period": "Maximale Periode", @@ -2810,20 +2829,20 @@ "server-attributes-placeholder": "Server-Attribute", "timeseries-placeholder": "Zeitreihen", "target-entity": "Zielentität", - "attributes-propagation": "Attributübertragung", - "attributes-propagation-hint": "Die Entitätsansicht kopiert automatisch die angegebenen Attribute von der Zielentität jedes Mal, wenn Sie diese Entitätsansicht speichern oder aktualisieren. Aus Leistungsgründen werden Zielentitätsattribute nicht bei jeder Attributänderung auf die Entitätsansicht übertragen. Sie können die automatische Übertragung aktivieren, indem Sie einen 'copy to view'-Regelknoten in Ihrer Regelkette konfigurieren und 'Post attributes' und 'Attributes Updated'-Nachrichten an diesen neuen Regelknoten verlinken.", + "attributes-propagation": "Attributweiterleitung", + "attributes-propagation-hint": "Die Entitätsansicht kopiert automatisch die angegebenen Attribute von der Zielentität jedes Mal, wenn Sie diese Entitätsansicht speichern oder aktualisieren. Aus Leistungsgründen werden die Attribute der Zielentität nicht bei jeder Attributänderung automatisch in die Entitätsansicht übernommen. Sie können eine automatische Weiterleitung aktivieren, indem Sie den Regelknoten \"In Ansicht kopieren\" in Ihrer Regelkette konfigurieren und die Nachrichten \"Post attributes\" und \"Attributes Updated\" mit diesem neuen Regelknoten verknüpfen.", "timeseries-data": "Zeitreihendaten", - "timeseries-data-hint": "Konfigurieren Sie die Zeitreihendatenschlüssel der Zielentität, die für die Entitätsansicht zugänglich sein werden. Diese Zeitreihendaten sind schreibgeschützt.", - "search": "Entitätsansichten suchen", - "selected-entity-views": "{ count, plural, =1 {1 Entitätsansicht} other {# Entitätsansichten} } ausgewählt", - "assign-entity-view-to-edge": "Entitätsansicht(en) Edge zuweisen", - "assign-entity-view-to-edge-text": "Bitte wählen Sie die Entitätsansichten aus, die dem Edge zugewiesen werden sollen", - "unassign-entity-view-from-edge-title": "Sind Sie sicher, dass Sie die Entitätsansicht '{{entityViewName}}' von Edge entfernen möchten?", - "unassign-entity-view-from-edge-text": "Nach der Bestätigung wird die Entitätsansicht von Edge entfernt und ist nicht mehr zugänglich.", - "unassign-entity-views-from-edge-action-title": "{ count, plural, =1 {1 Entitätsansicht} other {# Entitätsansichten} } von Edge entfernen", - "unassign-entity-view-from-edge": "Entitätsansicht von Edge entfernen", - "unassign-entity-views-from-edge-title": "Sind Sie sicher, dass Sie { count, plural, =1 {1 Entitätsansicht} other {# Entitätsansichten} } von Edge entfernen möchten?", - "unassign-entity-views-from-edge-text": "Nach der Bestätigung werden alle ausgewählten Entitätsansichten von Edge entfernt und sind nicht mehr zugänglich." + "timeseries-data-hint": "Konfigurieren Sie die Zeitreihenschlüssel der Zielentität, die in der Entitätsansicht verfügbar sein sollen. Diese Zeitreihendaten sind schreibgeschützt.", + "search": "Entitätssichten suchen", + "selected-entity-views": "{ count, plural, =1 {1 Entitätssicht} other {# Entitätssichten} } ausgewählt", + "assign-entity-view-to-edge": "Entitätssicht(en) einer Edge zuweisen", + "assign-entity-view-to-edge-text": "Bitte wählen Sie die Entitätssichten aus, die der Edge zugewiesen werden sollen", + "unassign-entity-view-from-edge-title": "Möchten Sie die Entitätsansicht '{{entityViewName}}' wirklich von der Edge entfernen?", + "unassign-entity-view-from-edge-text": "Nach der Bestätigung wird die Entitätsansicht entfernt und ist auf der Edge nicht mehr verfügbar.", + "unassign-entity-views-from-edge-action-title": "{ count, plural, =1 {1 Entitätsansicht von der Edge entfernen} other {# Entitätssichten von der Edge entfernen} }", + "unassign-entity-view-from-edge": "Entitätsansicht entfernen", + "unassign-entity-views-from-edge-title": "Möchten Sie { count, plural, =1 {1 Entitätssicht} other {# Entitätssichten} } wirklich entfernen?", + "unassign-entity-views-from-edge-text": "Nach der Bestätigung werden alle ausgewählten Entitätssichten entfernt und sind auf der Edge nicht mehr verfügbar." }, "event": { "event-type": "Ereignistyp", @@ -3041,15 +3060,15 @@ "edit": "Filter bearbeiten", "name": "Filtername", "name-required": "Filtername ist erforderlich.", - "duplicate-filter": "Ein Filter mit demselben Namen existiert bereits.", + "duplicate-filter": "Ein Filter mit demselben Namen ist bereits vorhanden.", "filters": "Filter", "unable-delete-filter-title": "Filter kann nicht gelöscht werden", - "unable-delete-filter-text": "Der Filter '{{filter}}' kann nicht gelöscht werden, da er von folgenden Widget(s) verwendet wird:
{{widgetsList}}", - "duplicate-filter-error": "Doppelter Filter gefunden '{{filter}}'.
Filter müssen innerhalb des Dashboards eindeutig sein.", + "unable-delete-filter-text": "Filter '{{filter}}' kann nicht gelöscht werden, da er von folgendem/n Widget(s) verwendet wird:
{{widgetsList}}", + "duplicate-filter-error": "Doppelter Filter gefunden: '{{filter}}'.
Filter müssen innerhalb des Dashboards eindeutig sein.", "missing-key-filters-error": "Schlüsselfilter fehlt für Filter '{{filter}}'.", "filter": "Filter", "editable": "Bearbeitbar", - "editable-hint": "Benutzern erlauben, den Filterwert in Dashboards zu ändern.", + "editable-hint": "Ermöglicht dem Benutzer, den Filterwert in Dashboards zu ändern.", "no-filters-found": "Keine Filter gefunden.", "no-filter-text": "Kein Filter angegeben", "add-filter-prompt": "Bitte Filter hinzufügen", @@ -4303,7 +4322,7 @@ }, "profile": { "profile": "Profil", - "last-login-time": "Letzte Anmeldung", + "last-login-time": "Letzter Login", "change-password": "Passwort ändern", "current-password": "Aktuelles Passwort", "copy-jwt-token": "JWT-Token kopieren", @@ -4478,7 +4497,8 @@ "jks": "JKS", "js-module": "JS-Modul", "lwm2m-model": "LWM2M-Modell", - "pkcs-12": "PKCS #12" + "pkcs-12": "PKCS #12", + "general": "Allgemein" }, "resource-sub-type": "Subtyp", "sub-type": { @@ -4486,7 +4506,12 @@ "scada-symbol": "SCADA-Symbol", "extension": "Erweiterung", "module": "Modul" - } + }, + "resource-is-in-use": "Ressource wird von anderen Entitäten verwendet", + "resources-are-in-use": "Ressourcen werden von anderen Entitäten verwendet", + "resource-is-in-use-text": "Die Ressource '{{title}}' wurde nicht gelöscht, da sie von folgenden Entitäten verwendet wird:", + "resources-are-in-use-text": "Nicht alle Ressourcen wurden gelöscht, da sie von anderen Entitäten verwendet werden.
Sie können die referenzierten Entitäten anzeigen, indem Sie auf die Schaltfläche Referenzen in der entsprechenden Ressourcenzeile klicken.
Wenn Sie diese Ressourcen dennoch löschen möchten, wählen Sie sie in der Tabelle unten aus und klicken Sie auf die Schaltfläche Ausgewählte löschen.", + "delete-resource-in-use-text": "Wenn Sie die Ressource dennoch löschen möchten, klicken Sie auf die Schaltfläche Trotzdem löschen." }, "javascript": { "add": "JavaScript-Ressource hinzufügen", @@ -4742,24 +4767,24 @@ "send-attributes-deleted-notification": "Benachrichtigung bei gelöschten Attributen senden", "send-attributes-deleted-notification-hint": "Sendet Benachrichtigung über gelöschte Attribute als separate Nachricht an die Regelmaschinen-Warteschlange.", "update-attributes-only-on-value-change": "Attribute nur bei Wertänderung speichern", - "update-attributes-only-on-value-change-hint": "Aktualisiert Attribute bei jeder eingehenden Nachricht, unabhängig von Wertänderung. Erhöht API-Nutzung und verringert Leistung.", - "update-attributes-only-on-value-change-hint-enabled": "Aktualisiert Attribute nur bei Wertänderung. Keine Aktualisierung von Zeitstempel oder Änderungsbenachrichtigung bei gleichem Wert.", + "update-attributes-only-on-value-change-hint": "Aktualisiert die Attribute bei jeder eingehenden Nachricht, unabhängig davon, ob sich deren Wert geändert hat. Erhöht die API-Nutzung und verringert die Leistung.", + "update-attributes-only-on-value-change-hint-enabled": "Aktualisiert die Attribute nur, wenn sich deren Wert geändert hat. Wenn der Wert unverändert bleibt, werden weder der Attribut-Zeitstempel noch eine Änderungsbenachrichtigung gesendet.", "fetch-credentials-to-metadata": "Zugangsdaten in Metadaten übernehmen", - "notify-device-on-update-hint": "Wenn aktiviert, erzwingt Benachrichtigung an das Gerät bei Attribut-Update. Bei Deaktivierung erfolgt Steuerung über Metadatenparameter 'notifyDevice'.", - "notify-device-on-delete-hint": "Wenn aktiviert, erzwingt Benachrichtigung an das Gerät bei Attribut-Entfernung. Bei Deaktivierung erfolgt Steuerung über Metadatenparameter 'notifyDevice'.", - "latest-timeseries": "Neueste Zeitreihenschlüssel", + "notify-device-on-update-hint": "Wenn aktiviert, wird das Gerät über die Aktualisierung gemeinsamer Attribute zwangsweise benachrichtigt. Wenn deaktiviert, steuert das Metadatenfeld 'notifyDevice' im eingehenden Nachrichtenkontext das Benachrichtigungsverhalten. Um die Benachrichtigung zu deaktivieren, muss der Parameter 'notifyDevice' auf 'false' gesetzt sein. In allen anderen Fällen wird eine Benachrichtigung ausgelöst.", + "notify-device-on-delete-hint": "Wenn aktiviert, wird das Gerät über das Entfernen gemeinsamer Attribute zwangsweise benachrichtigt. Wenn deaktiviert, steuert das Metadatenfeld 'notifyDevice' im eingehenden Nachrichtenkontext das Verhalten. Um die Benachrichtigung zu aktivieren, muss der Parameter 'notifyDevice' auf 'true' gesetzt sein. In allen anderen Fällen wird keine Benachrichtigung gesendet.", + "latest-timeseries": "Neueste Zeitreihendatenschlüssel", "timeseries-keys": "Zeitreihenschlüssel", - "timeseries-keys-required": "Mindestens ein Zeitreihenschlüssel muss ausgewählt werden.", + "timeseries-keys-required": "Mindestens ein Zeitreihenschlüssel muss ausgewählt sein.", "add-timeseries-key": "Zeitreihenschlüssel hinzufügen", "add-message-field": "Nachrichtenfeld hinzufügen", - "relation-search-parameters": "Beziehungs-Suchparameter", + "relation-search-parameters": "Suchparameter für Beziehungen", "relation-parameters": "Beziehungsparameter", "add-metadata-field": "Metadatenfeld hinzufügen", "data-keys": "Feldnamen der Nachricht", "copy-from": "Kopieren von", "data-to-metadata": "Daten zu Metadaten", "metadata-to-data": "Metadaten zu Daten", - "use-regular-expression-hint": "Verwenden Sie reguläre Ausdrücke, um Schlüssel anhand eines Musters zu kopieren.\n\nTipps & Tricks:\nDrücken Sie 'Enter', um die Eingabe des Feldnamens abzuschließen.\nDrücken Sie 'Rücktaste', um den Feldnamen zu löschen. Mehrere Feldnamen werden unterstützt.", + "use-regular-expression-hint": "Verwenden Sie reguläre Ausdrücke, um Schlüssel anhand von Mustern zu kopieren.\n\nTipps & Tricks:\nDrücken Sie 'Enter', um die Eingabe eines Feldnamens abzuschließen.\nDrücken Sie 'Rücktaste', um einen Feldnamen zu löschen. Mehrere Feldnamen werden unterstützt.", "interval": "Intervall", "interval-required": "Intervall ist erforderlich", "interval-hint": "Deduplizierungsintervall in Sekunden.", @@ -4826,13 +4851,13 @@ "fields-mapping-hint": "Wenn das Nachrichtenfeld auf $entityId gesetzt ist, wird die ID des Absenders in die angegebene Spalte gespeichert.", "relations-query-config-direction-suffix": "Absender", "profile-name": "Profilname", - "fetch-circle-parameter-info-from-metadata-hint": "Das Metadatenfeld '{{perimeterKeyName}}' sollte folgendes Format haben: {\"latitude\":48.196, \"longitude\":24.6532, \"radius\":100.0, \"radiusUnit\":\"METER\"}", - "fetch-poligon-parameter-info-from-metadata-hint": "Das Metadatenfeld '{{perimeterKeyName}}' sollte folgendes Format haben: [[48.19736,24.65235],[48.19800,24.65060],...,[48.19849,24.65420]]", - "short-templatization-tooltip": "Verwenden Sie $[messageKey] für Nachrichtenwerte und ${metadataKey} für Metadatenwerte.", + "fetch-circle-parameter-info-from-metadata-hint": "Das Metadatenfeld '{{perimeterKeyName}}' muss im folgenden Format definiert sein: {\"latitude\":48.196, \"longitude\":24.6532, \"radius\":100.0, \"radiusUnit\":\"METER\"}", + "fetch-poligon-parameter-info-from-metadata-hint": "Das Metadatenfeld '{{perimeterKeyName}}' muss im folgenden Format definiert sein: [[48.19736,24.65235],[48.19800,24.65060],...,[48.19849,24.65420]]", + "short-templatization-tooltip": "Verwenden Sie $[messageKey], um einen Wert aus der Nachricht zu extrahieren, und ${metadataKey}, um einen Wert aus den Metadaten zu extrahieren.", "fields-mapping-required": "Mindestens eine Feldzuordnung muss angegeben werden.", "at-least-one-field-required": "Mindestens ein Eingabefeld muss einen Wert enthalten.", - "originator-fields-sv-map-hint": "Zielschlüsselfelder unterstützen Templatisierung. Verwenden Sie $[messageKey] oder ${metadataKey}.", - "sv-map-hint": "Nur Zielschlüsselfelder unterstützen Templatisierung. Verwenden Sie $[messageKey] oder ${metadataKey}.", + "originator-fields-sv-map-hint": "Zielschlüsselfelder unterstützen Templatisierung. Verwenden Sie $[messageKey], um einen Wert aus der Nachricht zu extrahieren, und ${metadataKey}, um einen Wert aus den Metadaten zu extrahieren.", + "sv-map-hint": "Nur Zielschlüsselfelder unterstützen Templatisierung. Verwenden Sie $[messageKey], um einen Wert aus der Nachricht zu extrahieren, und ${metadataKey}, um einen Wert aus den Metadaten zu extrahieren.", "source-field": "Quellfeld", "source-field-required": "Quellfeld ist erforderlich.", "originator-source": "Absenderquelle", @@ -5436,11 +5461,11 @@ "prompt-settings": "Prompt-Einstellungen", "prompt-settings-hint": "Der optionale System-Prompt definiert die allgemeine Rolle und Einschränkungen der KI, während der Benutzer-Prompt die spezifische Aufgabe beschreibt. Beide Felder unterstützen auch die Verwendung von Templates.", "system-prompt": "System-Prompt", - "system-prompt-max-length": "Der System-Prompt darf maximal 500.000 Zeichen lang sein.", + "system-prompt-max-length": "Der System-Prompt darf maximal 10.000 Zeichen lang sein.", "system-prompt-blank": "Der System-Prompt darf nicht leer sein.", "user-prompt": "Benutzer-Prompt", "user-prompt-required": "Benutzer-Prompt ist erforderlich.", - "user-prompt-max-length": "Der Benutzer-Prompt darf maximal 500.000 Zeichen lang sein.", + "user-prompt-max-length": "Der Benutzer-Prompt darf maximal 10.000 Zeichen lang sein.", "user-prompt-blank": "Der Benutzer-Prompt darf nicht leer sein.", "response-format": "Antwortformat", "response-text": "Text", @@ -5457,7 +5482,8 @@ "timeout-required": "Zeitüberschreitung ist erforderlich", "timeout-validation": "Muss zwischen 1 Sekunde und 10 Minuten liegen.", "force-acknowledgement": "Erzwinge Bestätigung", - "force-acknowledgement-hint": "Wenn aktiviert, wird die eingehende Nachricht sofort bestätigt. Die Antwort des Modells wird dann als separate, neue Nachricht eingereiht." + "force-acknowledgement-hint": "Wenn aktiviert, wird die eingehende Nachricht sofort bestätigt. Die Antwort des Modells wird dann als separate, neue Nachricht eingereiht.", + "ai-resources": "KI-Ressourcen" } }, "timezone": { @@ -5987,9 +6013,10 @@ "label": "Beschriftung", "value": "Wert", "date": "Datum", - "show-date-time-interval": "Datum/Zeit-Intervall anzeigen", - "show-date-time-interval-hint": "Datum/Zeit-Intervall gemäß Datenaggregation anzeigen.", + "show-date-time-interval": "Datums-/Zeitintervall anzeigen", + "show-date-time-interval-hint": "Zeigt das Datums-/Zeitintervall entsprechend der Datenaggregation an.", "hide-zero-tooltip-values": "Nullwerte ausblenden", + "show-stack-total": "Gesamtwert im Stapelmodus anzeigen", "background-color": "Hintergrundfarbe", "background-blur": "Hintergrundunschärfe" }, @@ -6556,10 +6583,10 @@ "no-users-text": "Keine Benutzer gefunden", "user-details": "Benutzerdetails", "delete-user-title": "Möchten Sie den Benutzer '{{userEmail}}' wirklich löschen?", - "delete-user-text": "Vorsicht! Nach der Bestätigung werden der Benutzer und alle zugehörigen Daten unwiederbringlich gelöscht.", - "delete-users-title": "Möchten Sie wirklich { count, plural, =1 {1 Benutzer} other {# Benutzer} } löschen?", + "delete-user-text": "Achtung: Nach der Bestätigung werden der Benutzer und alle zugehörigen Daten unwiederbringlich gelöscht.", + "delete-users-title": "Möchten Sie { count, plural, =1 {1 Benutzer} other {# Benutzer} } wirklich löschen?", "delete-users-action-title": "{ count, plural, =1 {1 Benutzer löschen} other {# Benutzer löschen} }", - "delete-users-text": "Vorsicht! Nach der Bestätigung werden alle ausgewählten Benutzer und zugehörige Daten gelöscht.", + "delete-users-text": "Achtung: Nach der Bestätigung werden alle ausgewählten Benutzer und ihre zugehörigen Daten unwiederbringlich entfernt.", "activation-email-sent-message": "Aktivierungs-E-Mail wurde erfolgreich gesendet!", "resend-activation": "Aktivierung erneut senden", "email": "E-Mail", @@ -6669,24 +6696,24 @@ "remove-all": "Alle entfernen", "version-create-result": "{ added, plural, =0 {Keine Entitäten} =1 {1 Entität} other {# Entitäten} } hinzugefügt.
{ modified, plural, =0 {Keine Entitäten} =1 {1 Entität} other {# Entitäten} } geändert.
{ removed, plural, =0 {Keine Entitäten} =1 {1 Entität} other {# Entitäten} } entfernt.", "remove-other-entities": "Andere Entitäten entfernen", - "find-existing-entity-by-name": "Vorhandene Entität nach Namen finden", + "find-existing-entity-by-name": "Bestehende Entität nach Name suchen", "restore-entities-from-version": "Entitäten aus Version '{{versionName}}' wiederherstellen", "restoring-entities-from-version": "Entitäten werden wiederhergestellt... Bitte warten", - "no-entities-restored": "Keine Entitäten wiederhergestellt", + "no-entities-restored": "Keine Entitäten wurden wiederhergestellt", "created": "{{created}} erstellt", "updated": "{{updated}} aktualisiert", "deleted": "{{deleted}} gelöscht", - "remove-other-entities-confirm-text": "Achtung! Dies wird alle aktuellen Entitäten dauerhaft löschen
die nicht in der wiederherzustellenden Version vorhanden sind.

Bitte geben Sie \"andere Entitäten entfernen\" ein, um zu bestätigen.", - "auto-commit-to-branch": "automatisch in {{ branch }}-Zweig übernehmen", - "default-create-entity-version-name": "{{entityName}} Aktualisierung", - "sync-strategy-merge-hint": "Erstellt oder aktualisiert ausgewählte Entitäten im Repository. Alle anderen Repository-Entitäten werden nicht verändert.", - "sync-strategy-overwrite-hint": "Erstellt oder aktualisiert ausgewählte Entitäten im Repository. Alle anderen Repository-Entitäten werden gelöscht.", - "device-credentials-conflict": "Gerät mit externer ID {{entityId}} konnte nicht geladen werden,
da dieselben Zugangsdaten bereits für ein anderes Gerät vorhanden sind.
Bitte erwägen Sie, die Einstellung Zugangsdaten laden im Wiederherstellungsformular zu deaktivieren.", - "missing-referenced-entity": "{{sourceEntityTypeName}} mit externer ID {{sourceEntityId}} konnte nicht geladen werden,
da sie auf eine fehlende {{targetEntityTypeName}} mit ID {{targetEntityId}} verweist.", + "remove-other-entities-confirm-text": "Achtung! Dies wird alle aktuellen Entitäten dauerhaft löschen,
die nicht in der wiederherzustellenden Version vorhanden sind.

Bitte geben Sie \"remove other entities\" ein, um zu bestätigen.", + "auto-commit-to-branch": "Auto-Commit in den Branch {{branch}}", + "default-create-entity-version-name": "{{entityName}}-Aktualisierung", + "sync-strategy-merge-hint": "Erstellt oder aktualisiert die ausgewählten Entitäten im Repository. Alle anderen Repository-Entitäten werden nicht verändert.", + "sync-strategy-overwrite-hint": "Erstellt oder aktualisiert die ausgewählten Entitäten im Repository. Alle anderen Repository-Entitäten werden gelöscht.", + "device-credentials-conflict": "Laden des Geräts mit externer ID {{entityId}} fehlgeschlagen,
da dieselben Zugangsdaten bereits für ein anderes Gerät in der Datenbank vorhanden sind.
Deaktivieren Sie ggf. die Option Zugangsdaten laden im Wiederherstellungsformular.", + "missing-referenced-entity": "Laden von {{sourceEntityTypeName}} mit externer ID {{sourceEntityId}} fehlgeschlagen,
da die referenzierte {{targetEntityTypeName}} mit ID {{targetEntityId}} fehlt.", "runtime-failed": "Fehlgeschlagen: {{message}}", - "auto-commit-settings-read-only-hint": "Auto-Commit funktioniert nicht, wenn die Option 'Nur-Lesen' in den Repository-Einstellungen aktiviert ist.", - "rollback-on-error": "Bei Fehler zurücksetzen", - "rollback-on-error-hint": "Wenn Sie eine große Menge an Entitäten wiederherstellen, deaktivieren Sie diese Option zur Leistungssteigerung.\nBeachten Sie, dass bei einem Fehler bereits gespeicherte Entitäten (mit Beziehungen, Attributen etc.) erhalten bleiben." + "auto-commit-settings-read-only-hint": "Die Auto-Commit-Funktion funktioniert nicht, wenn die Option 'Nur Lesen' in den Repository-Einstellungen aktiviert ist.", + "rollback-on-error": "Rollback bei Fehlern", + "rollback-on-error-hint": "Wenn Sie eine große Anzahl von Entitäten wiederherstellen, sollten Sie diese Option zur Leistungsverbesserung deaktivieren.\nHinweis: Im Fehlerfall bleiben bereits gespeicherte Entitäten (mit Beziehungen, Attributen usw.) erhalten." }, "widget": { "widget-library": "Widget-Bibliothek", @@ -6703,8 +6730,8 @@ "management": "Widget-Verwaltung", "editor": "Widget-Editor", "confirm-to-exit-editor-html": "Sie haben nicht gespeicherte Widget-Einstellungen.
Möchten Sie diese Seite wirklich verlassen?", - "widget-type-not-found": "Fehler beim Laden der Widget-Konfiguration.
Vermutlich wurde der zugehörige Widget-Typ entfernt.", - "widget-type-load-error": "Widget konnte aufgrund folgender Fehler nicht geladen werden:", + "widget-type-not-found": "Fehler beim Laden der Widget-Konfiguration.
Der zugehörige\n Widget-Typ wurde möglicherweise entfernt.", + "widget-type-load-error": "Widget konnte aufgrund der folgenden Fehler nicht geladen werden:", "remove": "Widget entfernen", "delete": "Widget löschen", "edit": "Widget bearbeiten", @@ -6769,11 +6796,11 @@ "javascript": "JavaScript", "js": "JS", "delete-widget-title": "Möchten Sie das Widget '{{widgetName}}' wirklich löschen?", - "delete-widget-text": "Nach der Bestätigung wird das Widget und alle zugehörigen Daten unwiederbringlich gelöscht.", - "delete-widgets-title": "Möchten Sie wirklich { count, plural, =1 {1 Widget} other {# Widgets} } löschen?", - "delete-widgets-text": "Nach der Bestätigung werden alle ausgewählten Widgets und alle zugehörigen Daten gelöscht.", + "delete-widget-text": "Nach der Bestätigung wird das Widget und alle zugehörigen Daten unwiderruflich gelöscht.", + "delete-widgets-title": "Möchten Sie { count, plural, =1 {1 Widget} other {# Widgets} } wirklich löschen?", + "delete-widgets-text": "Achtung: Nach der Bestätigung werden alle ausgewählten Widgets und deren zugehörige Daten unwiderruflich entfernt.", "delete-widget": "Widget löschen", - "widget-template-load-failed-error": "Widget-Vorlage konnte nicht geladen werden!", + "widget-template-load-failed-error": "Laden der Widget-Vorlage fehlgeschlagen!", "details": "Details", "widget-details": "Widget-Details", "add": "Widget hinzufügen", @@ -8572,15 +8599,15 @@ "fit-map-bounds": "Kartenausschnitt anpassen, um alle Marker abzudecken", "use-default-map-center-position": "Standard-Zentrum der Karte verwenden", "entities-limit": "Grenze für zu ladende Entitäten", - "markers-settings": "Marker-Einstellungen", - "marker-offset-x": "X-Versatz des Markers multipliziert mit Breite", - "marker-offset-y": "Y-Versatz des Markers multipliziert mit Höhe", - "position-function": "Positionsumrechnungsfunktion, sollte x,y-Koordinaten als Double (0-1) zurückgeben", - "draggable-marker": "Marker verschiebbar", + "markers-settings": "Markereinstellungen", + "marker-offset-x": "Marker-X-Versatz relativ zur Position multipliziert mit der Markerbreite", + "marker-offset-y": "Marker-Y-Versatz relativ zur Position multipliziert mit der Markerhöhe", + "position-function": "Positionskonvertierungsfunktion, sollte x,y-Koordinaten im Bereich von 0 bis 1 (double) zurückgeben", + "draggable-marker": "Verschiebbarer Marker", "label": "Beschriftung", "show-label": "Beschriftung anzeigen", "use-label-function": "Beschriftungsfunktion verwenden", - "label-pattern": "Beschriftung (z.B.: '${entityName}', '${entityName}: (Text ${keyName} Einheiten.)')", + "label-pattern": "Beschriftung (Beispielmuster: '${entityName}', '${entityName}: (Text ${keyName} Einheiten.)')", "label-function": "Beschriftungsfunktion", "tooltip": "Tooltip", "show-tooltip": "Tooltip anzeigen", @@ -9522,4 +9549,4 @@ "language": { "language": "Sprache" } -} +} \ No newline at end of file diff --git a/ui-ngx/src/assets/locale/locale.constant-el_GR.json b/ui-ngx/src/assets/locale/locale.constant-el_GR.json index 4af644ab8d..9c2a7edc23 100644 --- a/ui-ngx/src/assets/locale/locale.constant-el_GR.json +++ b/ui-ngx/src/assets/locale/locale.constant-el_GR.json @@ -864,7 +864,7 @@ "api-features": "Λειτουργίες API", "api-usage": "Χρήση API", "alarm": "Συναγερμός", - "alarms-created": "Δημιουργήθηκαν συναγερμοί", + "alarms-created": "Συναγερμοί που δημιουργήθηκαν", "queue-stats": "Στατιστικά ουράς", "processing-failures-and-timeouts": "Αποτυχίες επεξεργασίας και χρονικά όρια", "exceptions": "Εξαιρέσεις", @@ -873,11 +873,11 @@ "alarms-created-monthly-activity": "Μηνιαία δραστηριότητα δημιουργίας συναγερμών", "data-points": "Σημεία δεδομένων", "data-points-storage-days": "Ημέρες αποθήκευσης σημείων δεδομένων", - "device-api": "API συσκευής", + "device-api": "API Συσκευής", "email": "Email", - "email-messages": "Μηνύματα Email", - "email-messages-daily-activity": "Ημερήσια δραστηριότητα Email", - "email-messages-monthly-activity": "Μηνιαία δραστηριότητα Email", + "email-messages": "Μηνύματα email", + "email-messages-daily-activity": "Ημερήσια δραστηριότητα μηνυμάτων email", + "email-messages-monthly-activity": "Μηνιαία δραστηριότητα μηνυμάτων email", "executions": "Εκτελέσεις", "scripts": "Σενάρια", "scripts-hourly-activity": "Ωριαία δραστηριότητα σεναρίων", @@ -1111,13 +1111,15 @@ "mistral-ai": "Mistral AI", "anthropic": "Anthropic", "amazon-bedrock": "Amazon Bedrock", - "github-models": "GitHub Models" + "github-models": "GitHub Models", + "ollama": "Ollama" }, - "name-required": "Απαιτείται όνομα.", - "name-max-length": "Το όνομα πρέπει να έχει έως 255 χαρακτήρες.", + "name-required": "Το όνομα είναι υποχρεωτικό.", + "name-max-length": "Το όνομα πρέπει να είναι έως 255 χαρακτήρες.", "provider": "Πάροχος", "api-key": "Κλειδί API", - "api-key-required": "Απαιτείται κλειδί API.", + "api-key-required": "Το κλειδί API είναι υποχρεωτικό.", + "api-key-open-ai-required": "Το κλειδί API είναι υποχρεωτικό όταν χρησιμοποιείται το επίσημο API του OpenAI.", "project-id": "Αναγνωριστικό έργου", "project-id-required": "Απαιτείται αναγνωριστικό έργου.", "location": "Τοποθεσία", @@ -1141,30 +1143,47 @@ "secret-access-key": "Μυστικό κλειδί πρόσβασης", "secret-access-key-required": "Απαιτείται μυστικό κλειδί πρόσβασης.", "temperature": "Θερμοκρασία", - "temperature-hint": "Ρυθμίζει το επίπεδο τυχαιότητας στην έξοδο του μοντέλου. Υψηλότερες τιμές αυξάνουν την τυχαιότητα, ενώ χαμηλότερες τη μειώνουν.", + "temperature-hint": "Ρυθμίζει το επίπεδο τυχαιότητας στην έξοδο του μοντέλου. Υψηλότερες τιμές αυξάνουν την τυχαιότητα, ενώ χαμηλότερες την μειώνουν.", "temperature-min": "Πρέπει να είναι 0 ή μεγαλύτερο.", "top-p": "Top P", - "top-p-hint": "Δημιουργεί μια ομάδα με τα πιο πιθανά tokens από τα οποία θα επιλέξει το μοντέλο. Υψηλότερες τιμές δημιουργούν μεγαλύτερη και πιο ποικίλη ομάδα.", + "top-p-hint": "Δημιουργεί μια ομάδα από τα πιο πιθανά tokens για επιλογή από το μοντέλο. Υψηλότερες τιμές δημιουργούν μεγαλύτερη και πιο ποικιλόμορφη ομάδα, ενώ χαμηλότερες δημιουργούν μικρότερη.", "top-p-min-max": "Πρέπει να είναι μεγαλύτερο από 0 και έως 1.", "top-k": "Top K", - "top-k-hint": "Περιορίζει τις επιλογές του μοντέλου σε ένα καθορισμένο σύνολο με τα \"K\" πιο πιθανά tokens.", + "top-k-hint": "Περιορίζει τις επιλογές του μοντέλου σε ένα καθορισμένο σύνολο από τα \"K\" πιο πιθανά tokens.", "top-k-min": "Πρέπει να είναι 0 ή μεγαλύτερο.", "presence-penalty": "Ποινή παρουσίας", - "presence-penalty-hint": "Εφαρμόζει σταθερή ποινή στην πιθανότητα ενός token αν έχει ήδη εμφανιστεί στο κείμενο.", + "presence-penalty-hint": "Εφαρμόζει μια σταθερή ποινή στην πιθανότητα ενός token εάν έχει ήδη εμφανιστεί στο κείμενο.", "frequency-penalty": "Ποινή συχνότητας", - "frequency-penalty-hint": "Εφαρμόζει ποινή στην πιθανότητα ενός token που αυξάνεται με βάση τη συχνότητα εμφάνισής του στο κείμενο.", + "frequency-penalty-hint": "Εφαρμόζει ποινή στην πιθανότητα ενός token, που αυξάνεται βάσει της συχνότητάς του στο κείμενο.", "max-output-tokens": "Μέγιστος αριθμός tokens εξόδου", - "max-output-tokens-min": "Πρέπει να είναι μεγαλύτερο από 0.", - "max-output-tokens-hint": "Ορίζει τον μέγιστο αριθμό tokens που μπορεί να δημιουργήσει το μοντέλο σε μία απάντηση.", - "endpoint": "Σημείο τερματισμού (Endpoint)", - "endpoint-required": "Απαιτείται σημείο τερματισμού.", + "max-output-tokens-hint": "Καθορίζει τον μέγιστο αριθμό tokens που μπορεί να παράγει το μοντέλο σε μία απάντηση.", + "context-length": "Μήκος συμφραζομένων", + "context-length-hint": "Καθορίζει το μέγεθος του παραθύρου συμφραζομένων σε tokens. Αυτή η τιμή ορίζει το συνολικό όριο μνήμης του μοντέλου, περιλαμβάνοντας τόσο την είσοδο του χρήστη όσο και την παραγόμενη απάντηση.", + "endpoint": "Σημείο τέλους", + "endpoint-required": "Το σημείο τέλους είναι υποχρεωτικό.", + "baseurl": "Βασικό URL", + "baseurl-required": "Το βασικό URL είναι υποχρεωτικό.", "service-version": "Έκδοση υπηρεσίας", "check-connectivity": "Έλεγχος συνδεσιμότητας", "check-connectivity-success": "Το δοκιμαστικό αίτημα ήταν επιτυχές", "check-connectivity-failed": "Το δοκιμαστικό αίτημα απέτυχε", "no-model-matching": "Δεν βρέθηκαν μοντέλα που να ταιριάζουν με '{{entity}}'.", "model-required": "Απαιτείται μοντέλο.", - "no-model-text": "Δεν βρέθηκαν μοντέλα." + "no-model-text": "Δεν βρέθηκαν μοντέλα.", + "authentication": "Αυθεντικοποίηση", + "authentication-basic-hint": "Χρησιμοποιεί την τυπική HTTP Basic αυθεντικοποίηση. Το όνομα χρήστη και ο κωδικός πρόσβασης θα συνδυαστούν, θα κωδικοποιηθούν σε Base64 και θα σταλούν στην κεφαλίδα \"Authorization\" με κάθε αίτημα προς τον διακομιστή Ollama.", + "authentication-token-hint": "Χρησιμοποιεί αυθεντικοποίηση με διακριτικό τύπου Bearer. Το παρεχόμενο διακριτικό θα σταλεί απευθείας στην κεφαλίδα \"Authorization\" με κάθε αίτημα προς τον διακομιστή Ollama.", + "authentication-type": { + "none": "Καμία", + "basic": "Basic", + "token": "Token" + }, + "username": "Όνομα χρήστη", + "username-required": "Το όνομα χρήστη είναι υποχρεωτικό.", + "password": "Κωδικός πρόσβασης", + "password-required": "Ο κωδικός πρόσβασης είναι υποχρεωτικός.", + "token": "Διακριτικό", + "token-required": "Το διακριτικό είναι υποχρεωτικό." }, "confirm-on-exit": { "message": "Έχετε μη αποθηκευμένες αλλαγές. Είστε βέβαιοι ότι θέλετε να φύγετε από αυτήν τη σελίδα;", @@ -1434,9 +1453,9 @@ "min-mobile-row-height-message": "Ελάχιστο ύψος γραμμής για κινητό είναι 5 pixels.", "max-mobile-row-height-message": "Μέγιστο ύψος γραμμής για κινητό είναι 200 pixels.", "row-height": "Ύψος γραμμής", - "row-height-required": "Απαιτείται τιμή ύψους γραμμής.", - "min-row-height-message": "Ελάχιστο ύψος γραμμής είναι 5 pixels.", - "max-row-height-message": "Μέγιστο ύψος γραμμής είναι 200 pixels.", + "row-height-required": "Η τιμή ύψους γραμμής είναι υποχρεωτική.", + "min-row-height-message": "Επιτρέπονται μόνο 5 pixel ως ελάχιστο ύψος γραμμής.", + "max-row-height-message": "Επιτρέπονται μόνο 200 pixel ως μέγιστο ύψος γραμμής.", "display-first-in-mobile-view": "Εμφάνιση πρώτα στην προβολή κινητού", "title-settings": "Ρυθμίσεις τίτλου", "display-title": "Εμφάνιση τίτλου πίνακα", @@ -1587,7 +1606,7 @@ "aggregation-type-count-hint": "Συνολικός αριθμός σημείων δεδομένων σε επιλεγμένο χρονικό παράθυρο.", "delta-calculation": "Υπολογισμός διαφοράς", "enable-delta-calculation": "Ενεργοποίηση υπολογισμού διαφοράς", - "enable-delta-calculation-hint": "Όταν είναι ενεργοποιημένο, η τιμή του κλειδιού δεδομένων υπολογίζεται με βάση τις συσσωρευμένες τιμές για ένα επιλεγμένο χρονικό παράθυρο και μια καθορισμένη περίοδο σύγκρισης. Για λόγους απόδοσης, ο υπολογισμός διαφοράς είναι διαθέσιμος μόνο για ιστορικά χρονικά παράθυρα και όχι για τιμές σε πραγματικό χρόνο.", + "enable-delta-calculation-hint": "Όταν είναι ενεργοποιημένο, η τιμή του δεδομένου υπολογίζεται βάσει των συγκεντρωτικών τιμών για ένα επιλεγμένο χρονικό παράθυρο και μια καθορισμένη περίοδο σύγκρισης. Για λόγους απόδοσης, ο υπολογισμός της διαφοράς είναι διαθέσιμος μόνο για χρονικά παράθυρα ιστορικού και όχι για τιμές σε πραγματικό χρόνο. Για παράδειγμα, μπορείτε να υπολογίσετε τη διαφορά στην κατανάλωση ενέργειας μεταξύ χθες και προχθές.", "delta-calculation-result": "Αποτέλεσμα υπολογισμού διαφοράς", "delta-calculation-result-previous-value": "Προηγούμενη τιμή", "delta-calculation-result-delta-absolute": "Διαφορά (απόλυτη)", @@ -1916,24 +1935,24 @@ "default": "Προεπιλογή", "default-rule-chain": "Προεπιλεγμένη αλυσίδα κανόνων", "default-edge-rule-chain": "Προεπιλεγμένη αλυσίδα κανόνων Edge", - "default-edge-rule-chain-hint": "Χρησιμοποιείται στο Edge ως αλυσίδα κανόνων για την επεξεργασία εισερχόμενων δεδομένων για περιουσιακά στοιχεία αυτού του προφίλ", - "mobile-dashboard": "Πίνακας ελέγχου για κινητό", - "mobile-dashboard-hint": "Χρησιμοποιείται από την εφαρμογή για κινητό ως πίνακας λεπτομερειών περιουσιακού στοιχείου", - "select-queue-hint": "Επιλέξτε από αναπτυσσόμενη λίστα.", - "delete-asset-profile-title": "Είστε βέβαιοι ότι θέλετε να διαγράψετε το προφίλ περιουσιακού στοιχείου '{{assetProfileName}}';", - "delete-asset-profile-text": "Προσοχή, μετά την επιβεβαίωση το προφίλ και όλα τα σχετικά δεδομένα δεν θα είναι ανακτήσιμα.", - "delete-asset-profiles-title": "Είστε βέβαιοι ότι θέλετε να διαγράψετε { count, plural, =1 {1 προφίλ περιουσιακού στοιχείου} other {# προφίλ περιουσιακών στοιχείων} };", - "delete-asset-profiles-text": "Προσοχή, μετά την επιβεβαίωση όλα τα επιλεγμένα προφίλ θα διαγραφούν και όλα τα σχετικά δεδομένα δεν θα είναι ανακτήσιμα.", - "set-default-asset-profile-title": "Είστε βέβαιοι ότι θέλετε να ορίσετε το προφίλ '{{assetProfileName}}' ως προεπιλεγμένο;", - "set-default-asset-profile-text": "Μετά την επιβεβαίωση, το προφίλ θα οριστεί ως προεπιλογή και θα χρησιμοποιείται για νέα περιουσιακά στοιχεία χωρίς καθορισμένο προφίλ.", - "no-asset-profiles-found": "Δεν βρέθηκαν προφίλ περιουσιακών στοιχείων.", - "create-new-asset-profile": "Δημιουργία νέου!", - "create-asset-profile": "Δημιουργία νέου προφίλ περιουσιακού στοιχείου", - "import": "Εισαγωγή προφίλ περιουσιακού στοιχείου", - "export": "Εξαγωγή προφίλ περιουσιακού στοιχείου", - "export-failed-error": "Αδυναμία εξαγωγής προφίλ: {{error}}", - "asset-profile-file": "Αρχείο προφίλ περιουσιακού στοιχείου", - "invalid-asset-profile-file-error": "Αδυναμία εισαγωγής προφίλ: Μη έγκυρη δομή δεδομένων προφίλ περιουσιακού στοιχείου." + "default-edge-rule-chain-hint": "Χρησιμοποιείται στο Edge ως αλυσίδα κανόνων για την επεξεργασία εισερχόμενων δεδομένων για στοιχεία αυτού του προφίλ πόρου", + "mobile-dashboard": "Πίνακας ελέγχου κινητού", + "mobile-dashboard-hint": "Χρησιμοποιείται από την εφαρμογή κινητού ως πίνακας λεπτομερειών πόρου", + "select-queue-hint": "Επιλέξτε από την αναπτυσσόμενη λίστα.", + "delete-asset-profile-title": "Είστε βέβαιοι ότι θέλετε να διαγράψετε το προφίλ πόρου '{{assetProfileName}}';", + "delete-asset-profile-text": "Προσοχή, μετά την επιβεβαίωση το προφίλ πόρου και όλα τα σχετικά δεδομένα δεν θα είναι ανακτήσιμα.", + "delete-asset-profiles-title": "Είστε βέβαιοι ότι θέλετε να διαγράψετε { count, plural, =1 {1 προφίλ πόρου} other {# προφίλ πόρων} };", + "delete-asset-profiles-text": "Προσοχή, μετά την επιβεβαίωση όλα τα επιλεγμένα προφίλ πόρων θα διαγραφούν και όλα τα σχετικά δεδομένα δεν θα είναι ανακτήσιμα.", + "set-default-asset-profile-title": "Είστε βέβαιοι ότι θέλετε να ορίσετε το προφίλ πόρου '{{assetProfileName}}' ως προεπιλεγμένο;", + "set-default-asset-profile-text": "Μετά την επιβεβαίωση, το προφίλ πόρου θα οριστεί ως προεπιλεγμένο και θα χρησιμοποιείται για νέους πόρους χωρίς καθορισμένο προφίλ.", + "no-asset-profiles-found": "Δεν βρέθηκαν προφίλ πόρων.", + "create-new-asset-profile": "Δημιουργήστε ένα νέο!", + "create-asset-profile": "Δημιουργία νέου προφίλ πόρου", + "import": "Εισαγωγή προφίλ πόρου", + "export": "Εξαγωγή προφίλ πόρου", + "export-failed-error": "Αδυναμία εξαγωγής προφίλ πόρου: {{error}}", + "asset-profile-file": "Αρχείο προφίλ πόρου", + "invalid-asset-profile-file-error": "Αδυναμία εισαγωγής προφίλ πόρου: Μη έγκυρη δομή δεδομένων προφίλ πόρου." }, "device-profile": { "device-profile": "Προφίλ συσκευής", @@ -1998,17 +2017,17 @@ "mqtt-device-payload-type": "Payload συσκευής MQTT", "mqtt-device-payload-type-json": "JSON", "mqtt-device-payload-type-proto": "Protobuf", - "mqtt-enable-compatibility-with-json-payload-format": "Ενεργοποίηση συμβατότητας με άλλες μορφές payload", - "mqtt-enable-compatibility-with-json-payload-format-hint": "Όταν είναι ενεργοποιημένο, χρησιμοποιείται Protobuf ως προεπιλογή και γίνεται fallback σε JSON αν αποτύχει η ανάλυση. Χρήσιμο για υποστήριξη συσκευών κατά τη διάρκεια αναβάθμισης firmware.", - "mqtt-use-json-format-for-default-downlink-topics": "Χρήση μορφής JSON για τα προεπιλεγμένα θέματα downlink", - "mqtt-use-json-format-for-default-downlink-topics-hint": "Όταν ενεργοποιηθεί, χρησιμοποιείται JSON payload για αποστολή attributes και RPC μέσω θεμάτων v1/devices/me/attributes/response/$request_id, v1/devices/me/attributes, v1/devices/me/rpc/request/$request_id, v1/devices/me/rpc/response/$request_id. Δεν επηρεάζει νέα θέματα (v2): v2/a/res/$request_id κ.λπ.", - "mqtt-send-ack-on-validation-exception": "Αποστολή PUBACK σε αποτυχία επικύρωσης PUBLISH μηνύματος", - "mqtt-send-ack-on-validation-exception-hint": "Αντί για τερματισμό της συνεδρίας, η πλατφόρμα θα στείλει PUBACK αν είναι ενεργοποιημένο.", + "mqtt-enable-compatibility-with-json-payload-format": "Ενεργοποίηση συμβατότητας με άλλες μορφές φορτίου.", + "mqtt-enable-compatibility-with-json-payload-format-hint": "Όταν είναι ενεργοποιημένο, η πλατφόρμα θα χρησιμοποιεί από προεπιλογή μορφή φορτίου Protobuf. Αν αποτύχει η ανάλυση, η πλατφόρμα θα προσπαθήσει να χρησιμοποιήσει μορφή φορτίου JSON. Χρήσιμο για συμβατότητα με προηγούμενες εκδόσεις κατά τις ενημερώσεις firmware. Για παράδειγμα, η αρχική έκδοση του firmware χρησιμοποιεί Json, ενώ η νέα χρησιμοποιεί Protobuf. Κατά τη διαδικασία ενημέρωσης firmware για τον στόλο των συσκευών, απαιτείται υποστήριξη τόσο Protobuf όσο και JSON ταυτόχρονα. Η λειτουργία συμβατότητας επιφέρει ελαφρά μείωση της απόδοσης, οπότε συνιστάται η απενεργοποίησή της μόλις ενημερωθούν όλες οι συσκευές.", + "mqtt-use-json-format-for-default-downlink-topics": "Χρήση μορφής Json για τα προεπιλεγμένα θέματα downlink", + "mqtt-use-json-format-for-default-downlink-topics-hint": "Όταν είναι ενεργοποιημένο, η πλατφόρμα θα χρησιμοποιεί μορφή φορτίου Json για αποστολή χαρακτηριστικών και RPC μέσω των ακόλουθων θεμάτων: v1/devices/me/attributes/response/$request_id, v1/devices/me/attributes, v1/devices/me/rpc/request/$request_id, v1/devices/me/rpc/response/$request_id. Αυτή η ρύθμιση δεν επηρεάζει τις εγγραφές χαρακτηριστικών και RPC που αποστέλλονται χρησιμοποιώντας τα νέα θέματα (v2): v2/a/res/$request_id, v2/a, v2/r/req/$request_id, v2/r/res/$request_id. Όπου το $request_id είναι ένας ακέραιος αναγνωριστικός αριθμός αιτήματος.", + "mqtt-send-ack-on-validation-exception": "Αποστολή PUBACK σε αποτυχία επικύρωσης μηνύματος PUBLISH", + "mqtt-send-ack-on-validation-exception-hint": "Από προεπιλογή, η πλατφόρμα θα τερματίζει τη συνεδρία MQTT σε περίπτωση αποτυχίας επικύρωσης μηνύματος. Όταν είναι ενεργοποιημένο, η πλατφόρμα θα στέλνει επιβεβαίωση δημοσίευσης αντί να τερματίζει τη συνεδρία.", "mqtt-protocol-version": "Έκδοση πρωτοκόλλου", - "snmp-add-mapping": "Προσθήκη SNMP αντιστοίχισης", - "snmp-mapping-not-configured": "Δεν έχει διαμορφωθεί αντιστοίχιση OID σε χρονική σειρά/χαρακτηριστικό", - "snmp-timseries-or-attribute-name": "Όνομα για αντιστοίχιση χρονικής σειράς/χαρακτηριστικού", - "snmp-timseries-or-attribute-type": "Τύπος για αντιστοίχιση χρονικής σειράς/χαρακτηριστικού", + "snmp-add-mapping": "Προσθήκη αντιστοίχισης SNMP", + "snmp-mapping-not-configured": "Δεν έχει διαμορφωθεί αντιστοίχιση από OID σε χρονοσειρά/τηλεμετρία", + "snmp-timseries-or-attribute-name": "Όνομα χρονοσειράς/χαρακτηριστικού για αντιστοίχιση", + "snmp-timseries-or-attribute-type": "Τύπος χρονοσειράς/χαρακτηριστικού για αντιστοίχιση", "snmp-method-pdu-type-get-request": "GetRequest", "snmp-method-pdu-type-get-next-request": "GetNextRequest", "snmp-oid": "OID", @@ -2209,20 +2228,20 @@ "bootstrap-server-legend": "Bootstrap διακομιστής (ShortId...)", "lwm2m-server-legend": "LwM2M διακομιστής (ShortId...)", "server": "Διακομιστής", - "short-id": "Σύντομο ID διακομιστή", - "short-id-tooltip": "Σύντομο Id διακομιστή. Χρησιμοποιείται για σύνδεση με στιγμιότυπο αντικειμένου.\nΠρέπει να οριστεί όταν το πεδίο Bootstrap-Server έχει τιμή 'false'.\nΔεν επιτρέπεται η χρήση των ID:0 και ID:65535.", - "short-id-tooltip-bootstrap": "Χρησιμοποιείται για σύνδεση με στιγμιότυπο αντικειμένου διακομιστή.\nΠρέπει να οριστεί όταν το πεδίο Bootstrap-Server έχει τιμή 'false'.", - "short-id-required": "Απαιτείται σύντομο ID διακομιστή.", - "short-id-range": "Το σύντομο ID διακομιστή πρέπει να είναι μεταξύ {{ min }} και {{ max }}.", - "short-id-pattern": "Το σύντομο ID διακομιστή πρέπει να είναι θετικός ακέραιος.", + "short-id": "Σύντομο αναγνωριστικό διακομιστή", + "short-id-tooltip": "Σύντομο αναγνωριστικό διακομιστή. Χρησιμοποιείται ως σύνδεσμος για τη συσχέτιση του αντικειμένου διακομιστή.\nΑυτό το αναγνωριστικό προσδιορίζει μοναδικά κάθε διακομιστή LwM2M που έχει διαμορφωθεί για τον πελάτη LwM2M.\nΟ πόρος ΠΡΕΠΕΙ να οριστεί όταν ο πόρος Bootstrap-Server έχει τιμή 'false'.\nΟι τιμές ID:0 και ID:65535 ΔΕΝ ΠΡΕΠΕΙ να χρησιμοποιούνται για την αναγνώριση του διακομιστή LwM2M.", + "short-id-tooltip-bootstrap": "Σύντομο αναγνωριστικό διακομιστή. Χρησιμοποιείται ως σύνδεσμος για τη συσχέτιση του αντικειμένου διακομιστή.\nΑυτό το αναγνωριστικό προσδιορίζει μοναδικά κάθε διακομιστή LwM2M που έχει διαμορφωθεί για τον πελάτη LwM2M.\nΟ πόρος ΠΡΕΠΕΙ να οριστεί όταν ο πόρος Bootstrap-Server έχει τιμή 'false'.", + "short-id-required": "Το σύντομο αναγνωριστικό διακομιστή είναι υποχρεωτικό.", + "short-id-range": "Το σύντομο αναγνωριστικό διακομιστή πρέπει να είναι εντός του εύρους από {{ min }} έως {{ max }}.", + "short-id-pattern": "Το σύντομο αναγνωριστικό διακομιστή πρέπει να είναι θετικός ακέραιος αριθμός.", "lifetime": "Διάρκεια εγγραφής πελάτη", - "lifetime-required": "Απαιτείται διάρκεια εγγραφής πελάτη.", - "lifetime-pattern": "Η διάρκεια πρέπει να είναι θετικός ακέραιος.", - "default-min-period": "Ελάχιστη περίοδος μεταξύ ειδοποιήσεων (δ)", - "default-min-period-tooltip": "Χρησιμοποιείται αν δεν περιλαμβάνεται η παράμετρος στην παρατήρηση.", - "default-min-period-required": "Απαιτείται ελάχιστη περίοδος.", - "default-min-period-pattern": "Η ελάχιστη περίοδος πρέπει να είναι θετικός ακέραιος.", - "notification-storing": "Αποθήκευση ειδοποιήσεων όταν είναι απενεργοποιημένο ή εκτός σύνδεσης", + "lifetime-required": "Η διάρκεια εγγραφής πελάτη είναι υποχρεωτική.", + "lifetime-pattern": "Η διάρκεια εγγραφής πελάτη πρέπει να είναι θετικός ακέραιος αριθμός.", + "default-min-period": "Ελάχιστη περίοδος μεταξύ δύο ειδοποιήσεων (δλ)", + "default-min-period-tooltip": "Η προεπιλεγμένη τιμή που πρέπει να χρησιμοποιεί ο πελάτης LwM2M για την Ελάχιστη Περίοδο μιας Παρατήρησης όταν αυτή η παράμετρος δεν περιλαμβάνεται.", + "default-min-period-required": "Η ελάχιστη περίοδος είναι υποχρεωτική.", + "default-min-period-pattern": "Η ελάχιστη περίοδος πρέπει να είναι θετικός ακέραιος αριθμός.", + "notification-storing": "Αποθήκευση ειδοποιήσεων όταν είναι απενεργοποιημένος ή εκτός σύνδεσης", "binding": "Δεσμευτικό", "binding-type": { "u": "U: Ο πελάτης είναι προσβάσιμος μέσω UDP ανά πάσα στιγμή.", @@ -4304,11 +4323,11 @@ "profile": { "profile": "Προφίλ", "last-login-time": "Τελευταία σύνδεση", - "change-password": "Αλλαγή κωδικού", - "current-password": "Τρέχων κωδικός", + "change-password": "Αλλαγή κωδικού πρόσβασης", + "current-password": "Τρέχων κωδικός πρόσβασης", "copy-jwt-token": "Αντιγραφή JWT token", "jwt-token": "JWT token", - "token-valid-till": "Το token είναι έγκυρο έως", + "token-valid-till": "Το token ισχύει μέχρι", "tokenCopiedSuccessMessage": "Το JWT token αντιγράφηκε στο πρόχειρο", "tokenCopiedWarnMessage": "Το JWT token έχει λήξει! Παρακαλώ, ανανεώστε τη σελίδα." }, @@ -4366,17 +4385,17 @@ }, "provider": { "email": "Email", - "email-description": "Χρησιμοποιήστε κωδικό που αποστέλλεται στο email σας.", - "email-hint": "Οι κωδικοί αποστέλλονται στο {{ info }}", + "email-description": "Χρησιμοποιήστε έναν κωδικό ασφαλείας που αποστέλλεται στη διεύθυνση email σας για να πραγματοποιήσετε έλεγχο ταυτότητας.", + "email-hint": "Οι κωδικοί ελέγχου ταυτότητας αποστέλλονται μέσω email στη διεύθυνση {{ info }}", "sms": "SMS", - "sms-description": "Χρησιμοποιήστε το κινητό σας για επαλήθευση. Θα σας αποστείλουμε έναν κωδικό μέσω SMS.", - "sms-hint": "Οι κωδικοί αποστέλλονται στο {{ info }}", - "totp": "Εφαρμογή επαλήθευσης", - "totp-description": "Χρησιμοποιήστε εφαρμογές όπως Google Authenticator, Authy ή Duo για την επαλήθευση.", - "totp-hint": "Η εφαρμογή επαλήθευσης έχει ρυθμιστεί για τον λογαριασμό σας", + "sms-description": "Χρησιμοποιήστε το τηλέφωνό σας για έλεγχο ταυτότητας. Θα σας στείλουμε έναν κωδικό ασφαλείας μέσω SMS όταν συνδεθείτε.", + "sms-hint": "Οι κωδικοί ελέγχου ταυτότητας αποστέλλονται με μήνυμα κειμένου στον αριθμό {{ info }}", + "totp": "Εφαρμογή ελέγχου ταυτότητας", + "totp-description": "Χρησιμοποιήστε εφαρμογές όπως Google Authenticator, Authy ή Duo στο τηλέφωνό σας για έλεγχο ταυτότητας. Θα δημιουργήσει έναν κωδικό ασφαλείας για σύνδεση.", + "totp-hint": "Η εφαρμογή ελέγχου ταυτότητας έχει ρυθμιστεί για τον λογαριασμό σας", "backup_code": "Εφεδρικός κωδικός", - "backup-code-description": "Οι εφεδρικοί κωδικοί επιτρέπουν σύνδεση όταν δεν έχετε πρόσβαση στο κινητό σας.", - "backup-code-hint": "{{ info }} μονο-χρησιμοποιούμενοι κωδικοί είναι ενεργοί αυτή τη στιγμή" + "backup-code-description": "Αυτοί οι εκτυπώσιμοι κωδικοί μίας χρήσης σάς επιτρέπουν να συνδεθείτε όταν δεν έχετε πρόσβαση στο τηλέφωνό σας, όπως κατά τη διάρκεια ενός ταξιδιού.", + "backup-code-hint": "{{ info }} κωδικοί μιας χρήσης είναι ενεργοί αυτήν τη στιγμή" } }, "password-requirement": { @@ -4478,15 +4497,21 @@ "jks": "JKS", "js-module": "JS module", "lwm2m-model": "Μοντέλο LWM2M", - "pkcs-12": "PKCS #12" + "pkcs-12": "PKCS #12", + "general": "Γενικά" }, "resource-sub-type": "Υποτύπος", "sub-type": { - "image": "εικόνα", + "image": "Εικόνα", "scada-symbol": "Σύμβολο SCADA", "extension": "Επέκταση", - "module": "Μονάδα" - } + "module": "Άρθρωμα" + }, + "resource-is-in-use": "Ο πόρος χρησιμοποιείται από άλλες οντότητες", + "resources-are-in-use": "Οι πόροι χρησιμοποιούνται από άλλες οντότητες", + "resource-is-in-use-text": "Ο πόρος '{{title}}' δεν διαγράφηκε επειδή χρησιμοποιείται από τις παρακάτω οντότητες:", + "resources-are-in-use-text": "Δεν διαγράφηκαν όλοι οι πόροι επειδή χρησιμοποιούνται από άλλες οντότητες.
Μπορείτε να δείτε τις σχετικές οντότητες κάνοντας κλικ στο κουμπί Αναφορές στη σχετική γραμμή πόρου.
Αν εξακολουθείτε να θέλετε να διαγράψετε αυτούς τους πόρους, επιλέξτε τους στον παρακάτω πίνακα και κάντε κλικ στο κουμπί Διαγραφή επιλεγμένων.", + "delete-resource-in-use-text": "Αν εξακολουθείτε να θέλετε να διαγράψετε τον πόρο, κάντε κλικ στο κουμπί Διαγραφή ούτως ή άλλως." }, "javascript": { "add": "Προσθήκη πόρου JavaScript", @@ -4568,23 +4593,23 @@ "edge-template-root": "Ρίζα προτύπου edge", "assign-to-edge": "Ανάθεση σε edge", "edge-rulechain": "Αλυσίδα κανόνων edge", - "unassign-rulechain-from-edge-text": "Μετά την επιβεβαίωση η αλυσίδα κανόνων θα αποανατεθεί και δεν θα είναι προσβάσιμη από το edge.", - "unassign-rulechains-from-edge-title": "Είστε σίγουροι ότι θέλετε να αποαναθέσετε { count, plural, =1 {1 αλυσίδα κανόνων} other {# αλυσίδες κανόνων} };", - "unassign-rulechains-from-edge-text": "Μετά την επιβεβαίωση όλες οι επιλεγμένες αλυσίδες κανόνων θα αποανατεθούν και δεν θα είναι προσβάσιμες από το edge.", - "assign-rulechain-to-edge-title": "Ανάθεση αλυσίδας(ών) κανόνων στο Edge", - "assign-rulechain-to-edge-text": "Επιλέξτε τις αλυσίδες κανόνων που θα ανατεθούν στο edge", - "set-edge-template-root-rulechain": "Ορισμός ως ρίζα προτύπου edge", + "unassign-rulechain-from-edge-text": "Μετά την επιβεβαίωση, η αλυσίδα κανόνων θα αποσυσχετιστεί και δεν θα είναι προσβάσιμη από το edge.", + "unassign-rulechains-from-edge-title": "Είστε σίγουροι ότι θέλετε να αποσυσχετίσετε { count, plural, =1 {1 αλυσίδα κανόνων} other {# αλυσίδες κανόνων} };", + "unassign-rulechains-from-edge-text": "Μετά την επιβεβαίωση, όλες οι επιλεγμένες αλυσίδες κανόνων θα αποσυσχετιστούν και δεν θα είναι προσβάσιμες από το edge.", + "assign-rulechain-to-edge-title": "Ανάθεση Αλυσίδας Κανόνων σε Edge", + "assign-rulechain-to-edge-text": "Παρακαλώ επιλέξτε τις αλυσίδες κανόνων που θα ανατεθούν στο edge", + "set-edge-template-root-rulechain": "Ορισμός αλυσίδας κανόνων ως ρίζα προτύπου edge", "set-edge-template-root-rulechain-title": "Είστε σίγουροι ότι θέλετε να ορίσετε την αλυσίδα κανόνων '{{ruleChainName}}' ως ρίζα προτύπου edge;", - "set-edge-template-root-rulechain-text": "Μετά την επιβεβαίωση, η αλυσίδα κανόνων θα γίνει ρίζα προτύπου edge και θα είναι η βασική αλυσίδα για νέα edge.", - "invalid-rulechain-type-error": "Αδυναμία εισαγωγής: Μη έγκυρος τύπος αλυσίδας κανόνων. Αναμενόμενος τύπος: {{expectedRuleChainType}}.", - "set-auto-assign-to-edge": "Ανάθεση σε edge κατά τη δημιουργία", - "set-auto-assign-to-edge-title": "Είστε σίγουροι ότι θέλετε να αναθέσετε την αλυσίδα '{{ruleChainName}}' σε edge κατά τη δημιουργία;", - "set-auto-assign-to-edge-text": "Μετά την επιβεβαίωση, η αλυσίδα θα ανατίθεται αυτόματα σε νέο edge.", - "unset-auto-assign-to-edge": "Μη αυτόματη ανάθεση σε edge κατά τη δημιουργία", - "unset-auto-assign-to-edge-title": "Είστε σίγουροι ότι δεν θέλετε την αυτόματη ανάθεση της αλυσίδας '{{ruleChainName}}';", - "unset-auto-assign-to-edge-text": "Μετά την επιβεβαίωση η αλυσίδα δεν θα ανατίθεται αυτόματα σε νέο edge.", - "unassign-rulechain-title": "Είστε σίγουροι ότι θέλετε να αποαναθέσετε την αλυσίδα '{{ruleChainName}}';", - "unassign-rulechains": "Αποανάθεση αλυσίδων κανόνων" + "set-edge-template-root-rulechain-text": "Μετά την επιβεβαίωση, η αλυσίδα κανόνων θα γίνει ρίζα προτύπου edge και θα είναι η βασική αλυσίδα για νέα edges.", + "invalid-rulechain-type-error": "Αδυναμία εισαγωγής αλυσίδας κανόνων: Μη έγκυρος τύπος. Αναμενόμενος τύπος: {{expectedRuleChainType}}.", + "set-auto-assign-to-edge": "Ανάθεση αλυσίδας κανόνων σε edge κατά τη δημιουργία", + "set-auto-assign-to-edge-title": "Είστε σίγουροι ότι θέλετε να ανατεθεί η αλυσίδα κανόνων edge '{{ruleChainName}}' σε edge κατά τη δημιουργία;", + "set-auto-assign-to-edge-text": "Μετά την επιβεβαίωση, η αλυσίδα κανόνων edge θα ανατίθεται αυτόματα σε edge κατά τη δημιουργία.", + "unset-auto-assign-to-edge": "Να μην ανατίθεται αλυσίδα κανόνων σε edge κατά τη δημιουργία", + "unset-auto-assign-to-edge-title": "Είστε σίγουροι ότι δεν θέλετε να ανατεθεί η αλυσίδα κανόνων edge '{{ruleChainName}}' σε edge κατά τη δημιουργία;", + "unset-auto-assign-to-edge-text": "Μετά την επιβεβαίωση, η αλυσίδα κανόνων edge δεν θα ανατίθεται πλέον αυτόματα σε edge κατά τη δημιουργία.", + "unassign-rulechain-title": "Είστε σίγουροι ότι θέλετε να αποσυσχετίσετε την αλυσίδα κανόνων '{{ruleChainName}}';", + "unassign-rulechains": "Αποσυσχέτιση αλυσίδων κανόνων" }, "rulenode": { "rule-node-events": "Συμβάντα κόμβου κανόνα", @@ -4692,14 +4717,14 @@ "entity-cache-expiration-range": "Ο χρόνος πρέπει να είναι μεγαλύτερος ή ίσος με 0.", "customer-name-pattern": "Τίτλος πελάτη", "customer-name-pattern-required": "Ο τίτλος πελάτη είναι υποχρεωτικός", - "customer-name-pattern-hint": "Χρησιμοποιήστε $[messageKey] και ${metadataKey} για τιμές από το μήνυμα ή μεταδεδομένα.", + "customer-name-pattern-hint": "Χρησιμοποιήστε $[messageKey] για να εξάγετε τιμή από το μήνυμα και ${metadataKey} για να εξάγετε τιμή από τα μεταδεδομένα.", "create-customer-if-not-exists": "Δημιουργία νέου πελάτη αν δεν υπάρχει", - "unassign-from-customer": "Αποσυσχέτιση από συγκεκριμένο πελάτη αν το αρχικό είναι πίνακας ελέγχου", - "unassign-from-customer-tooltip": "Μόνο πίνακες ελέγχου μπορούν να συσχετιστούν με πολλούς πελάτες. Αν ο αποστολέας είναι πίνακας, καθορίστε τίτλο πελάτη για αποσυσχέτιση.", - "customer-cache-expiration": "Χρόνος λήξης προσωρινής αποθήκευσης πελατών (δευτ)", - "customer-cache-expiration-hint": "Ορίζει το μέγιστο χρονικό διάστημα αποθήκευσης πελατών. 0 σημαίνει χωρίς λήξη.", - "customer-cache-expiration-required": "Απαιτείται χρόνος λήξης προσωρινής αποθήκευσης πελατών.", - "customer-cache-expiration-range": "Ο χρόνος πρέπει να είναι μεγαλύτερος ή ίσος με 0.", + "unassign-from-customer": "Αποσυσχέτιση από συγκεκριμένο πελάτη αν ο αποστολέας είναι πίνακας ελέγχου", + "unassign-from-customer-tooltip": "Μόνο οι πίνακες ελέγχου μπορούν να ανατεθούν σε πολλούς πελάτες ταυτόχρονα. \nΑν ο αποστολέας του μηνύματος είναι πίνακας ελέγχου, πρέπει να προσδιορίσετε ρητά τον τίτλο του πελάτη για αποσυσχέτιση.", + "customer-cache-expiration": "Χρόνος λήξης προσωρινής μνήμης πελατών (δευτ.)", + "customer-cache-expiration-hint": "Καθορίζει το μέγιστο χρονικό διάστημα αποθήκευσης των καταγεγραμμένων πελατών. Τιμή 0 σημαίνει ότι οι καταγραφές δεν λήγουν ποτέ.", + "customer-cache-expiration-required": "Απαιτείται χρόνος λήξης προσωρινής μνήμης πελατών.", + "customer-cache-expiration-range": "Ο χρόνος λήξης προσωρινής μνήμης πελατών πρέπει να είναι μεγαλύτερος ή ίσος με 0.", "interval-start": "Έναρξη διαστήματος", "interval-end": "Τέλος διαστήματος", "time-unit": "Μονάδα χρόνου", @@ -4719,10 +4744,10 @@ "end-interval-value-required": "Απαιτείται το τέλος διαστήματος.", "filter": "Φίλτρο", "switch": "Εναλλαγή", - "math-templatization-tooltip": "Υποστηρίζει templatization με $[messageKey] και ${metadataKey}.", + "math-templatization-tooltip": "Αυτό το πεδίο υποστηρίζει παραμετροποίηση. Χρησιμοποιήστε $[messageKey] για να εξάγετε τιμή από το μήνυμα και ${metadataKey} για να εξάγετε τιμή από τα μεταδεδομένα.", "add-message-type": "Προσθήκη τύπου μηνύματος", - "select-message-types-required": "Απαιτείται τουλάχιστον ένας τύπος μηνύματος.", - "select-message-types": "Επιλογή τύπων μηνύματος", + "select-message-types-required": "Πρέπει να επιλεγεί τουλάχιστον ένας τύπος μηνύματος.", + "select-message-types": "Επιλογή τύπων μηνυμάτων", "no-message-types-found": "Δεν βρέθηκαν τύποι μηνυμάτων", "no-message-type-matching": "'{{messageType}}' δεν βρέθηκε.", "create-new-message-type": "Δημιουργία νέου.", @@ -4734,22 +4759,22 @@ "attributes-keys-required": "Απαιτούνται κλειδιά χαρακτηριστικών", "attributes-scope": "Πεδίο χαρακτηριστικών", "attributes-scope-value": "Τιμή πεδίου χαρακτηριστικών", - "attributes-scope-value-copy": "Αντιγραφή τιμής πεδίου", - "attributes-scope-hint": "Χρησιμοποιήστε το μεταδεδομένο 'scope' για δυναμική ρύθμιση. Εάν υπάρχει, παρακάμπτει τη ρύθμιση.", - "notify-device": "Εξαναγκασμένη ειδοποίηση συσκευής", - "send-attributes-updated-notification": "Αποστολή ειδοποίησης ενημέρωσης χαρακτηριστικών", - "send-attributes-updated-notification-hint": "Στέλνει ειδοποίηση ενημέρωσης ως ξεχωριστό μήνυμα στην ουρά.", - "send-attributes-deleted-notification": "Αποστολή ειδοποίησης διαγραφής χαρακτηριστικών", - "send-attributes-deleted-notification-hint": "Στέλνει ειδοποίηση διαγραφής ως ξεχωριστό μήνυμα στην ουρά.", - "update-attributes-only-on-value-change": "Αποθήκευση μόνο σε αλλαγή τιμής", - "update-attributes-only-on-value-change-hint": "Ενημερώνει σε κάθε μήνυμα ανεξαρτήτως αλλαγής. Μειώνει απόδοση.", - "update-attributes-only-on-value-change-hint-enabled": "Ενημερώνει μόνο αν αλλάξει τιμή. Διαφορετικά, δεν ενημερώνεται ούτε timestamp ούτε αποστέλλεται ειδοποίηση.", + "attributes-scope-value-copy": "Αντιγραφή τιμής πεδίου χαρακτηριστικών", + "attributes-scope-hint": "Χρησιμοποιήστε το metadata key 'scope' για να ορίσετε δυναμικά το πεδίο χαρακτηριστικών ανά μήνυμα. Αν παρέχεται, αυτό παρακάμπτει το πεδίο που έχει οριστεί στη ρύθμιση.", + "notify-device": "Αναγκαστική ειδοποίηση στη συσκευή", + "send-attributes-updated-notification": "Αποστολή ειδοποίησης για ενημερωμένα χαρακτηριστικά", + "send-attributes-updated-notification-hint": "Αποστολή ειδοποίησης για ενημερωμένα χαρακτηριστικά ως ξεχωριστό μήνυμα στην ουρά του rule engine.", + "send-attributes-deleted-notification": "Αποστολή ειδοποίησης για διαγραμμένα χαρακτηριστικά", + "send-attributes-deleted-notification-hint": "Αποστολή ειδοποίησης για διαγραμμένα χαρακτηριστικά ως ξεχωριστό μήνυμα στην ουρά του rule engine.", + "update-attributes-only-on-value-change": "Αποθήκευση χαρακτηριστικών μόνο αν αλλάξει η τιμή", + "update-attributes-only-on-value-change-hint": "Ενημερώνει τα χαρακτηριστικά σε κάθε εισερχόμενο μήνυμα ανεξαρτήτως αν η τιμή τους έχει αλλάξει. Αυξάνει τη χρήση API και μειώνει την απόδοση.", + "update-attributes-only-on-value-change-hint-enabled": "Ενημερώνει τα χαρακτηριστικά μόνο αν έχει αλλάξει η τιμή τους. Αν δεν έχει αλλάξει, δεν ενημερώνεται ούτε το χρονικό στιγμιότυπο ούτε αποστέλλεται ειδοποίηση αλλαγής χαρακτηριστικού.", "fetch-credentials-to-metadata": "Ανάκτηση διαπιστευτηρίων στα μεταδεδομένα", - "notify-device-on-update-hint": "Αν είναι ενεργό, ειδοποιεί τη συσκευή για ενημέρωση κοινών χαρακτηριστικών. Αλλιώς, ελέγχεται από το metadata 'notifyDevice'.", - "notify-device-on-delete-hint": "Αν είναι ενεργό, ειδοποιεί τη συσκευή για διαγραφή κοινών χαρακτηριστικών. Αλλιώς, ελέγχεται από το metadata 'notifyDevice'.", - "latest-timeseries": "Τελευταία δεδομένα χρονικής σειράς", - "timeseries-keys": "Κλειδιά χρονικής σειράς", - "timeseries-keys-required": "Απαιτείται τουλάχιστον ένα κλειδί χρονικής σειράς.", + "notify-device-on-update-hint": "Αν είναι ενεργό, αποστέλλεται υποχρεωτικά ειδοποίηση στη συσκευή για την ενημέρωση κοινών χαρακτηριστικών. Αν είναι ανενεργό, η συμπεριφορά ελέγχεται από την παράμετρο 'notifyDevice' στα μεταδεδομένα του μηνύματος. Για απενεργοποίηση ειδοποίησης, τα μεταδεδομένα πρέπει να περιέχουν την παράμετρο 'notifyDevice' ορισμένη σε 'false'. Σε κάθε άλλη περίπτωση, η ειδοποίηση θα σταλεί.", + "notify-device-on-delete-hint": "Αν είναι ενεργό, αποστέλλεται υποχρεωτικά ειδοποίηση στη συσκευή για την αφαίρεση κοινών χαρακτηριστικών. Αν είναι ανενεργό, η συμπεριφορά ελέγχεται από την παράμετρο 'notifyDevice' στα μεταδεδομένα του μηνύματος. Για ενεργοποίηση ειδοποίησης, τα μεταδεδομένα πρέπει να περιέχουν την παράμετρο 'notifyDevice' ορισμένη σε 'true'. Σε κάθε άλλη περίπτωση, δεν θα σταλεί ειδοποίηση.", + "latest-timeseries": "Τελευταία δεδομένα χρονοσειράς", + "timeseries-keys": "Κλειδιά χρονοσειρών", + "timeseries-keys-required": "Πρέπει να επιλεγεί τουλάχιστον ένα κλειδί χρονοσειράς.", "add-timeseries-key": "Προσθήκη κλειδιού χρονικής σειράς", "add-message-field": "Προσθήκη πεδίου μηνύματος", "relation-search-parameters": "Παράμετροι αναζήτησης σχέσεων", @@ -4759,14 +4784,14 @@ "copy-from": "Αντιγραφή από", "data-to-metadata": "Δεδομένα σε μεταδεδομένα", "metadata-to-data": "Μεταδεδομένα σε δεδομένα", - "use-regular-expression-hint": "Χρησιμοποιήστε κανονική έκφραση για αντιγραφή κλειδιών με βάση μοτίβα.\n\nΣυμβουλές:\nΠατήστε 'Enter' για να ολοκληρώσετε την εισαγωγή ονόματος πεδίου.\nΠατήστε 'Backspace' για διαγραφή.\nΥποστηρίζονται πολλαπλά ονόματα.", + "use-regular-expression-hint": "Χρησιμοποιήστε κανονική έκφραση για αντιγραφή κλειδιών κατά μοτίβο.\n\nΣυμβουλές & κόλπα:\nΠατήστε 'Enter' για να ολοκληρώσετε την εισαγωγή ονόματος πεδίου.\nΠατήστε 'Backspace' για να διαγράψετε όνομα πεδίου. Υποστηρίζονται πολλαπλά ονόματα πεδίων.", "interval": "Διάστημα", - "interval-required": "Απαιτείται διάστημα", + "interval-required": "Το διάστημα είναι υποχρεωτικό", "interval-hint": "Χρονικό διάστημα αποφυγής διπλοτύπων σε δευτερόλεπτα.", "interval-min-error": "Ελάχιστη επιτρεπτή τιμή είναι 1", "max-pending-msgs": "Μέγιστος αριθμός εκκρεμών μηνυμάτων", - "max-pending-msgs-hint": "Μέγιστος αριθμός μηνυμάτων στη μνήμη για κάθε μοναδικό id αποφυγής διπλοτύπων.", - "max-pending-msgs-required": "Απαιτείται μέγιστος αριθμός εκκρεμών μηνυμάτων", + "max-pending-msgs-hint": "Μέγιστος αριθμός μηνυμάτων που αποθηκεύονται στη μνήμη για κάθε μοναδικό αναγνωριστικό αποφυγής διπλοτύπων.", + "max-pending-msgs-required": "Ο μέγιστος αριθμός εκκρεμών μηνυμάτων είναι υποχρεωτικός", "max-pending-msgs-max-error": "Μέγιστη επιτρεπτή τιμή είναι 1000", "max-pending-msgs-min-error": "Ελάχιστη επιτρεπτή τιμή είναι 1", "max-retries": "Μέγιστες επαναλήψεις", @@ -4795,24 +4820,24 @@ "new-key-name": "Νέο όνομα κλειδιού", "new-key-name-required": "Απαιτείται νέο όνομα κλειδιού", "metadata-keys": "Ονόματα πεδίων μεταδεδομένων", - "json-path-expression": "Έκφραση JSON path", - "json-path-expression-required": "Απαιτείται έκφραση JSON path", - "json-path-expression-hint": "Το JSONPath καθορίζει διαδρομή προς στοιχείο JSON. Το '$' είναι η ρίζα.", + "json-path-expression": "Έκφραση διαδρομής JSON", + "json-path-expression-required": "Η έκφραση διαδρομής JSON είναι υποχρεωτική", + "json-path-expression-hint": "Η JSONPath καθορίζει μια διαδρομή προς ένα στοιχείο ή ένα σύνολο στοιχείων σε μια δομή JSON. Το '$' αντιπροσωπεύει το ριζικό αντικείμενο ή πίνακα.", "relations-query": "Ερώτημα σχέσεων", "device-relations-query": "Ερώτημα σχέσεων συσκευής", "max-relation-level": "Μέγιστο επίπεδο σχέσης", - "max-relation-level-error": "Η τιμή πρέπει να είναι > 0 ή να μην οριστεί.", - "max-relation-level-invalid": "Η τιμή πρέπει να είναι ακέραιος.", + "max-relation-level-error": "Η τιμή πρέπει να είναι μεγαλύτερη από 0 ή μη καθορισμένη.", + "max-relation-level-invalid": "Η τιμή πρέπει να είναι ακέραιος αριθμός.", "relation-type": "Τύπος σχέσης", "relation-type-pattern": "Μοτίβο τύπου σχέσης", - "relation-type-pattern-required": "Απαιτείται μοτίβο τύπου σχέσης", - "relation-types-list": "Τύποι σχέσεων για διάδοση", - "relation-types-list-hint": "Αν δεν επιλεγούν τύποι, διαδίδονται χωρίς φιλτράρισμα.", + "relation-type-pattern-required": "Το μοτίβο τύπου σχέσης είναι υποχρεωτικό", + "relation-types-list": "Τύποι σχέσεων για προώθηση", + "relation-types-list-hint": "Αν δεν επιλεγούν τύποι σχέσεων για προώθηση, οι συναγερμοί θα προωθούνται χωρίς φιλτράρισμα κατά τύπο σχέσης.", "unlimited-level": "Απεριόριστο επίπεδο", "latest-telemetry": "Τελευταία τηλεμετρία", "add-telemetry-key": "Προσθήκη κλειδιού τηλεμετρίας", "delete-from": "Διαγραφή από", - "use-regular-expression-delete-hint": "Χρησιμοποιήστε κανονικές εκφράσεις για διαγραφή με βάση μοτίβα.\n\nΣυμβουλές:\n'Enter' για επιβεβαίωση, 'Backspace' για διαγραφή.\nΥποστηρίζονται πολλά πεδία.", + "use-regular-expression-delete-hint": "Χρησιμοποιήστε κανονική έκφραση για διαγραφή κλειδιών κατά μοτίβο.\n\nΣυμβουλές & κόλπα:\nΠατήστε 'Enter' για να ολοκληρώσετε την εισαγωγή ονόματος πεδίου.\nΠατήστε 'Backspace' για διαγραφή ονόματος πεδίου.\nΥποστηρίζονται πολλαπλά ονόματα πεδίων.", "fetch-into": "Ανάκτηση σε", "attr-mapping": "Αντιστοίχιση χαρακτηριστικών:", "source-attribute": "Κλειδί προέλευσης χαρακτηριστικού", @@ -4829,19 +4854,19 @@ "fetch-circle-parameter-info-from-metadata-hint": "Το μεταδεδομένο '{{perimeterKeyName}}' πρέπει να έχει μορφή: {\"latitude\":48.196, \"longitude\":24.6532, \"radius\":100.0, \"radiusUnit\":\"METER\"}", "fetch-poligon-parameter-info-from-metadata-hint": "Το μεταδεδομένο '{{perimeterKeyName}}' πρέπει να έχει μορφή: [[48.19736,24.65235],[48.19800,24.65060],...,[48.19849,24.65420]]", "short-templatization-tooltip": "Χρησιμοποιήστε $[messageKey] και ${metadataKey} για εξαγωγή τιμής.", - "fields-mapping-required": "Απαιτείται τουλάχιστον μία αντιστοίχιση πεδίου.", - "at-least-one-field-required": "Πρέπει να καθοριστεί τουλάχιστον ένα πεδίο με τιμή.", - "originator-fields-sv-map-hint": "Τα πεδία προορισμού υποστηρίζουν templatization με $[messageKey] και ${metadataKey}.", - "sv-map-hint": "Μόνο τα πεδία προορισμού υποστηρίζουν templatization με $[messageKey] και ${metadataKey}.", + "fields-mapping-required": "Πρέπει να καθοριστεί τουλάχιστον μία αντιστοίχιση πεδίου.", + "at-least-one-field-required": "Πρέπει να δοθεί τιμή τουλάχιστον σε ένα πεδίο εισόδου.", + "originator-fields-sv-map-hint": "Τα πεδία κλειδιών προορισμού υποστηρίζουν παραμετροποίηση. Χρησιμοποιήστε $[messageKey] για εξαγωγή τιμής από το μήνυμα και ${metadataKey} για εξαγωγή από τα μεταδεδομένα.", + "sv-map-hint": "Μόνο τα πεδία κλειδιών προορισμού υποστηρίζουν παραμετροποίηση. Χρησιμοποιήστε $[messageKey] για εξαγωγή τιμής από το μήνυμα και ${metadataKey} για εξαγωγή από τα μεταδεδομένα.", "source-field": "Πεδίο προέλευσης", - "source-field-required": "Απαιτείται πεδίο προέλευσης.", - "originator-source": "Προέλευση", - "new-originator": "Νέα προέλευση", + "source-field-required": "Το πεδίο προέλευσης είναι υποχρεωτικό.", + "originator-source": "Προέλευση αποστολέα", + "new-originator": "Νέος αποστολέας", "originator-customer": "Πελάτης", "originator-tenant": "Ενοικιαστής", - "originator-related": "Συσχετιζόμενη οντότητα", + "originator-related": "Σχετική οντότητα", "originator-alarm-originator": "Προέλευση συναγερμού", - "originator-entity": "Οντότητα με μοτίβο ονόματος", + "originator-entity": "Οντότητα βάσει προτύπου ονόματος", "clone-message": "Κλωνοποίηση μηνύματος", "transform": "Μετασχηματισμός", "default-ttl": "Προεπιλεγμένο TTL", @@ -4860,23 +4885,23 @@ "min-generation-frequency-message": "Ελάχιστο 60 δευτερόλεπτα επιτρέπεται.", "script-lang-tbel": "TBEL", "script-lang-js": "JS", - "use-metadata-period-in-seconds-patterns": "Χρήση μοτίβου περιόδου από μεταδεδομένα", - "use-metadata-period-in-seconds-patterns-hint": "Αν επιλεγεί, θα χρησιμοποιείται μοτίβο περιόδου σε δευτερόλεπτα από μεταδεδομένα ή δεδομένα.", - "period-in-seconds-pattern": "Μοτίβο περιόδου σε δευτερόλεπτα", - "period-in-seconds-pattern-required": "Απαιτείται μοτίβο περιόδου.", - "min-period-seconds-message": "Μόνο 60 δευτερόλεπτα ελάχιστο επιτρέπεται.", - "originator": "Προέλευση", + "use-metadata-period-in-seconds-patterns": "Χρήση μοτίβου διάρκειας σε δευτερόλεπτα", + "use-metadata-period-in-seconds-patterns-hint": "Αν επιλεγεί, ο κόμβος κανόνα θα χρησιμοποιεί μοτίβο διάρκειας σε δευτερόλεπτα από τα μεταδεδομένα ή τα δεδομένα του μηνύματος, υποθέτοντας ότι οι διάρκειες είναι σε δευτερόλεπτα.", + "period-in-seconds-pattern": "Μοτίβο διάρκειας σε δευτερόλεπτα", + "period-in-seconds-pattern-required": "Το μοτίβο διάρκειας σε δευτερόλεπτα είναι υποχρεωτικό", + "min-period-seconds-message": "Επιτρέπεται μόνο ελάχιστη διάρκεια 60 δευτερολέπτων.", + "originator": "Αποστολέας", "message-body": "Σώμα μηνύματος", "message-metadata": "Μεταδεδομένα μηνύματος", "generate": "Δημιουργία", - "current-rule-node": "Τρέχον Node Κανόνα", + "current-rule-node": "Τρέχων κόμβος κανόνα", "current-tenant": "Τρέχων ενοικιαστής", "generator-function": "Συνάρτηση δημιουργίας", "test-generator-function": "Δοκιμή συνάρτησης δημιουργίας", - "generator": "Γεννήτρια", - "test-filter-function": "Δοκιμή συνάρτησης φίλτρου", - "test-switch-function": "Δοκιμή συνάρτησης διακόπτη", - "test-transformer-function": "Δοκιμή συνάρτησης μετασχηματιστή", + "generator": "Δημιουργός", + "test-filter-function": "Δοκιμή συνάρτησης φιλτραρίσματος", + "test-switch-function": "Δοκιμή συνάρτησης εναλλαγής", + "test-transformer-function": "Δοκιμή συνάρτησης μετασχηματισμού", "transformer": "Μετασχηματιστής", "alarm-create-condition": "Συνθήκη δημιουργίας συναγερμού", "test-condition-function": "Δοκιμή συνθήκης", @@ -4907,22 +4932,22 @@ "from-metadata": "Από μεταδεδομένα", "to-template": "Προς", "to-template-required": "Απαιτείται πεδίο Προς", - "mail-address-list-template-hint": "Λίστα διευθύνσεων χωρισμένη με κόμμα, χρησιμοποιήστε ${metadataKey} για τιμή από τα μεταδεδομένα, $[messageKey] για τιμή από το σώμα του μηνύματος", - "cc-template": "Cc", - "bcc-template": "Bcc", + "mail-address-list-template-hint": "Λίστα διευθύνσεων χωρισμένη με κόμμα, χρησιμοποιήστε ${metadataKey} για τιμή από τα μεταδεδομένα, $[messageKey] για τιμή από το σώμα του μηνύματος", + "cc-template": "Κοινοποίηση (Cc)", + "bcc-template": "Κρυφή κοινοποίηση (Bcc)", "subject-template": "Θέμα", - "subject-template-required": "Απαιτείται πεδίο Θέμα", - "body-template": "Σώμα", - "body-template-required": "Απαιτείται πεδίο Σώμα", - "dynamic-mail-body-type": "Δυναμικός τύπος σώματος", + "subject-template-required": "Το πρότυπο θέματος είναι υποχρεωτικό", + "body-template": "Κείμενο", + "body-template-required": "Το πρότυπο κειμένου είναι υποχρεωτικό", + "dynamic-mail-body-type": "Δυναμικός τύπος σώματος email", "mail-body-type": "Τύπος σώματος email", "body-type-template": "Πρότυπο τύπου σώματος", "reply-routing-configuration": "Διαμόρφωση δρομολόγησης απάντησης", - "rpc-reply-routing-configuration-hint": "Καθορίζει metadata κλειδιά για προσδιορισμό υπηρεσίας, συνεδρίας και αιτήματος για αποστολή απάντησης.", - "reply-routing-configuration-hint": "Καθορίζει metadata κλειδιά για προσδιορισμό υπηρεσίας και αιτήματος για απάντηση.", - "request-id-metadata-attribute": "Id Αιτήματος", - "service-id-metadata-attribute": "Id Υπηρεσίας", - "session-id-metadata-attribute": "Id Συνεδρίας", + "rpc-reply-routing-configuration-hint": "Αυτές οι ρυθμίσεις καθορίζουν τα ονόματα των κλειδιών μεταδεδομένων που χρησιμοποιούνται για τον προσδιορισμό της υπηρεσίας, της συνεδρίας και του αιτήματος για την αποστολή απάντησης.", + "reply-routing-configuration-hint": "Αυτές οι ρυθμίσεις καθορίζουν τα ονόματα των κλειδιών μεταδεδομένων που χρησιμοποιούνται για τον προσδιορισμό της υπηρεσίας και του αιτήματος για την αποστολή απάντησης.", + "request-id-metadata-attribute": "Αναγνωριστικό αιτήματος", + "service-id-metadata-attribute": "Αναγνωριστικό υπηρεσίας", + "session-id-metadata-attribute": "Αναγνωριστικό συνεδρίας", "timeout-sec": "Χρονικό όριο (δευτερόλεπτα)", "timeout-required": "Απαιτείται χρονικό όριο", "min-timeout-message": "Μόνο τιμή 0 επιτρέπεται ως ελάχιστο χρονικό όριο.", @@ -5007,26 +5032,26 @@ "gcp-service-account-key-required": "Απαιτείται αρχείο κλειδιού GCP", "pubsub-topic-name": "Όνομα θέματος", "pubsub-topic-name-required": "Απαιτείται όνομα θέματος", - "message-attributes": "Ιδιότητες μηνύματος", - "message-attributes-hint": "Χρησιμοποιήστε ${metadataKey} για τιμή από τα μεταδεδομένα, $[messageKey] για τιμή από το σώμα του μηνύματος στα πεδία ονόματος/τιμής", - "connect-timeout": "Χρονικό όριο σύνδεσης (δευτ)", - "connect-timeout-required": "Απαιτείται χρονικό όριο σύνδεσης.", - "connect-timeout-range": "Το χρονικό όριο πρέπει να είναι από 1 έως 200.", + "message-attributes": "Χαρακτηριστικά μηνύματος", + "message-attributes-hint": "Χρησιμοποιήστε ${metadataKey} για τιμή από τα μεταδεδομένα και $[messageKey] για τιμή από το σώμα του μηνύματος στα πεδία ονόματος/τιμής", + "connect-timeout": "Χρονικό όριο σύνδεσης (δευτ.)", + "connect-timeout-required": "Το χρονικό όριο σύνδεσης είναι υποχρεωτικό.", + "connect-timeout-range": "Το χρονικό όριο σύνδεσης πρέπει να είναι από 1 έως 200.", "client-id": "Client ID", - "client-id-hint": "Προαιρετικό. Αφήστε κενό για αυτόματη δημιουργία. Αν δοθεί, να είναι μοναδικό.", - "append-client-id-suffix": "Προσθήκη ID υπηρεσίας στο Client ID", - "client-id-suffix-hint": "Εφαρμόζεται όταν δίνεται Client ID. Προσθέτει το ID υπηρεσίας ως επίθημα για αποφυγή συγκρούσεων.", - "device-id": "ID Συσκευής", - "device-id-required": "Απαιτείται ID Συσκευής", + "client-id-hint": "Προαιρετικό. Αφήστε κενό για αυτόματη δημιουργία Client ID. Προσοχή κατά τον καθορισμό του Client ID. Οι περισσότεροι MQTT brokers δεν επιτρέπουν πολλαπλές συνδέσεις με το ίδιο Client ID. Για να συνδεθείτε σε τέτοιους brokers, το Client ID σας πρέπει να είναι μοναδικό. Όταν η πλατφόρμα εκτελείται σε λειτουργία μικροϋπηρεσιών, κάθε μικροϋπηρεσία θα εκτελεί αντίγραφο του rule node. Αυτό μπορεί να προκαλέσει αποτυχίες. Για αποφυγή, ενεργοποιήστε την επιλογή \"Προσθήκη Service ID ως επίθημα στο Client ID\" παρακάτω.", + "append-client-id-suffix": "Προσθήκη Service ID ως επίθημα στο Client ID", + "client-id-suffix-hint": "Προαιρετικό. Εφαρμόζεται όταν το \"Client ID\" καθορίζεται ρητά. Αν επιλεγεί, το Service ID θα προστεθεί ως επίθημα στο Client ID. Χρήσιμο για αποφυγή αποτυχιών σε λειτουργία μικροϋπηρεσιών.", + "device-id": "Device ID", + "device-id-required": "Το Device ID είναι υποχρεωτικό.", "clean-session": "Καθαρή συνεδρία", "enable-ssl": "Ενεργοποίηση SSL", "credentials": "Διαπιστευτήρια", "credentials-type": "Τύπος διαπιστευτηρίων", - "credentials-type-required": "Απαιτείται τύπος διαπιστευτηρίων.", + "credentials-type-required": "Ο τύπος διαπιστευτηρίων είναι υποχρεωτικός.", "credentials-anonymous": "Ανώνυμα", "credentials-basic": "Βασικά", "credentials-pem": "PEM", - "credentials-pem-hint": "Απαιτείται τουλάχιστον το αρχείο πιστοποιητικού Server CA ή το ζεύγος Client certificate και Client private key", + "credentials-pem-hint": "Απαιτείται τουλάχιστον αρχείο Server CA ή ζεύγος αρχείων Client certificate και Client private key", "credentials-sas": "Shared Access Signature", "sas-key": "SAS Κλειδί", "sas-key-required": "Απαιτείται SAS Κλειδί.", @@ -5043,23 +5068,23 @@ "private-key-password": "Κωδικός ιδιωτικού κλειδιού", "use-system-smtp-settings": "Χρήση ρυθμίσεων SMTP του συστήματος", "use-metadata-dynamic-interval": "Χρήση δυναμικού διαστήματος", - "metadata-dynamic-interval-hint": "Υποστηρίζεται τεμπλοποίηση στα πεδία. Τιμές σε milliseconds.", - "use-metadata-interval-patterns-hint": "Αν επιλεγεί, χρησιμοποιούνται μοτίβα από metadata για αρχή/τέλος διαστήματος (ms).", + "metadata-dynamic-interval-hint": "Τα πεδία εισόδου για την αρχή και το τέλος του διαστήματος υποστηρίζουν παραμετροποίηση. Σημειώστε ότι η τιμή του προτύπου που αντικαθίσταται πρέπει να είναι σε χιλιοστά του δευτερολέπτου. Χρησιμοποιήστε $[messageKey] για εξαγωγή τιμής από το μήνυμα και ${metadataKey} για εξαγωγή από τα μεταδεδομένα.", + "use-metadata-interval-patterns-hint": "Αν επιλεγεί, ο κόμβος κανόνα θα χρησιμοποιεί μοτίβα για την αρχή και το τέλος του διαστήματος από τα μεταδεδομένα ή τα δεδομένα του μηνύματος, υποθέτοντας ότι τα διαστήματα είναι σε χιλιοστά του δευτερολέπτου.", "use-message-alarm-data": "Χρήση δεδομένων συναγερμού από το μήνυμα", "overwrite-alarm-details": "Αντικατάσταση λεπτομερειών συναγερμού", "use-alarm-severity-pattern": "Χρήση μοτίβου σοβαρότητας συναγερμού", - "check-all-keys": "Έλεγχος παρουσίας όλων των πεδίων", - "check-all-keys-hint": "Αν επιλεγεί, ελέγχεται η παρουσία όλων των καθορισμένων κλειδιών.", + "check-all-keys": "Έλεγχος ότι όλα τα καθορισμένα πεδία είναι παρόντα", + "check-all-keys-hint": "Αν επιλεγεί, ελέγχει ότι όλα τα καθορισμένα κλειδιά υπάρχουν στα δεδομένα και τα μεταδεδομένα του μηνύματος.", "check-relation-to-specific-entity": "Έλεγχος σχέσης με συγκεκριμένη οντότητα", - "check-relation-to-specific-entity-tooltip": "Αν ενεργοποιηθεί, ελέγχει για συγκεκριμένη οντότητα αντί για οποιαδήποτε.", - "check-relation-hint": "Ελέγχει ύπαρξη σχέσης με βάση κατεύθυνση και τύπο.", + "check-relation-to-specific-entity-tooltip": "Αν είναι ενεργό, ελέγχει την ύπαρξη σχέσης με μία συγκεκριμένη οντότητα, διαφορετικά ελέγχει για οποιαδήποτε οντότητα. Και στις δύο περιπτώσεις, η αναζήτηση γίνεται με βάση την κατεύθυνση και τον τύπο σχέσης.", + "check-relation-hint": "Ελέγχει την ύπαρξη σχέσης με συγκεκριμένη ή οποιαδήποτε οντότητα βάσει κατεύθυνσης και τύπου σχέσης.", "delete-relation-with-specific-entity": "Διαγραφή σχέσης με συγκεκριμένη οντότητα", - "delete-relation-with-specific-entity-hint": "Αν ενεργοποιηθεί, διαγράφει μόνο τη συγκεκριμένη σχέση.", - "delete-relation-hint": "Διαγράφει σχέσεις από originator προς οντότητα/οντότητες με βάση κατεύθυνση/τύπο.", + "delete-relation-with-specific-entity-hint": "Αν είναι ενεργό, θα διαγράψει τη σχέση μόνο με μία συγκεκριμένη οντότητα. Διαφορετικά, θα διαγραφεί η σχέση με όλες τις οντότητες που ταιριάζουν.", + "delete-relation-hint": "Διαγράφει τη σχέση από τον αποστολέα του εισερχόμενου μηνύματος προς την καθορισμένη οντότητα ή λίστα οντοτήτων με βάση την κατεύθυνση και τον τύπο.", "remove-current-relations": "Αφαίρεση τρεχουσών σχέσεων", - "remove-current-relations-hint": "Αφαιρεί σχέσεις από τον originator.", - "change-originator-to-related-entity": "Αλλαγή originator σε σχετική οντότητα", - "change-originator-to-related-entity-hint": "Επεξεργασία μηνύματος ως από άλλη οντότητα.", + "remove-current-relations-hint": "Αφαιρεί τις τρέχουσες σχέσεις από τον αποστολέα του εισερχόμενου μηνύματος βάσει κατεύθυνσης και τύπου.", + "change-originator-to-related-entity": "Αλλαγή αποστολέα σε σχετική οντότητα", + "change-originator-to-related-entity-hint": "Χρησιμοποιείται για την επεξεργασία του μηνύματος ως μήνυμα από άλλη οντότητα.", "start-interval": "Έναρξη διαστήματος", "end-interval": "Τέλος διαστήματος", "start-interval-required": "Απαιτείται έναρξη διαστήματος.", @@ -5077,25 +5102,25 @@ "enable-tls": "Ενεργοποίηση TLS", "tls-version": "Έκδοση TLS", "enable-proxy": "Ενεργοποίηση proxy", - "use-system-proxy-properties": "Χρήση proxy ρυθμίσεων συστήματος", - "proxy-host": "Host proxy", - "proxy-host-required": "Απαιτείται proxy host.", + "use-system-proxy-properties": "Χρήση ρυθμίσεων proxy συστήματος", + "proxy-host": "Διακομιστής proxy", + "proxy-host-required": "Ο διακομιστής proxy είναι υποχρεωτικός.", "proxy-port": "Θύρα proxy", - "proxy-port-required": "Απαιτείται θύρα proxy.", + "proxy-port-required": "Η θύρα proxy είναι υποχρεωτική.", "proxy-port-range": "Η θύρα proxy πρέπει να είναι από 1 έως 65535.", "proxy-user": "Χρήστης proxy", "proxy-password": "Κωδικός proxy", "proxy-scheme": "Σχήμα proxy", - "numbers-to-template": "Πρότυπο τηλεφώνων", - "numbers-to-template-required": "Απαιτείται πρότυπο τηλεφώνων", - "numbers-to-template-hint": "Αριθμοί τηλεφώνου χωρισμένοι με κόμμα, χρησιμοποιήστε ${metadataKey} για τιμή από τα μεταδεδομένα, $[messageKey] για τιμή από το σώμα του μηνύματος", + "numbers-to-template": "Πρότυπο αποδεκτών αριθμών τηλεφώνου", + "numbers-to-template-required": "Το πρότυπο αποδεκτών αριθμών τηλεφώνου είναι υποχρεωτικό", + "numbers-to-template-hint": "Αριθμοί τηλεφώνου χωρισμένοι με κόμμα, χρησιμοποιήστε ${metadataKey} για τιμή από τα μεταδεδομένα, $[messageKey] για τιμή από το σώμα του μηνύματος", "sms-message-template": "Πρότυπο μηνύματος SMS", - "sms-message-template-required": "Απαιτείται πρότυπο μηνύματος SMS", - "use-system-sms-settings": "Χρήση ρυθμίσεων SMS συστήματος", - "min-period-0-seconds-message": "Μόνο τιμή 0 επιτρέπεται ως ελάχιστη περίοδος.", + "sms-message-template-required": "Το πρότυπο μηνύματος SMS είναι υποχρεωτικό", + "use-system-sms-settings": "Χρήση ρυθμίσεων SMS του συστήματος", + "min-period-0-seconds-message": "Μόνο 0 δευτερόλεπτα επιτρέπονται ως ελάχιστη διάρκεια.", "max-pending-messages": "Μέγιστος αριθμός εκκρεμών μηνυμάτων", - "max-pending-messages-required": "Απαιτείται μέγιστος αριθμός εκκρεμών μηνυμάτων.", - "max-pending-messages-range": "Ο μέγιστος αριθμός εκκρεμών μηνυμάτων πρέπει να είναι εντός του εύρους από 1 έως 100000.", + "max-pending-messages-required": "Ο μέγιστος αριθμός εκκρεμών μηνυμάτων είναι υποχρεωτικός.", + "max-pending-messages-range": "Ο μέγιστος αριθμός εκκρεμών μηνυμάτων πρέπει να είναι από 1 έως 100000.", "originator-types-filter": "Φίλτρο τύπων αποστολέα", "interval-seconds": "Διάστημα σε δευτερόλεπτα", "interval-seconds-required": "Απαιτείται διάστημα.", @@ -5119,28 +5144,28 @@ "email-sender": "Αποστολέας Email", "fields-to-check": "Πεδία προς έλεγχο", "add-detail": "Προσθήκη λεπτομέρειας", - "check-all-keys-tooltip": "Εάν ενεργοποιηθεί, ελέγχει την παρουσία όλων των πεδίων που αναφέρονται στα ονόματα πεδίων μηνύματος και μεταδεδομένων στο εισερχόμενο μήνυμα και τα μεταδεδομένα του.", - "fields-to-check-hint": "Πατήστε \"Enter\" για να ολοκληρώσετε την εισαγωγή πεδίου. Υποστηρίζονται πολλά πεδία.", + "check-all-keys-tooltip": "Αν είναι ενεργό, ελέγχει την παρουσία όλων των πεδίων που αναφέρονται στα δεδομένα και τα μεταδεδομένα του εισερχόμενου μηνύματος.", + "fields-to-check-hint": "Πατήστε \"Enter\" για να ολοκληρώσετε την εισαγωγή ονόματος πεδίου. Υποστηρίζονται πολλαπλά ονόματα πεδίων.", "entity-details-list-empty": "Πρέπει να επιλεγεί τουλάχιστον μία λεπτομέρεια.", "alarm-status": "Κατάσταση συναγερμού", "alarm-required": "Πρέπει να επιλεγεί τουλάχιστον μία κατάσταση συναγερμού.", - "no-entity-details-matching": "Δεν βρέθηκαν αντίστοιχες λεπτομέρειες οντοτήτων.", + "no-entity-details-matching": "Δεν βρέθηκαν αντιστοιχίες στις λεπτομέρειες οντοτήτων.", "custom-table-name": "Προσαρμοσμένο όνομα πίνακα", - "custom-table-name-required": "Απαιτείται όνομα πίνακα", - "custom-table-hint": "Ο πίνακας πρέπει να έχει δημιουργηθεί στον Cassandra cluster και το όνομά του να ξεκινά με 'cs_tb_'. Εισαγάγετε το όνομα χωρίς το πρόθεμα.", + "custom-table-name-required": "Το όνομα πίνακα είναι υποχρεωτικό", + "custom-table-hint": "Ο πίνακας πρέπει να έχει δημιουργηθεί στο Cassandra cluster και το όνομά του να ξεκινά με το πρόθεμα 'cs_tb_' ώστε να αποφευχθεί η εισαγωγή δεδομένων στους κοινούς πίνακες του TB. Εισάγετε το όνομα χωρίς το πρόθεμα 'cs_tb_'.", "message-field": "Πεδίο μηνύματος", - "message-field-required": "Απαιτείται πεδίο μηνύματος.", + "message-field-required": "Το πεδίο μηνύματος είναι υποχρεωτικό.", "table-col": "Στήλη πίνακα", - "table-col-required": "Απαιτείται στήλη πίνακα.", + "table-col-required": "Η στήλη πίνακα είναι υποχρεωτική.", "latitude-field-name": "Όνομα πεδίου γεωγραφικού πλάτους", "longitude-field-name": "Όνομα πεδίου γεωγραφικού μήκους", - "latitude-field-name-required": "Απαιτείται όνομα πεδίου γεωγραφικού πλάτους.", - "longitude-field-name-required": "Απαιτείται όνομα πεδίου γεωγραφικού μήκους.", + "latitude-field-name-required": "Το όνομα πεδίου γεωγραφικού πλάτους είναι υποχρεωτικό.", + "longitude-field-name-required": "Το όνομα πεδίου γεωγραφικού μήκους είναι υποχρεωτικό.", "fetch-perimeter-info-from-metadata": "Ανάκτηση πληροφοριών περιμέτρου από μεταδεδομένα", - "fetch-perimeter-info-from-metadata-tooltip": "Εάν ο τύπος περιμέτρου είναι 'Polygon', η τιμή του πεδίου '{{perimeterKeyName}}' χρησιμοποιείται απευθείας. Αν είναι 'Circle', το πεδίο αναλύεται για εξαγωγή 'latitude', 'longitude', 'radius', 'radiusUnit'.", + "fetch-perimeter-info-from-metadata-tooltip": "Αν ο τύπος περιμέτρου έχει οριστεί ως 'Πολύγωνο', η τιμή του πεδίου μεταδεδομένων '{{perimeterKeyName}}' θα χρησιμοποιηθεί ως ορισμός περιμέτρου χωρίς επιπλέον ανάλυση. Διαφορετικά, αν ο τύπος περιμέτρου είναι 'Κύκλος', η τιμή του πεδίου μεταδεδομένων '{{perimeterKeyName}}' θα αναλυθεί ώστε να εξαχθούν τα πεδία 'latitude', 'longitude', 'radius', 'radiusUnit' που χρησιμοποιούνται για τον ορισμό κυκλικής περιμέτρου.", "perimeter-key-name": "Όνομα κλειδιού περιμέτρου", - "perimeter-key-name-hint": "Όνομα πεδίου μεταδεδομένων που περιέχει πληροφορίες περιμέτρου.", - "perimeter-key-name-required": "Απαιτείται όνομα κλειδιού περιμέτρου.", + "perimeter-key-name-hint": "Όνομα πεδίου μεταδεδομένων που περιλαμβάνει πληροφορίες περιμέτρου.", + "perimeter-key-name-required": "Το όνομα κλειδιού περιμέτρου είναι υποχρεωτικό.", "perimeter-circle": "Κύκλος", "perimeter-polygon": "Πολύγωνο", "perimeter-type": "Τύπος περιμέτρου", @@ -5158,20 +5183,20 @@ "range": "Απόσταση", "range-required": "Απαιτείται απόσταση.", "polygon-definition": "Ορισμός πολυγώνου", - "polygon-definition-required": "Απαιτείται ορισμός πολυγώνου.", - "polygon-definition-hint": "Χρησιμοποιήστε μορφή: [[lat1,lon1],[lat2,lon2],...,[latN,lonN]].", + "polygon-definition-required": "Ο ορισμός πολυγώνου είναι υποχρεωτικός.", + "polygon-definition-hint": "Χρησιμοποιήστε την εξής μορφή για χειροκίνητο ορισμό πολυγώνου: [[lat1,lon1],[lat2,lon2], ... ,[latN,lonN]].", "min-inside-duration": "Ελάχιστη διάρκεια εντός", - "min-inside-duration-value-required": "Απαιτείται ελάχιστη διάρκεια εντός.", + "min-inside-duration-value-required": "Η ελάχιστη διάρκεια εντός είναι υποχρεωτική", "min-inside-duration-time-unit": "Μονάδα χρόνου ελάχιστης διάρκειας εντός", "min-outside-duration": "Ελάχιστη διάρκεια εκτός", - "min-outside-duration-value-required": "Απαιτείται ελάχιστη διάρκεια εκτός.", + "min-outside-duration-value-required": "Η ελάχιστη διάρκεια εκτός είναι υποχρεωτική", "min-outside-duration-time-unit": "Μονάδα χρόνου ελάχιστης διάρκειας εκτός", - "tell-failure-if-absent": "Αναφορά αποτυχίας αν απουσιάζει", - "tell-failure-if-absent-hint": "Αν λείπει κάποιο κλειδί, θα επιστραφεί μήνυμα \"Failure\".", - "get-latest-value-with-ts": "Ανάκτηση χρονικής σήμανσης για την τελευταία τιμή", - "get-latest-value-with-ts-hint": "Αν ενεργοποιηθεί, οι τιμές τηλεμετρίας θα περιλαμβάνουν και χρονική σήμανση.", + "tell-failure-if-absent": "Αναφορά αποτυχίας", + "tell-failure-if-absent-hint": "Αν τουλάχιστον ένα από τα επιλεγμένα κλειδιά δεν υπάρχει, το εξερχόμενο μήνυμα θα αναφέρει \"Αποτυχία\".", + "get-latest-value-with-ts": "Ανάκτηση χρονικής σήμανσης για τις τελευταίες τιμές τηλεμετρίας", + "get-latest-value-with-ts-hint": "Αν επιλεγεί, οι τελευταίες τιμές τηλεμετρίας θα περιλαμβάνουν και χρονική σήμανση, π.χ.: \"temp\": \"{\"ts\":1574329385897, \"value\":42}\"", "ignore-null-strings": "Αγνόηση κενών συμβολοσειρών", - "ignore-null-strings-hint": "Αν ενεργοποιηθεί, οι κενές τιμές αγνοούνται.", + "ignore-null-strings-hint": "Αν επιλεγεί, ο κόμβος κανόνα θα αγνοεί πεδία οντοτήτων με κενή τιμή.", "add-metadata-key-values-as-kafka-headers": "Προσθήκη μεταδεδομένων στα Kafka headers", "add-metadata-key-values-as-kafka-headers-hint": "Τα ζεύγη μεταδεδομένων προστίθενται ως headers στην Kafka εγγραφή.", "charset-encoding": "Κωδικοποίηση χαρακτήρων", @@ -5182,33 +5207,33 @@ "charset-utf-16be": "UTF-16BE", "charset-utf-16le": "UTF-16LE", "charset-utf-16": "UTF-16", - "select-queue-hint": "Μπορείτε να επιλέξετε από τη λίστα ή να προσθέσετε δικό σας όνομα.", - "device-profile-node-hint": "Χρήσιμο για συνθήκες διάρκειας/επαναλήψεων.", - "persist-alarm-rules": "Αποθήκευση κατάστασης κανόνων συναγερμού", - "persist-alarm-rules-hint": "Εάν ενεργοποιηθεί, η κατάσταση θα αποθηκεύεται στη βάση.", - "fetch-alarm-rules": "Ανάκτηση κατάστασης κανόνων συναγερμού", - "fetch-alarm-rules-hint": "Εάν ενεργοποιηθεί, η κατάσταση αποκαθίσταται κατά την αρχικοποίηση.", - "input-value-key": "Κλειδί εισερχόμενης τιμής", - "input-value-key-required": "Απαιτείται κλειδί εισερχόμενης τιμής.", + "select-queue-hint": "Το όνομα της ουράς μπορεί να επιλεγεί από μια λίστα ή να εισαχθεί προσαρμοσμένο όνομα.", + "device-profile-node-hint": "Χρήσιμο όταν υπάρχουν συνθήκες διάρκειας ή επανάληψης για να διασφαλιστεί η συνέχεια της αξιολόγησης κατάστασης του συναγερμού.", + "persist-alarm-rules": "Διατήρηση κατάστασης κανόνων συναγερμών", + "persist-alarm-rules-hint": "Αν είναι ενεργό, ο κόμβος κανόνα θα αποθηκεύει την κατάσταση επεξεργασίας στη βάση δεδομένων.", + "fetch-alarm-rules": "Ανάκτηση κατάστασης κανόνων συναγερμών", + "fetch-alarm-rules-hint": "Αν είναι ενεργό, ο κόμβος κανόνα θα επαναφέρει την κατάσταση επεξεργασίας κατά την εκκίνηση και θα διασφαλίζει ότι οι συναγερμοί θα ενεργοποιούνται ακόμη και μετά από επανεκκινήσεις του διακομιστή. Διαφορετικά, η κατάσταση θα επαναφέρεται όταν ληφθεί το πρώτο μήνυμα από τη συσκευή.", + "input-value-key": "Κλειδί εισόδου τιμής", + "input-value-key-required": "Το κλειδί εισόδου τιμής είναι υποχρεωτικό.", "output-value-key": "Κλειδί εξόδου τιμής", - "output-value-key-required": "Απαιτείται το κλειδί εξόδου τιμής.", - "number-of-digits-after-floating-point": "Αριθμός ψηφίων μετά την υποδιαστολή", - "number-of-digits-after-floating-point-range": "Ο αριθμός ψηφίων πρέπει να είναι από 0 έως 15.", - "failure-if-delta-negative": "Αναφορά αποτυχίας αν η διαφορά είναι αρνητική", - "failure-if-delta-negative-tooltip": "Ο κόμβος κανόνα αποτυγχάνει την επεξεργασία αν η τιμή διαφοράς είναι αρνητική.", - "use-caching": "Χρήση προσωρινής αποθήκευσης", - "use-caching-tooltip": "Ο κόμβος κανόνα θα αποθηκεύει προσωρινά την τιμή του \"{{inputValueKey}}\" για βελτίωση απόδοσης.", - "add-time-difference-between-readings": "Προσθήκη χρονικής διαφοράς μεταξύ των αναγνώσεων \"{{inputValueKey}}\"", - "add-time-difference-between-readings-tooltip": "Αν ενεργοποιηθεί, η διαφορά χρόνου θα προστεθεί στο εξερχόμενο μήνυμα ως \"{{periodValueKey}}\".", + "output-value-key-required": "Το κλειδί εξόδου τιμής είναι υποχρεωτικό.", + "number-of-digits-after-floating-point": "Αριθμός δεκαδικών ψηφίων", + "number-of-digits-after-floating-point-range": "Ο αριθμός δεκαδικών πρέπει να είναι από 0 έως 15.", + "failure-if-delta-negative": "Αναφορά αποτυχίας αν το delta είναι αρνητικό", + "failure-if-delta-negative-tooltip": "Ο κόμβος κανόνα προκαλεί αποτυχία επεξεργασίας μηνύματος αν η τιμή delta είναι αρνητική.", + "use-caching": "Χρήση προσωρινής αποθήκευσης (caching)", + "use-caching-tooltip": "Ο κόμβος κανόνα θα αποθηκεύει προσωρινά την τιμή του \"{{inputValueKey}}\" από το εισερχόμενο μήνυμα για βελτίωση της απόδοσης. Σημειώστε ότι η προσωρινή αποθήκευση δεν θα ενημερωθεί αν τροποποιήσετε την τιμή του \"{{inputValueKey}}\" αλλού.", + "add-time-difference-between-readings": "Προσθήκη διαφοράς χρόνου μεταξύ των τιμών \"{{inputValueKey}}\"", + "add-time-difference-between-readings-tooltip": "Αν είναι ενεργό, ο κόμβος κανόνα θα προσθέτει την τιμή \"{{periodValueKey}}\" στο εξερχόμενο μήνυμα.", "period-value-key": "Κλειδί τιμής περιόδου", - "period-value-key-required": "Απαιτείται κλειδί τιμής περιόδου.", - "general-pattern-hint": "Χρησιμοποιήστε ${metadataKey} για τιμή από μεταδεδομένα και $[messageKey] για τιμή από το σώμα μηνύματος.", - "alarm-severity-pattern-hint": "Χρησιμοποιήστε ${metadataKey} για τιμή από τα μεταδεδομένα, $[messageKey] για τιμή από το σώμα του μηνύματος. Η σοβαρότητα του συναγερμού πρέπει να είναι συστημική (CRITICAL, MAJOR κ.λπ.)", - "output-node-name-hint": "Το όνομα κόμβου αντιστοιχεί στον τύπο σχέσης για την προώθηση μηνυμάτων σε άλλους κόμβους.", + "period-value-key-required": "Το κλειδί τιμής περιόδου είναι υποχρεωτικό.", + "general-pattern-hint": "Χρησιμοποιήστε ${metadataKey} για τιμή από μεταδεδομένα, $[messageKey] για τιμή από το σώμα του μηνύματος.", + "alarm-severity-pattern-hint": "Χρησιμοποιήστε ${metadataKey} για τιμή από μεταδεδομένα, $[messageKey] για τιμή από το σώμα του μηνύματος. Η σοβαρότητα του συναγερμού πρέπει να είναι συστημική (CRITICAL, MAJOR κ.λπ.)", + "output-node-name-hint": "Το όνομα του κόμβου κανόνα αντιστοιχεί στον τύπο σχέσης του εξερχόμενου μηνύματος και χρησιμοποιείται για προώθηση μηνυμάτων σε άλλους κόμβους κανόνων στην ίδια αλυσίδα.", "use-server-ts": "Χρήση χρονικής σήμανσης διακομιστή", - "use-server-ts-hint": "Χρησιμοποιεί χρονική σήμανση διακομιστή όταν δεν ορίζεται στα δεδομένα.", - "kv-map-pattern-hint": "Όλα τα πεδία εισόδου υποστηρίζουν template. Χρησιμοποιήστε $[messageKey] ή ${metadataKey}.", - "kv-map-single-pattern-hint": "Το πεδίο εισόδου υποστηρίζει template.", + "use-server-ts-hint": "Χρησιμοποιεί τη χρονική σήμανση του διακομιστή για δεδομένα χρονοσειρών που δεν έχουν ρητή χρονική σήμανση. Χρήσιμο για τη διατήρηση της σωστής σειράς κατά την επεξεργασία μηνυμάτων από πολλαπλές πηγές ή όταν τα μηνύματα φτάνουν εκτός σειράς.", + "kv-map-pattern-hint": "Όλα τα πεδία εισόδου υποστηρίζουν παραμετροποίηση. Χρησιμοποιήστε $[messageKey] για εξαγωγή από το μήνυμα και ${metadataKey} για εξαγωγή από τα μεταδεδομένα.", + "kv-map-single-pattern-hint": "Το πεδίο εισόδου υποστηρίζει παραμετροποίηση. Χρησιμοποιήστε $[messageKey] για εξαγωγή από το μήνυμα και ${metadataKey} για εξαγωγή από τα μεταδεδομένα.", "shared-scope": "Κοινόχρηστο scope", "server-scope": "Scope διακομιστή", "client-scope": "Scope πελάτη", @@ -5266,21 +5291,21 @@ "clear-selected-keys": "Απαλοιφή κλειδιών", "geofence-configuration": "Ρυθμίσεις γεωφράχτη", "coordinate-field-names": "Ονόματα πεδίων συντεταγμένων", - "coordinate-field-hint": "Αναζήτηση πεδίων από μήνυμα ή μεταδεδομένα", + "coordinate-field-hint": "Ο κόμβος κανόνα προσπαθεί να ανακτήσει τα καθορισμένα πεδία από το μήνυμα. Αν δεν υπάρχουν, θα τα αναζητήσει στα μεταδεδομένα.", "presence-monitoring-strategy": "Στρατηγική παρακολούθησης παρουσίας", "presence-monitoring-strategy-on-first-message": "Στο πρώτο μήνυμα", "presence-monitoring-strategy-on-each-message": "Σε κάθε μήνυμα", - "presence-monitoring-strategy-on-first-message-hint": "Αναφέρει 'Inside/Outside' μετά το πρώτο μήνυμα και την ελάχιστη διάρκεια.", - "presence-monitoring-strategy-on-each-message-hint": "Αναφέρει 'Inside/Outside' σε κάθε μήνυμα μετά από αλλαγή παρουσίας.", + "presence-monitoring-strategy-on-first-message-hint": "Αναφέρει την κατάσταση παρουσίας 'Εντός' ή 'Εκτός' στο πρώτο μήνυμα, αφού περάσει η καθορισμένη ελάχιστη διάρκεια από την τελευταία ενημέρωση 'Εισήλθε' ή 'Εξήλθε'.", + "presence-monitoring-strategy-on-each-message-hint": "Αναφέρει την κατάσταση παρουσίας 'Εντός' ή 'Εκτός' σε κάθε μήνυμα μετά την ενημέρωση 'Εισήλθε' ή 'Εξήλθε'.", "fetch-credentials-to": "Ανάκτηση διαπιστευτηρίων σε", - "add-originator-attributes-to": "Προσθήκη ιδιοτήτων αποστολέα σε", - "originator-attributes": "Ιδιότητες αποστολέα", - "fetch-latest-telemetry-with-timestamp": "Ανάκτηση τελευταίας τηλεμετρίας με timestamp", - "fetch-latest-telemetry-with-timestamp-tooltip": "Οι τιμές προστίθενται στα μεταδεδομένα με χρονική σήμανση.", - "tell-failure": "Αναφορά αποτυχίας αν λείπουν ιδιότητες", - "tell-failure-tooltip": "Αν λείπει κάποιο κλειδί, το μήνυμα εξόδου αποτυγχάνει.", - "created-time": "Ώρα δημιουργίας", - "chip-help": "Πατήστε 'Enter' για να ολοκληρώσετε την εισαγωγή {{inputName}}. \nΠατήστε 'Backspace' για να διαγράψετε το {{inputName}}. \nΥποστηρίζονται πολλαπλές τιμές.", + "add-originator-attributes-to": "Προσθήκη χαρακτηριστικών αποστολέα σε", + "originator-attributes": "Χαρακτηριστικά αποστολέα", + "fetch-latest-telemetry-with-timestamp": "Ανάκτηση τελευταίας τηλεμετρίας με χρονική σήμανση", + "fetch-latest-telemetry-with-timestamp-tooltip": "Αν επιλεγεί, οι τελευταίες τιμές τηλεμετρίας θα προστεθούν στα εξερχόμενα μεταδεδομένα με χρονική σήμανση, π.χ.: \"{{latestTsKeyName}}\": \"{\"ts\":1574329385897, \"value\":42}\"", + "tell-failure": "Αναφορά αποτυχίας αν λείπει κάποιο χαρακτηριστικό", + "tell-failure-tooltip": "Αν τουλάχιστον ένα από τα επιλεγμένα κλειδιά δεν υπάρχει, το εξερχόμενο μήνυμα θα αναφέρει \"Αποτυχία\".", + "created-time": "Χρόνος δημιουργίας", + "chip-help": "Πατήστε 'Enter' για να ολοκληρώσετε την εισαγωγή του {{inputName}}. \nΠατήστε 'Backspace' για διαγραφή του {{inputName}}. \nΥποστηρίζονται πολλαπλές τιμές.", "detail": "λεπτομέρεια", "field-name": "όνομα πεδίου", "device-profile": "προφίλ συσκευής", @@ -5295,15 +5320,15 @@ "add-mapped-originator-fields-to": "Προσθήκη χαρτογραφημένων πεδίων αποστολέα σε", "fields": "Πεδία", "skip-empty-fields": "Παράλειψη κενών πεδίων", - "skip-empty-fields-tooltip": "Τα πεδία με κενές τιμές δεν θα προστεθούν στο μήνυμα εξόδου ή τα μεταδεδομένα εξόδου.", + "skip-empty-fields-tooltip": "Πεδία με κενές τιμές δεν θα προστεθούν στο εξερχόμενο μήνυμα ή στα μεταδεδομένα εξόδου.", "fetch-interval": "Διάστημα ανάκτησης", "fetch-strategy": "Στρατηγική ανάκτησης", "fetch-timeseries-from-to": "Ανάκτηση χρονοσειρών από {{startInterval}} {{startIntervalTimeUnit}} πριν έως {{endInterval}} {{endIntervalTimeUnit}} πριν.", - "fetch-timeseries-from-to-invalid": "Μη έγκυρη ανάκτηση χρονοσειρών (\"Η αρχή του διαστήματος\" πρέπει να είναι μικρότερη από \"το τέλος του διαστήματος\").", - "use-metadata-dynamic-interval-tooltip": "Εάν επιλεγεί, ο κόμβος κανόνα θα χρησιμοποιήσει δυναμικά πρότυπα για την έναρξη και λήξη του διαστήματος βάσει μηνύματος και μεταδεδομένων.", - "all-mode-hint": "Αν επιλεγεί 'Όλα', θα ανακτηθεί τηλεμετρία εντός του καθορισμένου διαστήματος με παραμέτρους ερωτήματος.", - "first-mode-hint": "Αν επιλεγεί 'Πρώτο', θα ανακτηθεί η πιο κοντινή τηλεμετρία στην αρχή του διαστήματος.", - "last-mode-hint": "Αν επιλεγεί 'Τελευταίο', θα ανακτηθεί η πιο κοντινή τηλεμετρία στο τέλος του διαστήματος.", + "fetch-timeseries-from-to-invalid": "Μη έγκυρη ανάκτηση χρονοσειρών (\"Έναρξη διαστήματος\" πρέπει να είναι μικρότερη από \"Λήξη διαστήματος\").", + "use-metadata-dynamic-interval-tooltip": "Αν είναι ενεργό, ο κόμβος κανόνα θα χρησιμοποιεί δυναμική έναρξη και λήξη διαστήματος βάσει των προτύπων στο μήνυμα και στα μεταδεδομένα.", + "all-mode-hint": "Αν επιλεγεί η λειτουργία ανάκτησης \"Όλα\", ο κόμβος κανόνα θα ανακτήσει τηλεμετρία από το καθορισμένο διάστημα με παραμετροποιήσιμες παραμέτρους ερωτήματος.", + "first-mode-hint": "Αν επιλεγεί η λειτουργία ανάκτησης \"Πρώτο\", ο κόμβος κανόνα θα ανακτήσει την πλησιέστερη τηλεμετρία προς την έναρξη του διαστήματος.", + "last-mode-hint": "Αν επιλεγεί η λειτουργία ανάκτησης \"Τελευταίο\", ο κόμβος κανόνα θα ανακτήσει την πλησιέστερη τηλεμετρία προς τη λήξη του διαστήματος.", "ascending": "Αύξουσα", "descending": "Φθίνουσα", "min": "Ελάχιστο", @@ -5328,23 +5353,23 @@ "use-system-slack-settings": "Χρήση ρυθμίσεων συστήματος για Slack", "slack-api-token": "Slack API token", "slack-api-token-required": "Απαιτείται Slack API token", - "keys-mapping": "Χαρτογράφηση κλειδιών", + "keys-mapping": "Αντιστοίχιση κλειδιών", "add-key": "Προσθήκη κλειδιού", "recipients": "Παραλήπτες", "message-subject-and-content": "Θέμα και περιεχόμενο μηνύματος", - "template-rules-hint": "Και τα δύο πεδία υποστηρίζουν template. Χρησιμοποιήστε $[messageKey] ή ${metadataKey}.", - "originator-customer-desc": "Χρήση πελάτη αποστολέα ως νέος αποστολέας.", - "originator-tenant-desc": "Χρήση τρέχοντος ενοικιαστή ως νέος αποστολέας.", - "originator-related-entity-desc": "Χρήση σχετικής οντότητας ως νέος αποστολέας βάσει σχέσης.", - "originator-alarm-originator-desc": "Χρήση αποστολέα συναγερμού ως νέος αποστολέας (μόνο αν είναι αποστολέας συναγερμού).", - "originator-entity-by-name-pattern-desc": "Χρήση οντότητας από βάση δεδομένων ως αποστολέας βάσει ονόματος.", - "email-from-template-hint": "Χρησιμοποιήστε $[messageKey] ή ${metadataKey} για τιμές.", - "recipients-block-main-hint": "Διευθύνσεις διαχωρισμένες με κόμμα. Υποστηρίζονται templates.", - "forward-msg-default-rule-chain": "Προώθηση μηνύματος στην προεπιλεγμένη αλυσίδα κανόνων αποστολέα", - "forward-msg-default-rule-chain-tooltip": "Αν δεν υπάρχει προεπιλεγμένη αλυσίδα, χρησιμοποιείται αυτή από τη διαμόρφωση προφίλ.", - "exclude-zero-deltas": "Αποκλεισμός μηδενικών διαφορών από μήνυμα εξόδου", - "exclude-zero-deltas-hint": "Το {{outputValueKey}} προστίθεται μόνο αν η τιμή δεν είναι 0.", - "exclude-zero-deltas-time-difference-hint": "Το {{outputValueKey}} και {{periodValueKey}} προστίθενται μόνο αν η τιμή {{outputValueKey}} δεν είναι 0.", + "template-rules-hint": "Και τα δύο πεδία υποστηρίζουν παραμετροποίηση. Χρησιμοποιήστε $[messageKey] για τιμή από το μήνυμα και ${metadataKey} για τιμή από τα μεταδεδομένα του μηνύματος.", + "originator-customer-desc": "Χρήση πελάτη του αποστολέα του εισερχόμενου μηνύματος ως νέου αποστολέα.", + "originator-tenant-desc": "Χρήση του τρέχοντος ενοικιαστή ως νέου αποστολέα.", + "originator-related-entity-desc": "Χρήση σχετικής οντότητας ως νέου αποστολέα. Η αναζήτηση βασίζεται στον καθορισμένο τύπο σχέσης και κατεύθυνση.", + "originator-alarm-originator-desc": "Χρήση αποστολέα συναγερμού ως νέου αποστολέα. Ισχύει μόνο αν ο αποστολέας του εισερχόμενου μηνύματος είναι οντότητα συναγερμού.", + "originator-entity-by-name-pattern-desc": "Χρήση οντότητας από τη βάση δεδομένων ως νέου αποστολέα. Η αναζήτηση βασίζεται στον τύπο οντότητας και το καθορισμένο πρότυπο ονόματος.", + "email-from-template-hint": "Χρησιμοποιήστε $[messageKey] για εξαγωγή τιμής από το μήνυμα και ${metadataKey} για εξαγωγή από τα μεταδεδομένα.", + "recipients-block-main-hint": "Λίστα διευθύνσεων χωρισμένων με κόμμα. Όλα τα πεδία υποστηρίζουν παραμετροποίηση. Χρησιμοποιήστε $[messageKey] για εξαγωγή από το μήνυμα και ${metadataKey} από τα μεταδεδομένα.", + "forward-msg-default-rule-chain": "Προώθηση μηνύματος στην προεπιλεγμένη αλυσίδα κανόνων του αποστολέα", + "forward-msg-default-rule-chain-tooltip": "Αν είναι ενεργό, το μήνυμα θα προωθηθεί στην προεπιλεγμένη αλυσίδα κανόνων του αποστολέα ή στην καθορισμένη στην παραμετροποίηση, αν δεν έχει οριστεί προεπιλεγμένη στο προφίλ της οντότητας.", + "exclude-zero-deltas": "Αποκλεισμός μηδενικών διαφορών από το εξερχόμενο μήνυμα", + "exclude-zero-deltas-hint": "Αν είναι ενεργό, το κλειδί εξόδου \"{{outputValueKey}}\" θα προστεθεί μόνο αν η τιμή του δεν είναι μηδέν.", + "exclude-zero-deltas-time-difference-hint": "Αν είναι ενεργό, τα κλειδιά εξόδου \"{{outputValueKey}}\" και \"{{periodValueKey}}\" θα προστεθούν μόνο αν η τιμή του \"{{outputValueKey}}\" δεν είναι μηδέν.", "search-direction-from": "Από αποστολέα προς στόχο", "search-direction-to": "Από στόχο προς αποστολέα", "del-relation-direction-from": "Από αποστολέα", @@ -5424,10 +5449,10 @@ "html": "HTML", "dynamic": "Δυναμικό", "use-body-type-template": "Χρήση προτύπου τύπου σώματος", - "plain-text-description": "Απλό, μη μορφοποιημένο κείμενο χωρίς στυλ.", - "html-text-description": "Υποστηρίζει ετικέτες HTML για μορφοποίηση, συνδέσμους και εικόνες.", - "dynamic-text-description": "Υποστηρίζει δυναμική εναλλαγή μεταξύ Plain Text και HTML βάσει προτύπων.", - "after-template-evaluation-hint": "Μετά την αξιολόγηση, αν η τιμή είναι true τότε είναι HTML, αλλιώς Plain text." + "plain-text-description": "Απλό, μη μορφοποιημένο κείμενο χωρίς ειδικό στυλ ή μορφοποίηση.", + "html-text-description": "Επιτρέπει τη χρήση HTML tags για μορφοποίηση, συνδέσμους και εικόνες στο σώμα του μηνύματος.", + "dynamic-text-description": "Επιτρέπει δυναμική χρήση τύπου σώματος είτε σε Απλό Κείμενο είτε σε HTML, βάσει της λειτουργίας παραμετροποίησης.", + "after-template-evaluation-hint": "Μετά την αξιολόγηση του προτύπου, η τιμή θα πρέπει να είναι true για HTML και false για Απλό Κείμενο." }, "ai": { "ai-model": "Μοντέλο AI", @@ -5436,11 +5461,11 @@ "prompt-settings": "Ρυθμίσεις prompt", "prompt-settings-hint": "Το προαιρετικό system prompt ορίζει τον γενικό ρόλο και τους περιορισμούς του AI, ενώ το user prompt καθορίζει το συγκεκριμένο έργο προς εκτέλεση. Και τα δύο πεδία υποστηρίζουν χρήση προτύπων.", "system-prompt": "System prompt", - "system-prompt-max-length": "Το system prompt πρέπει να είναι έως 500000 χαρακτήρες.", + "system-prompt-max-length": "Το system prompt πρέπει να είναι έως 10000 χαρακτήρες.", "system-prompt-blank": "Το system prompt δεν πρέπει να είναι κενό.", "user-prompt": "User prompt", "user-prompt-required": "Απαιτείται user prompt.", - "user-prompt-max-length": "Το user prompt πρέπει να είναι έως 500000 χαρακτήρες.", + "user-prompt-max-length": "Το user prompt πρέπει να είναι έως 10000 χαρακτήρες.", "user-prompt-blank": "Το user prompt δεν πρέπει να είναι κενό.", "response-format": "Μορφή απόκρισης", "response-text": "Κείμενο", @@ -5453,11 +5478,12 @@ "response-json-schema-required": "Απαιτείται JSON Schema", "advanced-settings": "Προχωρημένες ρυθμίσεις", "timeout": "Χρονικό όριο (Timeout)", - "timeout-hint": "Μέγιστος χρόνος αναμονής για απάντηση \nαπό το μοντέλο AI πριν τερματιστεί το αίτημα.", - "timeout-required": "Απαιτείται χρονικό όριο", + "timeout-hint": "Μέγιστος χρόνος αναμονής για απάντηση\nαπό το AI μοντέλο πριν διακοπεί το αίτημα.", + "timeout-required": "Το χρονικό όριο είναι υποχρεωτικό", "timeout-validation": "Πρέπει να είναι από 1 δευτερόλεπτο έως 10 λεπτά.", - "force-acknowledgement": "Εξαναγκασμένη επιβεβαίωση", - "force-acknowledgement-hint": "Αν είναι ενεργοποιημένο, το εισερχόμενο μήνυμα επιβεβαιώνεται άμεσα. Η απάντηση του μοντέλου τοποθετείται στη συνέχεια στην ουρά ως ξεχωριστό νέο μήνυμα." + "force-acknowledgement": "Εξαναγκασμένη επιβεβαίωση (ACK)", + "force-acknowledgement-hint": "Αν είναι ενεργό, το εισερχόμενο μήνυμα επιβεβαιώνεται αμέσως. Η απάντηση του μοντέλου αποστέλλεται ως ξεχωριστό, νέο μήνυμα.", + "ai-resources": "AI πόροι" } }, "timezone": { @@ -5757,11 +5783,11 @@ "rule-engine-exceptions-ttl-days": "Ημέρες TTL εξαιρέσεων Rule Engine", "rule-engine-exceptions-ttl-days-required": "Απαιτούνται ημέρες TTL εξαιρέσεων Rule Engine", "rule-engine-exceptions-ttl-days-range": "Οι ημέρες TTL εξαιρέσεων Rule Engine δεν μπορεί να είναι αρνητικές", - "max-rule-node-executions-per-message": "Μέγιστος αριθμός εκτελέσεων rule node ανά μήνυμα", - "max-rule-node-executions-per-message-required": "Απαιτείται μέγιστος αριθμός εκτελέσεων rule node ανά μήνυμα", - "max-rule-node-executions-per-message-range": "Ο μέγιστος αριθμός εκτελέσεων rule node ανά μήνυμα δεν μπορεί να είναι αρνητικός", + "max-rule-node-executions-per-message": "Μέγιστος αριθμός εκτελέσεων κόμβου κανόνα ανά μήνυμα", + "max-rule-node-executions-per-message-required": "Ο μέγιστος αριθμός εκτελέσεων κόμβου κανόνα ανά μήνυμα είναι υποχρεωτικός.", + "max-rule-node-executions-per-message-range": "Ο μέγιστος αριθμός εκτελέσεων κόμβου κανόνα ανά μήνυμα δεν μπορεί να είναι αρνητικός", "max-emails": "Μέγιστος αριθμός αποσταλμένων emails", - "max-emails-required": "Απαιτείται μέγιστος αριθμός αποσταλμένων emails", + "max-emails-required": "Ο μέγιστος αριθμός αποσταλμένων emails είναι υποχρεωτικός.", "max-emails-range": "Ο μέγιστος αριθμός αποσταλμένων emails δεν μπορεί να είναι αρνητικός", "sms-enabled": "SMS ενεργοποιημένο", "max-sms": "Μέγιστος αριθμός αποσταλμένων SMS", @@ -5981,17 +6007,18 @@ "all": "Όλα" }, "tooltip": { - "trigger": "Ενεργοποίηση", + "trigger": "Ενεργοποιητής", "trigger-point": "Σημείο", "trigger-axis": "Άξονας", "label": "Ετικέτα", "value": "Τιμή", "date": "Ημερομηνία", - "show-date-time-interval": "Εμφάνιση χρονικού διαστήματος", - "show-date-time-interval-hint": "Εμφάνιση χρονικού διαστήματος σύμφωνα με τη συγχώνευση δεδομένων.", + "show-date-time-interval": "Εμφάνιση χρονικού διαστήματος ημερομηνίας", + "show-date-time-interval-hint": "Εμφανίζει το χρονικό διάστημα ημερομηνίας σύμφωνα με την ομαδοποίηση δεδομένων.", "hide-zero-tooltip-values": "Απόκρυψη μηδενικών τιμών", + "show-stack-total": "Εμφάνιση συνολικής τιμής σε λειτουργία στοίβας", "background-color": "Χρώμα φόντου", - "background-blur": "Θόλωση φόντου" + "background-blur": "Θάμπωμα φόντου" }, "unit": { "set-unit-conversion": "Ορισμός μετατροπής μονάδων", @@ -6702,15 +6729,15 @@ "no-widgets-text": "Δεν βρέθηκαν widgets", "management": "Διαχείριση widgets", "editor": "Επεξεργαστής widget", - "confirm-to-exit-editor-html": "Έχετε μη αποθηκευμένες ρυθμίσεις widget.
Είστε σίγουροι ότι θέλετε να φύγετε από αυτή τη σελίδα;", - "widget-type-not-found": "Πρόβλημα κατά τη φόρτωση της διαμόρφωσης του widget.
Πιθανόν ο τύπος widget να έχει αφαιρεθεί.", - "widget-type-load-error": "Το widget δεν φορτώθηκε λόγω των εξής σφαλμάτων:", + "confirm-to-exit-editor-html": "Έχετε αποθηκεύσει ρυθμίσεις widget.
Είστε σίγουροι ότι θέλετε να φύγετε από αυτή τη σελίδα;", + "widget-type-not-found": "Πρόβλημα κατά τη φόρτωση της ρύθμισης του widget.
Πιθανόν ο τύπος\n widget που σχετίζεται να αφαιρέθηκε.", + "widget-type-load-error": "Το widget δεν φόρτωσε λόγω των παρακάτω λαθών:", "remove": "Αφαίρεση widget", "delete": "Διαγραφή widget", "edit": "Επεξεργασία widget", "remove-widget-title": "Είστε σίγουροι ότι θέλετε να αφαιρέσετε το widget '{{widgetTitle}}';", - "remove-widget-text": "Μετά την επιβεβαίωση, το widget και όλα τα σχετικά δεδομένα δεν θα μπορούν να ανακτηθούν.", - "replace-reference-with-widget-copy": "Αντικατάσταση αναφοράς με αντίγραφο widget", + "remove-widget-text": "Μετά την επιβεβαίωση, το widget και όλα τα σχετικά δεδομένα θα γίνουν μη ανακτήσιμα.", + "replace-reference-with-widget-copy": "Αντικατάσταση αναφοράς με αντίγραφο του widget", "timeseries": "Χρονοσειρά", "search-data": "Αναζήτηση δεδομένων", "no-data-found": "Δεν βρέθηκαν δεδομένα", @@ -7062,19 +7089,19 @@ }, "widgets": { "mobile-app-qr-code": { - "configuration-hint": "Η διαμόρφωση εξαρτάται από το widget QR code της εφαρμογής κινητού στις βασικές ρυθμίσεις της πλατφόρμας", - "get-it-on-google-play": "Λήψη από το Google Play", - "download-on-the-app-store": "Λήψη από το App Store" + "configuration-hint": "Η ρύθμιση εξαρτάται από το widget QR κώδικα της εφαρμογής κινητού στις κύριες ρυθμίσεις της πλατφόρμας", + "get-it-on-google-play": "Αποκτήστε το στο Google Play", + "download-on-the-app-store": "Κατεβάστε το στο App Store" }, "action-button": { "behavior": "Συμπεριφορά", "on-click": "Κατά το κλικ", - "on-click-hint": "Ενέργεια που εκτελείται όταν γίνεται κλικ στο κουμπί", - "first-button-click": "Κλικ στο πρώτο κουμπί", - "first-button-click-hint": "Ενέργεια κατά την πίεση του πρώτου κουμπιού.", - "second-button-click": "Κλικ στο δεύτερο κουμπί", - "second-button-click-hint": "Ενέργεια κατά την πίεση του δεύτερου κουμπιού.", - "button-click-hint": "Ενέργεια κατά την πίεση στο widget." + "on-click-hint": "Ενέργεια που ενεργοποιείται όταν πατηθεί το κουμπί", + "first-button-click": "Πρώτο κλικ στο κουμπί", + "first-button-click-hint": "Ενέργεια κατά τη διάρκεια της πίεσης στο πρώτο κουμπί.", + "second-button-click": "Δεύτερο κλικ στο κουμπί", + "second-button-click-hint": "Ενέργεια κατά τη διάρκεια της πίεσης στο δεύτερο κουμπί.", + "button-click-hint": "Ενέργεια κατά τη διάρκεια της πίεσης στο widget." }, "command-button": { "behavior": "Συμπεριφορά", @@ -8138,7 +8165,7 @@ "button-primary": "Πρωτεύον χρώμα", "button-background-color": "Χρώμα φόντου κουμπιού", "button-text-color": "Χρώμα κειμένου κουμπιού", - "widget-title": "Τίτλος γραφικού στοιχείου", + "widget-title": "Τίτλος widget", "button-label": "Ετικέτα κουμπιού", "device-attribute-scope": "Πεδίο χαρακτηριστικού συσκευής", "server-attribute": "Χαρακτηριστικό διακομιστή", @@ -8298,17 +8325,17 @@ "no-datasources": "Δεν έχουν διαμορφωθεί πηγές δεδομένων", "remove-datasource": "Αφαίρεση πηγής δεδομένων", "behavior": "Συμπεριφορά", - "on-click": "Με κλικ", - "on-click-hint": "Ενέργεια που εκτελείται όταν ο χρήστης κάνει κλικ στο στοιχείο του χάρτη.", + "on-click": "Κατά το κλικ", + "on-click-hint": "Ενέργεια που ενεργοποιείται όταν ο χρήστης κάνει κλικ στο στοιχείο του χάρτη.", "groups": "Ομάδες", - "groups-hint": "Λίστα ονομάτων ομάδων που έχουν εκχωρηθεί στην επικάλυψη, χρησιμοποιείται για την εναλλαγή της ορατότητάς της στον χάρτη.", + "groups-hint": "Λίστα με τα ονόματα ομάδων που ανατίθενται στο επικαλυπτόμενο στοιχείο, χρησιμοποιούνται για την εναλλαγή της ορατότητάς του στον χάρτη.", "color": "Χρώμα", "color-settings": "Ρυθμίσεις χρώματος", "color-type-constant": "Σταθερό", "color-type-range": "Εύρος", "color-type-function": "Συνάρτηση", "color-range-source-key": "Κλειδί πηγής εύρους χρώματος", - "color-range-source-key-required": "Απαιτείται κλειδί πηγής εύρους χρώματος", + "color-range-source-key-required": "Το κλειδί πηγής εύρους χρώματος είναι υποχρεωτικό", "color-range": "Εύρος χρώματος", "color-function": "Συνάρτηση χρώματος", "label": "Ετικέτα", @@ -8795,7 +8822,7 @@ "tank": "Δοχείο", "shape": "Σχήμα", "datasource-units": "Μονάδες πηγής", - "widget-units": "Μονάδες γραφικού στοιχείου", + "widget-units": "Μονάδες widget", "decimals": "Δεκαδικά", "liquid": "Υγρό", "liquid-color": "Χρώμα υγρού", @@ -8880,9 +8907,9 @@ "progress-bar-card-style": "Στυλ κάρτας γραμμής προόδου" }, "notification": { - "max-notification-display": "Μέγιστος αριθμός ειδοποιήσεων για εμφάνιση", + "max-notification-display": "Μέγιστος αριθμός ειδοποιήσεων προς εμφάνιση", "counter": "Μετρητής", - "counter-hint": "Ο μετρητής θα εμφανίζεται εάν είναι ενεργοποιημένος ο \"Τίτλος γραφικού στοιχείου\"", + "counter-hint": "Ο μετρητής θα εμφανιστεί αν είναι ενεργοποιημένος ο «Τίτλος widget»", "icon": "Εικονίδιο", "counter-value": "Τιμή", "counter-color": "Χρώμα", @@ -8890,10 +8917,10 @@ "button-view-all": "Προβολή όλων", "button-filter": "Φίλτρο", "type-filter": "Φίλτρο τύπου", - "button-mark-read": "Σήμανση όλων ως αναγνωσμένων", + "button-mark-read": "Επισήμανση όλων ως αναγνωσμένων", "notification-types": "Τύποι ειδοποιήσεων", "notification-type": "Τύπος ειδοποίησης", - "search-type": "Τύπος αναζήτησης", + "search-type": "Αναζήτηση τύπου", "any-type": "Οποιοσδήποτε τύπος" }, "alarm-count": { @@ -9290,15 +9317,15 @@ "no-data-available": "Δεν υπάρχουν διαθέσιμα δεδομένα" }, "system-info": { - "cpu": "Επεξεργαστής", + "cpu": "CPU", "ram": "RAM", "disk": "Δίσκος", - "cpu-warning-text": "Υψηλή χρήση επεξεργαστή. Βελτιστοποιήστε την απόδοση του συστήματος για να αποφύγετε αποτυχία.", - "cpu-critical-text": "Κρίσιμα υψηλή χρήση επεξεργαστή. Βελτιστοποιήστε την απόδοση του συστήματος για να αποφύγετε αποτυχία.", - "ram-warning-text": "Χαμηλή διαθεσιμότητα RAM. Βελτιστοποιήστε ή αυξήστε τη RAM για να αποφύγετε αποτυχία.", - "ram-critical-text": "Κρίσιμα χαμηλή RAM. Βελτιστοποιήστε ή αυξήστε τη RAM για να αποφύγετε αποτυχία.", - "disk-warning-text": "Χαμηλός διαθέσιμος χώρος δίσκου. Απελευθερώστε ή αυξήστε τον αποθηκευτικό χώρο.", - "disk-critical-text": "Κρίσιμα χαμηλός χώρος δίσκου. Απελευθερώστε ή αυξήστε τον αποθηκευτικό χώρο." + "cpu-warning-text": "Η χρήση του CPU είναι υψηλή. Για να αποφύγετε αποτυχία του συστήματος, βελτιστοποιήστε την απόδοση του συστήματος.", + "cpu-critical-text": "Κρίσιμα υψηλή χρήση CPU. Για να αποφύγετε αποτυχία του συστήματος, βελτιστοποιήστε την απόδοση του συστήματος.", + "ram-warning-text": "Η μνήμη RAM είναι χαμηλή. Για να αποφύγετε αποτυχία του συστήματος, βελτιστοποιήστε την απόδοση του συστήματος ή αυξήστε το μέγεθος της μνήμης RAM.", + "ram-critical-text": "Κρίσιμα χαμηλή μνήμη RAM. Για να αποφύγετε αποτυχία του συστήματος, βελτιστοποιήστε την απόδοση του συστήματος ή αυξήστε το μέγεθος της μνήμης RAM.", + "disk-warning-text": "Ο χώρος στον δίσκο είναι χαμηλός. Για να αποφύγετε την απώλεια δεδομένων, ελευθερώστε ή επεκτείνετε τον χώρο στον δίσκο.", + "disk-critical-text": "Κρίσιμα χαμηλός χώρος στον δίσκο. Για να αποφύγετε την απώλεια δεδομένων, ελευθερώστε ή επεκτείνετε τον χώρο στον δίσκο." }, "cluster-info": { "service-id": "Αναγνωριστικό υπηρεσίας", @@ -9522,4 +9549,4 @@ "language": { "language": "Γλώσσα" } -} +} \ No newline at end of file diff --git a/ui-ngx/src/assets/locale/locale.constant-en_US.json b/ui-ngx/src/assets/locale/locale.constant-en_US.json index 794688ea29..54ea5737f7 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -2831,7 +2831,7 @@ "target-entity": "Target entity", "attributes-propagation": "Attributes propagation", "attributes-propagation-hint": "Entity View will automatically copy specified attributes from Target Entity each time you save or update this entity view. For performance reasons target entity attributes are not propagated to entity view on each attribute change. You can enable automatic propagation by configuring \"copy to view\" rule node in your rule chain and linking \"Post attributes\" and \"Attributes Updated\" messages to the new rule node.", - "timeseries-data": "Times eries data", + "timeseries-data": "Time series data", "timeseries-data-hint": "Configure time series data keys of the target entity that will be accessible to the entity view. This time series data is read-only.", "search": "Search entity views", "selected-entity-views": "{ count, plural, =1 {1 entity view} other {# entity views} } selected", @@ -5948,13 +5948,13 @@ "timewindow": { "timewindow": "Time window", "timewindow-settings": "Time window settings", - "years": "{ years, plural, =1 { year } other {# years } }", + "years": "{ years, plural, =1 {1 year } other {# years } }", "years-short": "{{ years }}y", - "months": "{ months, plural, =1 { month } other {# months } }", + "months": "{ months, plural, =1 {1 month } other {# months } }", "months-short": "{{ months }}M", - "weeks": "{ weeks, plural, =1 { week } other {# weeks } }", + "weeks": "{ weeks, plural, =1 {1 week } other {# weeks } }", "weeks-short": "{{ weeks }}w", - "days": "{ days, plural, =1 { day } other {# days } }", + "days": "{ days, plural, =1 {1 day } other {# days } }", "days-short": "{{ days }}d", "hours": "{ hours, plural, =0 { hour } =1 {1 hour } other {# hours } }", "hr": "{{ hr }} hr", diff --git a/ui-ngx/src/assets/locale/locale.constant-fr_FR.json b/ui-ngx/src/assets/locale/locale.constant-fr_FR.json index e278f5f8a9..91cd95bd41 100644 --- a/ui-ngx/src/assets/locale/locale.constant-fr_FR.json +++ b/ui-ngx/src/assets/locale/locale.constant-fr_FR.json @@ -684,7 +684,7 @@ "filter-type-entity-name": "Nom de l'entité", "filter-type-entity-type": "Type d'entité", "filter-type-state-entity": "Entité de l'état du tableau de bord", - "filter-type-state-entity-description": "Entité extraite des paramètres de l'état du tableau de bord", + "filter-type-state-entity-description": "Entité prise à partir des paramètres de l'état du tableau de bord", "filter-type-asset-type": "Type d'actif", "filter-type-asset-type-description": "Actifs de type '{{assetTypes}}'", "filter-type-asset-type-and-name-description": "Actifs de type '{{assetTypes}}' dont le nom commence par '{{prefix}}'", @@ -715,18 +715,18 @@ "filter-type-required": "Le type de filtre est requis.", "entity-filter-no-entity-matched": "Aucune entité ne correspond au filtre spécifié.", "no-entity-filter-specified": "Aucun filtre d'entité spécifié", - "root-state-entity": "Utiliser l'entité de l'état du tableau de bord comme racine", - "last-level-relation": "Ne récupérer que le dernier niveau de relation", + "root-state-entity": "Utiliser l'entité d'état du tableau de bord comme racine", + "last-level-relation": "Extraire uniquement la relation de dernier niveau", "root-entity": "Entité racine", "state-entity-parameter-name": "Nom du paramètre d'entité d'état", "default-state-entity": "Entité d'état par défaut", "default-entity-parameter-name": "Par défaut", "query-options": "Options de requête", - "max-relation-level": "Niveau de relation maximal", + "max-relation-level": "Niveau maximal de relation", "unlimited-level": "Niveau illimité", "state-entity": "Entité d'état du tableau de bord", "all-entities": "Toutes les entités", - "any-relation": "n'importe quelle" + "any-relation": "n'importe laquelle" }, "asset": { "asset": "Actif", @@ -861,23 +861,23 @@ } }, "api-usage": { - "api-features": "Fonctionnalités de l'API", + "api-features": "Fonctionnalités API", "api-usage": "Utilisation de l'API", "alarm": "Alarme", "alarms-created": "Alarmes créées", - "queue-stats": "Statistiques de file", - "processing-failures-and-timeouts": "Échecs de traitement et expirations", + "queue-stats": "Statistiques de file d'attente", + "processing-failures-and-timeouts": "Échecs et expirations de traitement", "exceptions": "Exceptions", "alarms-created-daily-activity": "Activité quotidienne des alarmes créées", "alarms-created-hourly-activity": "Activité horaire des alarmes créées", "alarms-created-monthly-activity": "Activité mensuelle des alarmes créées", "data-points": "Points de données", - "data-points-storage-days": "Durée de stockage des points de données (jours)", + "data-points-storage-days": "Durée de conservation des points de données (jours)", "device-api": "API des appareils", - "email": "Email", - "email-messages": "Messages email", - "email-messages-daily-activity": "Activité quotidienne des emails", - "email-messages-monthly-activity": "Activité mensuelle des emails", + "email": "E-mail", + "email-messages": "Messages e-mail", + "email-messages-daily-activity": "Activité quotidienne des e-mails", + "email-messages-monthly-activity": "Activité mensuelle des e-mails", "executions": "Exécutions", "scripts": "Scripts", "scripts-hourly-activity": "Activité horaire des scripts", @@ -890,12 +890,12 @@ "latest-error": "Dernière erreur", "messages": "Messages", "notifications": "Notifications", - "notifications-email-sms": "Notifications (Email/SMS)", + "notifications-email-sms": "Notifications (E-mail/SMS)", "notifications-hourly-activity": "Activité horaire des notifications", - "permanent-failures": "Échecs permanents de ${entityName}", - "permanent-timeouts": "Expirations permanentes de ${entityName}", - "processing-failures": "Échecs de traitement de ${entityName}", - "processing-timeouts": "Expirations de traitement de ${entityName}", + "permanent-failures": "Échecs permanents ${entityName}", + "permanent-timeouts": "Expirations permanentes ${entityName}", + "processing-failures": "Échecs de traitement ${entityName}", + "processing-timeouts": "Expirations de traitement ${entityName}", "rule-chain": "Chaîne de règles", "rule-engine": "Moteur de règles", "rule-engine-daily-activity": "Activité quotidienne du moteur de règles", @@ -924,14 +924,14 @@ "view-statistics": "Voir les statistiques" }, "api-limit": { - "cassandra-write-queries-core": "Requêtes d'écriture Cassandra via l'API REST", - "cassandra-read-queries-core": "Requêtes de lecture Cassandra via l'API REST et WS (télémétrie)", - "cassandra-write-queries-rule-engine": "Requêtes d'écriture Cassandra du moteur de règles (télémétrie)", - "cassandra-read-queries-rule-engine": "Requêtes de lecture Cassandra du moteur de règles (télémétrie)", - "cassandra-write-queries-monolith": "Requêtes d'écriture Cassandra monolithiques (télémétrie)", - "cassandra-read-queries-monolith": "Requêtes de lecture Cassandra monolithiques (télémétrie)", - "entity-version-creation": "Création de version d'entité", - "entity-version-load": "Chargement de version d'entité", + "cassandra-write-queries-core": "Requêtes d’écriture Cassandra via l’API REST", + "cassandra-read-queries-core": "Requêtes de lecture Cassandra pour la télémétrie via REST API et WebSocket", + "cassandra-write-queries-rule-engine": "Requêtes d’écriture Cassandra pour la télémétrie du moteur de règles", + "cassandra-read-queries-rule-engine": "Requêtes de lecture Cassandra pour la télémétrie du moteur de règles", + "cassandra-write-queries-monolith": "Requêtes d’écriture Cassandra pour la télémétrie du monolithe", + "cassandra-read-queries-monolith": "Requêtes de lecture Cassandra pour la télémétrie du monolithe", + "entity-version-creation": "Création de version d’entité", + "entity-version-load": "Chargement de version d’entité", "notification-requests": "Requêtes de notification", "notification-requests-per-rule": "Requêtes de notification par règle", "rest-api-requests": "Requêtes API REST", @@ -942,9 +942,9 @@ "transport-messages-per-gateway-device": "Messages de transport par appareil de passerelle", "ws-updates-per-session": "Mises à jour WS par session", "edge-events": "Événements Edge", - "edge-events-per-edge": "Événements Edge par instance Edge", + "edge-events-per-edge": "Événements Edge par instance", "edge-uplink-messages": "Messages montants Edge", - "edge-uplink-messages-per-edge": "Messages montants Edge par instance Edge" + "edge-uplink-messages-per-edge": "Messages montants Edge par instance" }, "audit-log": { "audit": "Audit", @@ -966,7 +966,7 @@ "type-assigned-to-customer": "Assigné à un client", "type-unassigned-from-customer": "Désassigné d'un client", "type-assigned-to-edge": "Assigné à une Edge", - "type-unassigned-from-edge": "Désassigné d'une Edge", + "type-unassigned-from-edge": "Désassigné d'un Edge", "type-activated": "Activé", "type-suspended": "Suspendu", "type-credentials-read": "Identifiants lus", @@ -1008,9 +1008,9 @@ "failures": "Échecs", "entity": "entité", "hint": { - "main-limited": "Pas plus de {{msg}} messages de débogage pour {{entity}} toutes les {{time}} seront enregistrés.", - "on-failure": "Journaliser uniquement les messages d'erreur.", - "all-messages": "Journaliser tous les messages de débogage." + "main-limited": "Pas plus de {{msg}} messages de débogage de {{entity}} par {{time}} ne seront enregistrés.", + "on-failure": "Enregistrer uniquement les messages d'erreur.", + "all-messages": "Enregistrer tous les messages de débogage." } }, "calculated-fields": { @@ -1030,79 +1030,79 @@ "add-argument": "Ajouter un argument", "test-script-function": "Tester la fonction script", "no-arguments": "Aucun argument configuré", - "argument-settings": "Paramètres des arguments", + "argument-settings": "Paramètres de l'argument", "argument-current": "Entité actuelle", - "argument-current-tenant": "Locataire actuel", + "argument-current-tenant": "Tenant actuel", "argument-device": "Appareil", "argument-asset": "Actif", "argument-customer": "Client", - "argument-tenant": "Locataire actuel", + "argument-tenant": "Tenant actuel", "argument-type": "Type d'argument", "see-debug-events": "Voir les événements de débogage", "attribute": "Attribut", "copy-argument-name": "Copier le nom de l'argument", "timeseries-key": "Clé de série temporelle", - "device-name": "Nom de l'appareil", + "device-name": "Nom de l’appareil", "latest-telemetry": "Dernière télémétrie", - "rolling": "Rolling des séries temporelles", - "attribute-scope": "Portée de l'attribut", + "rolling": "Déroulement des séries temporelles", + "attribute-scope": "Portée de l’attribut", "server-attributes": "Attributs serveur", "client-attributes": "Attributs client", "shared-attributes": "Attributs partagés", "attribute-key": "Clé d'attribut", "default-value": "Valeur par défaut", - "limit": "Valeurs max", + "limit": "Valeurs max.", "time-window": "Fenêtre temporelle", "customer-name": "Nom du client", - "asset-name": "Nom de l'actif", + "asset-name": "Nom de l’actif", "timeseries": "Séries temporelles", - "output": "Résultat", + "output": "Sortie", "create": "Créer un nouveau champ calculé", "file": "Fichier de champ calculé", - "invalid-file-error": "Format de fichier invalide. Veuillez vérifier que le fichier est bien un fichier JSON valide.", + "invalid-file-error": "Format de fichier invalide. Veuillez vous assurer que le fichier est un JSON valide.", "import": "Importer un champ calculé", "export": "Exporter un champ calculé", "export-failed-error": "Impossible d'exporter le champ calculé : {{error}}", - "output-type": "Type de résultat", - "delete-title": "Êtes-vous sûr de vouloir supprimer le champ calculé '{{title}}' ?", - "delete-text": "Attention, après confirmation le champ calculé et toutes les données associées seront irrécupérables.", - "delete-multiple-title": "Êtes-vous sûr de vouloir supprimer { count, plural, =1 {1 champ calculé} other {# champs calculés} } ?", - "delete-multiple-text": "Attention, après confirmation tous les champs calculés sélectionnés seront supprimés et toutes les données associées seront irrécupérables.", + "output-type": "Type de sortie", + "delete-title": "Voulez-vous vraiment supprimer le champ calculé '{{title}}' ?", + "delete-text": "Attention, après confirmation, le champ calculé et toutes les données associées seront irrécupérables.", + "delete-multiple-title": "Voulez-vous vraiment supprimer { count, plural, =1 {1 champ calculé} other {# champs calculés} } ?", + "delete-multiple-text": "Attention, après confirmation, tous les champs calculés sélectionnés seront supprimés et les données associées seront irrécupérables.", "test-with-this-message": "Tester avec ce message", - "use-latest-timestamp": "Utiliser l'horodatage le plus récent", + "use-latest-timestamp": "Utiliser le dernier horodatage", "hint": { - "arguments-simple-with-rolling": "Un champ calculé de type simple ne doit pas contenir de clés avec type de séries temporelles roulantes.", + "arguments-simple-with-rolling": "Un champ calculé de type simple ne doit pas contenir de clés avec déroulement de séries temporelles.", "arguments-empty": "Les arguments ne doivent pas être vides.", - "expression-required": "Une expression est requise.", - "expression-invalid": "L'expression est invalide", + "expression-required": "L'expression est requise.", + "expression-invalid": "L'expression est invalide.", "expression-max-length": "La longueur de l'expression doit être inférieure à 255 caractères.", "argument-name-required": "Le nom de l'argument est requis.", "argument-name-pattern": "Le nom de l'argument est invalide.", - "argument-name-duplicate": "Un argument portant ce nom existe déjà.", - "argument-name-max-length": "Le nom de l'argument doit comporter moins de 256 caractères.", + "argument-name-duplicate": "Un argument avec ce nom existe déjà.", + "argument-name-max-length": "Le nom de l'argument doit contenir moins de 256 caractères.", "argument-name-forbidden": "Ce nom d'argument est réservé et ne peut pas être utilisé.", "argument-type-required": "Le type d'argument est requis.", "max-args": "Nombre maximal d'arguments atteint.", - "decimals-range": "Les décimales par défaut doivent être un nombre entre 0 et 15.", + "decimals-range": "Le nombre de décimales par défaut doit être compris entre 0 et 15.", "expression": "L'expression par défaut montre comment convertir une température de Fahrenheit en Celsius.", - "arguments-entity-not-found": "Entité cible de l'argument introuvable.", - "use-latest-timestamp": "Si activé, la valeur calculée sera enregistrée avec l'horodatage le plus récent des télémétries des arguments, au lieu de l'heure du serveur." + "arguments-entity-not-found": "L'entité cible de l'argument est introuvable.", + "use-latest-timestamp": "Si activé, la valeur calculée sera enregistrée avec l’horodatage le plus récent parmi la télémétrie des arguments, au lieu de celui du serveur." } }, "ai-models": { - "ai-models": "Modèles IA", - "ai-model": "Modèle IA", + "ai-models": "Modèles d'IA", + "ai-model": "Modèle d'IA", "model": "Modèle", "name": "Nom", - "ai-provider": "Fournisseur IA", - "no-found": "Aucun modèle IA trouvé", + "ai-provider": "Fournisseur d'IA", + "no-found": "Aucun modèle d'IA trouvé", "list": "{ count, plural, =1 {Un modèle} other {Liste de # modèles} }", "selected-fields": "{ count, plural, =1 {1 modèle} other {# modèles} } sélectionné(s)", "add": "Ajouter un modèle", - "delete-model-title": "Êtes-vous sûr de vouloir supprimer le modèle '{{modelName}}' ?", + "delete-model-title": "Voulez-vous vraiment supprimer le modèle '{{modelName}}' ?", "delete-model-text": "Attention, après confirmation, le modèle et toutes les données associées seront irrécupérables.", - "delete-models-title": "Êtes-vous sûr de vouloir supprimer { count, plural, =1 {1 modèle} other {# modèles} } ?", - "delete-models-text": "Attention, après confirmation, tous les modèles sélectionnés seront supprimés et toutes les données associées deviendront irrécupérables.", + "delete-models-title": "Voulez-vous vraiment supprimer { count, plural, =1 {1 modèle} other {# modèles} } ?", + "delete-models-text": "Attention, après confirmation, tous les modèles sélectionnés seront supprimés et toutes les données associées seront irrécupérables.", "ai-providers": { "openai": "OpenAI", "azure-openai": "Azure OpenAI", @@ -1111,64 +1111,83 @@ "mistral-ai": "Mistral AI", "anthropic": "Anthropic", "amazon-bedrock": "Amazon Bedrock", - "github-models": "Modèles GitHub" + "github-models": "GitHub Models", + "ollama": "Ollama" }, "name-required": "Le nom est requis.", - "name-max-length": "Le nom doit comporter 255 caractères ou moins.", + "name-max-length": "Le nom doit contenir 255 caractères ou moins.", "provider": "Fournisseur", "api-key": "Clé API", "api-key-required": "La clé API est requise.", - "project-id": "ID de projet", - "project-id-required": "L'ID de projet est requis.", + "api-key-open-ai-required": "La clé API est requise lors de l'utilisation de l'API officielle d'OpenAI.", + "project-id": "ID du projet", + "project-id-required": "L'ID du projet est requis", "location": "Emplacement", - "location-required": "L'emplacement est requis.", + "location-required": "L’emplacement est requis.", "service-account-key-file": "Fichier de clé du compte de service", "service-account-key-file-required": "Le fichier de clé du compte de service est requis.", "no-file": "Aucun fichier sélectionné.", "drop-file": "Déposez un fichier ou cliquez pour en sélectionner un à téléverser.", - "personal-access-token": "Jeton d'accès personnel", - "personal-access-token-required": "Le jeton d'accès personnel est requis.", + "personal-access-token": "Jeton d’accès personnel", + "personal-access-token-required": "Le jeton d’accès personnel est requis.", "configuration": "Configuration", "model-id": "ID du modèle", - "model-id-required": "L'ID du modèle est requis.", + "model-id-required": "L’ID du modèle est requis.", "deployment-name": "Nom du déploiement", - "deployment-name-required": "Le nom du déploiement est requis.", + "deployment-name-required": "Le nom du déploiement est requis", "set": "Définir", "region": "Région", "region-required": "La région est requise.", "access-key-id": "ID de la clé d'accès", - "access-key-id-required": "L'ID de la clé d'accès est requis.", - "secret-access-key": "Clé d'accès secrète", - "secret-access-key-required": "La clé d'accès secrète est requise.", + "access-key-id-required": "L’ID de la clé d’accès est requis.", + "secret-access-key": "Clé d’accès secrète", + "secret-access-key-required": "La clé d’accès secrète est requise.", "temperature": "Température", - "temperature-hint": "Ajuste le niveau d'aléatoire dans la sortie du modèle. Des valeurs plus élevées augmentent l'aléatoire, tandis que des valeurs plus faibles la réduisent.", + "temperature-hint": "Ajuste le niveau d’aléa dans la sortie du modèle. Une valeur élevée augmente l’aléa, tandis qu’une valeur faible le réduit.", "temperature-min": "Doit être supérieur ou égal à 0.", "top-p": "Top P", - "top-p-hint": "Crée un ensemble des jetons les plus probables pour que le modèle puisse choisir. Des valeurs plus élevées créent un ensemble plus large et diversifié, tandis que des valeurs plus faibles le réduisent.", + "top-p-hint": "Crée un ensemble de tokens les plus probables pour la sélection du modèle. Une valeur élevée élargit le choix, une valeur faible le restreint.", "top-p-min-max": "Doit être supérieur à 0 et inférieur ou égal à 1.", "top-k": "Top K", - "top-k-hint": "Limite les choix du modèle à un ensemble fixe des \"K\" jetons les plus probables.", + "top-k-hint": "Limite le choix du modèle à un ensemble fixe des K tokens les plus probables.", "top-k-min": "Doit être supérieur ou égal à 0.", "presence-penalty": "Pénalité de présence", - "presence-penalty-hint": "Applique une pénalité fixe à la probabilité d’un jeton s’il est déjà apparu dans le texte.", + "presence-penalty-hint": "Applique une pénalité fixe à la probabilité d’un token s’il est déjà apparu dans le texte.", "frequency-penalty": "Pénalité de fréquence", - "frequency-penalty-hint": "Applique une pénalité à la probabilité d’un jeton qui augmente avec sa fréquence dans le texte.", - "max-output-tokens": "Nombre maximum de jetons en sortie", - "max-output-tokens-min": "Doit être supérieur à 0.", - "max-output-tokens-hint": "Définit le nombre maximal de jetons que le modèle peut générer en une seule réponse.", + "frequency-penalty-hint": "Applique une pénalité à la probabilité d’un token selon sa fréquence dans le texte.", + "max-output-tokens": "Nombre maximal de tokens en sortie", + "max-output-tokens-hint": "Définit le nombre maximal de tokens que \nle modèle peut générer dans une réponse unique.", + "context-length": "Longueur du contexte", + "context-length-hint": "Définit la taille de la fenêtre de contexte en tokens. Cela inclut l'entrée utilisateur et la réponse générée.", "endpoint": "Point de terminaison", "endpoint-required": "Le point de terminaison est requis.", + "baseurl": "URL de base", + "baseurl-required": "L’URL de base est requise.", "service-version": "Version du service", "check-connectivity": "Vérifier la connectivité", "check-connectivity-success": "La requête de test a réussi", "check-connectivity-failed": "La requête de test a échoué", - "no-model-matching": "Aucun modèle correspondant à '{{entity}}' trouvé.", + "no-model-matching": "Aucun modèle correspondant à '{{entity}}' n’a été trouvé.", "model-required": "Le modèle est requis.", - "no-model-text": "Aucun modèle trouvé." + "no-model-text": "Aucun modèle trouvé.", + "authentication": "Authentification", + "authentication-basic-hint": "Utilise l’authentification HTTP Basic standard. Le nom d’utilisateur et le mot de passe seront combinés, encodés en Base64 et envoyés dans l’en-tête \"Authorization\" de chaque requête vers le serveur Ollama.", + "authentication-token-hint": "Utilise l’authentification par jeton Bearer. Le jeton fourni sera directement envoyé dans l’en-tête \"Authorization\" de chaque requête vers le serveur Ollama.", + "authentication-type": { + "none": "Aucune", + "basic": "Basic", + "token": "Jeton" + }, + "username": "Nom d’utilisateur", + "username-required": "Le nom d’utilisateur est requis.", + "password": "Mot de passe", + "password-required": "Le mot de passe est requis.", + "token": "Jeton", + "token-required": "Le jeton est requis." }, "confirm-on-exit": { - "message": "Vous avez des modifications non enregistrées. Êtes-vous sûr de vouloir quitter cette page ?", - "html-message": "Vous avez des modifications non enregistrées.
Êtes-vous sûr de vouloir quitter cette page ?", + "message": "Des modifications non enregistrées existent. Voulez-vous vraiment quitter cette page ?", + "html-message": "Des modifications non enregistrées existent.
Voulez-vous vraiment quitter cette page ?", "title": "Modifications non enregistrées" }, "contact": { @@ -1321,21 +1340,21 @@ "dashboard": "Tableau de bord", "dashboards": "Tableaux de bord", "management": "Gestion des tableaux de bord", - "view-dashboards": "Voir les tableaux de bord", + "view-dashboards": "Afficher les tableaux de bord", "add": "Ajouter un tableau de bord", "assign-dashboard-to-customer": "Assigner le(s) tableau(x) de bord au client", "assign-dashboard-to-customer-text": "Veuillez sélectionner les tableaux de bord à assigner au client", - "assign-to-customer-text": "Veuillez sélectionner le client à qui assigner le(s) tableau(x) de bord", + "assign-to-customer-text": "Veuillez sélectionner le client auquel assigner le(s) tableau(x) de bord", "assign-to-customer": "Assigner au client", "unassign-from-customer": "Désassigner du client", - "make-public": "Rendre public le tableau de bord", - "make-private": "Rendre privé le tableau de bord", + "make-public": "Rendre le tableau de bord public", + "make-private": "Rendre le tableau de bord privé", "manage-assigned-customers": "Gérer les clients assignés", "assigned-customers": "Clients assignés", "assign-to-customers": "Assigner le(s) tableau(x) de bord aux clients", "assign-to-customers-text": "Veuillez sélectionner les clients à qui assigner le(s) tableau(x) de bord", "unassign-from-customers": "Désassigner le(s) tableau(x) de bord des clients", - "unassign-from-customers-text": "Veuillez sélectionner les clients à désassigner du tableau(x) de bord", + "unassign-from-customers-text": "Veuillez sélectionner les clients à désassigner du/des tableau(x) de bord", "no-dashboards-text": "Aucun tableau de bord trouvé", "no-widgets": "Aucun widget configuré", "add-widget": "Ajouter un nouveau widget", @@ -1574,24 +1593,24 @@ "maximum-function-types": "Maximum { count, plural, =1 {1 type de fonction autorisé.} other {# types de fonctions autorisés} }", "time-description": "horodatage de la valeur actuelle ;", "value-description": "la valeur actuelle ;", - "prev-value-description": "résultat de l'appel précédent de la fonction ;", + "prev-value-description": "résultat de l'appel de fonction précédent ;", "time-prev-description": "horodatage de la valeur précédente ;", - "prev-orig-value-description": "valeur d'origine précédente ;", + "prev-orig-value-description": "valeur précédente d'origine ;", "aggregation": "Agrégation", - "aggregation-type-hint-common": "Pour des raisons de performance, le calcul des valeurs agrégées est disponible uniquement pour des intervalles de temps fixes comme « jour actuel », « mois actuel », etc., et n'est pas disponible pour des fenêtres glissantes comme « 30 dernières minutes » ou « dernières 24 heures ».", + "aggregation-type-hint-common": "Pour des raisons de performance, le calcul des valeurs agrégées est disponible uniquement pour des intervalles temporels fixes comme \"jour en cours\", \"mois en cours\", etc., et n'est pas disponible pour des fenêtres glissantes comme '30 dernières minutes' ou '24 dernières heures'.", "aggregation-type-none-hint": "Prendre la dernière valeur.", - "aggregation-type-min-hint": "Trouver la valeur minimale parmi les points de données dans la fenêtre temporelle sélectionnée.", - "aggregation-type-max-hint": "Trouver la valeur maximale parmi les points de données dans la fenêtre temporelle sélectionnée.", - "aggregation-type-avg-hint": "Calculer la moyenne des valeurs dans la fenêtre temporelle sélectionnée.", - "aggregation-type-sum-hint": "Additionner toutes les valeurs dans la fenêtre temporelle sélectionnée.", - "aggregation-type-count-hint": "Nombre total de points de données dans la fenêtre temporelle sélectionnée.", + "aggregation-type-min-hint": "Trouver la valeur minimale parmi les points de données dans une fenêtre temporelle sélectionnée.", + "aggregation-type-max-hint": "Trouver la valeur maximale parmi les points de données dans une fenêtre temporelle sélectionnée.", + "aggregation-type-avg-hint": "Calculer la valeur moyenne parmi les points de données dans une fenêtre temporelle sélectionnée.", + "aggregation-type-sum-hint": "Additionner toutes les valeurs des points de données dans une fenêtre temporelle sélectionnée.", + "aggregation-type-count-hint": "Nombre total de points de données dans une fenêtre temporelle sélectionnée.", "delta-calculation": "Calcul du delta", "enable-delta-calculation": "Activer le calcul du delta", - "enable-delta-calculation-hint": "Lorsqu'il est activé, la valeur de la clé de données est calculée sur la base des valeurs agrégées pour une fenêtre temporelle sélectionnée et une période de comparaison spécifiée. Pour des raisons de performance, le calcul du delta est disponible uniquement pour des fenêtres temporelles historiques et non pour des valeurs en temps réel. Par exemple, vous pouvez calculer le delta entre la consommation d'énergie d'hier et celle de l'avant-hier.", + "enable-delta-calculation-hint": "Lorsqu'activé, la valeur de la clé de données est calculée à partir des valeurs agrégées pour une fenêtre temporelle sélectionnée et une période de comparaison définie. Pour des raisons de performance, le calcul du delta est disponible uniquement pour les fenêtres historiques, et non pour les valeurs en temps réel. Par exemple, vous pouvez calculer le delta entre la consommation énergétique d'hier et celle de l'avant-veille.", "delta-calculation-result": "Résultat du calcul du delta", "delta-calculation-result-previous-value": "Valeur précédente", "delta-calculation-result-delta-absolute": "Delta (absolu)", - "delta-calculation-result-delta-percent": "Delta (pourcentage)", + "delta-calculation-result-delta-percent": "Delta (en pourcentage)", "source": "Source", "latest": "Dernier", "latest-value": "Dernière valeur", @@ -1698,30 +1717,30 @@ "lwm2m-security-config": { "identity": "Identité du client", "identity-required": "L'identité du client est requise.", - "identity-tooltip": "L'identifiant PSK est un identifiant arbitraire pouvant aller jusqu'à 128 octets, tel que décrit dans la norme [RFC7925].\nL'identifiant PSK DOIT d'abord être converti en chaîne de caractères puis encodé en octets à l'aide de l'encodage UTF-8.", + "identity-tooltip": "L'identifiant PSK est un identifiant PSK arbitraire jusqu'à 128 octets, comme décrit dans la norme [RFC7925].\nL'identifiant PSK DOIT d'abord être converti en chaîne de caractères, puis encodé en octets en utilisant UTF-8.", "client-key": "Clé du client", "client-key-required": "La clé du client est requise.", - "client-key-tooltip-prk": "La clé publique RPK ou l'identifiant doit être conforme à la norme [RFC7250] et encodée en Base64 !", - "client-key-tooltip-psk": "La clé PSK doit être conforme à la norme [RFC4279] et au format HexDec : 32, 64, 128 caractères !", - "endpoint": "Nom du client Endpoint", - "endpoint-required": "Le nom du client Endpoint est requis.", + "client-key-tooltip-prk": "La clé publique ou l'identifiant RPK doit respecter la norme [RFC7250] et être encodé en Base64 !", + "client-key-tooltip-psk": "La clé PSK doit respecter la norme [RFC4279] et être au format HexDec : 32, 64 ou 128 caractères !", + "endpoint": "Nom de l’endpoint du client", + "endpoint-required": "Le nom de l’endpoint du client est requis.", "client-public-key": "Clé publique du client", "client-public-key-hint": "Si la clé publique du client est vide, le certificat de confiance sera utilisé", - "client-public-key-tooltip": "La clé publique X509 doit être au format DER-encodé X509v3, uniquement avec l’algorithme EC, et encodée ensuite en Base64 !", + "client-public-key-tooltip": "La clé publique X509 doit être au format X509v3 encodé en DER, uniquement compatible avec l'algorithme EC, puis encodée en Base64 !", "mode": "Mode de configuration de sécurité", "client-tab": "Configuration de sécurité du client", "client-certificate": "Certificat du client", "bootstrap-tab": "Client Bootstrap", "bootstrap-server": "Serveur Bootstrap", "lwm2m-server": "Serveur LwM2M", - "client-publicKey-or-id": "Clé publique ou identifiant du client", - "client-publicKey-or-id-required": "Clé publique ou identifiant du client est requis.", - "client-publicKey-or-id-tooltip-psk": "L'identifiant PSK est un identifiant arbitraire jusqu'à 128 octets, selon la norme [RFC7925].\nIl DOIT être d'abord converti en chaîne puis encodé en UTF-8.", + "client-publicKey-or-id": "Clé publique ou ID du client", + "client-publicKey-or-id-required": "La clé publique ou l'ID du client est requis.", + "client-publicKey-or-id-tooltip-psk": "L'identifiant PSK est un identifiant PSK arbitraire jusqu'à 128 octets, comme décrit dans la norme [RFC7925].\nL'identifiant PSK DOIT d'abord être converti en chaîne de caractères, puis encodé en octets en utilisant UTF-8.", "client-publicKey-or-id-tooltip-rpk": "La clé publique ou l'identifiant RPK doit respecter la norme [RFC7250] et être encodé en Base64 !", - "client-publicKey-or-id-tooltip-x509": "La clé publique X509 doit être au format DER-encodé X509v3, supportant exclusivement l’algorithme EC, et encodée en Base64.", + "client-publicKey-or-id-tooltip-x509": "La clé publique X509 doit être au format X509v3 encodé en DER, uniquement compatible avec l'algorithme EC, puis encodée en Base64.", "client-secret-key": "Clé secrète du client", "client-secret-key-required": "La clé secrète du client est requise.", - "client-secret-key-tooltip-psk": "La clé PSK doit respecter la norme [RFC4279] et être au format HexDec : 32, 64, 128 caractères !", + "client-secret-key-tooltip-psk": "La clé PSK doit respecter la norme [RFC4279] et être au format HexDec : 32, 64 ou 128 caractères !", "client-secret-key-tooltip-prk": "La clé secrète RPK doit être au format PKCS_8 (encodage DER, norme [RFC5958]) puis encodée en Base64 !", "client-secret-key-tooltip-x509": "La clé secrète X509 doit être au format PKCS_8 (encodage DER, norme [RFC5958]) puis encodée en Base64 !" }, @@ -1842,7 +1861,7 @@ "min": "Min", "max": "Max", "step": "Pas", - "selected-options-limit": "Limite d'options sélectionnées", + "selected-options-limit": "Limite des options sélectionnées", "advanced-ui-settings": "Paramètres UI avancés", "disable-on-property": "Désactiver selon la propriété", "disable-on-property-none": "Aucune (champ toujours activé)", @@ -1877,10 +1896,10 @@ "html-section-classes": "Classes de section HTML", "html-section-content": "Contenu de la section HTML", "array-item": "Élément du tableau", - "item-type": "Type d'élément", - "item-name": "Nom de l'élément", + "item-type": "Type d’élément", + "item-name": "Nom de l’élément", "no-items": "Aucun élément", - "support-unit-conversion": "Prise en charge de la conversion d'unités" + "support-unit-conversion": "Supporte la conversion d’unités" }, "clear-form": "Effacer le formulaire", "clear-form-prompt": "Êtes-vous sûr de vouloir supprimer toutes les propriétés du formulaire ?", @@ -1936,28 +1955,28 @@ "invalid-asset-profile-file-error": "Impossible d'importer le profil d'actif : structure de données invalide." }, "device-profile": { - "device-profile": "Profil de dispositif", - "device-profiles": "Profils de dispositifs", + "device-profile": "Profil d'appareil", + "device-profiles": "Profils d'appareils", "all-device-profiles": "Tous", - "add": "Ajouter un profil de dispositif", - "edit": "Modifier le profil de dispositif", - "device-profile-details": "Détails du profil de dispositif", - "no-device-profiles-text": "Aucun profil de dispositif trouvé", - "search": "Rechercher des profils de dispositifs", - "selected-device-profiles": "{ count, plural, =1 {1 profil de dispositif} other {# profils de dispositifs} } sélectionné(s)", - "no-device-profiles-matching": "Aucun profil de dispositif correspondant à '{{entity}}' trouvé.", - "device-profile-required": "Le profil de dispositif est requis", - "idCopiedMessage": "L'identifiant du profil de dispositif a été copié dans le presse-papiers", - "set-default": "Définir comme profil de dispositif par défaut", - "delete": "Supprimer le profil de dispositif", - "copyId": "Copier l'identifiant du profil de dispositif", + "add": "Ajouter un profil d'appareil", + "edit": "Modifier le profil d'appareil", + "device-profile-details": "Détails du profil d'appareil", + "no-device-profiles-text": "Aucun profil d'appareil trouvé", + "search": "Rechercher des profils d'appareils", + "selected-device-profiles": "{ count, plural, =1 {1 profil d'appareil} other {# profils d'appareils} } sélectionné(s)", + "no-device-profiles-matching": "Aucun profil d'appareil correspondant à '{{entity}}' trouvé.", + "device-profile-required": "Le profil d'appareil est requis", + "idCopiedMessage": "L'identifiant du profil d'appareil a été copié dans le presse-papiers", + "set-default": "Définir comme profil d'appareil par défaut", + "delete": "Supprimer le profil d'appareil", + "copyId": "Copier l'identifiant du profil d'appareil", "name-max-length": "Le nom doit contenir moins de 256 caractères", "name": "Nom", "name-required": "Le nom est requis.", "type": "Type de profil", "type-required": "Le type de profil est requis.", "type-default": "Par défaut", - "image": "Image du profil de dispositif", + "image": "Image du profil d'appareil", "transport-type": "Type de transport", "transport-type-required": "Le type de transport est requis.", "transport-type-default": "Par défaut", @@ -1977,33 +1996,33 @@ "transport-configuration": "Configuration du transport", "default-rule-chain": "Chaîne de règles par défaut", "default-edge-rule-chain": "Chaîne de règles Edge par défaut", - "default-edge-rule-chain-hint": "Utilisé sur Edge comme chaîne de règles pour traiter les données entrantes des dispositifs de ce profil", + "default-edge-rule-chain-hint": "Utilisée sur l’Edge comme chaîne de règles pour traiter les données entrantes des appareils liés à ce profil d’appareil", "mobile-dashboard": "Tableau de bord mobile", - "mobile-dashboard-hint": "Utilisé par l'application mobile comme tableau de bord des détails du dispositif", - "select-queue-hint": "Sélectionnez dans une liste déroulante.", - "delete-device-profile-title": "Êtes-vous sûr de vouloir supprimer le profil de dispositif '{{deviceProfileName}}' ?", - "delete-device-profile-text": "Attention, après confirmation, le profil de dispositif et toutes les données associées, y compris les mises à jour OTA, seront irrécupérables.", - "delete-device-profiles-title": "Êtes-vous sûr de vouloir supprimer { count, plural, =1 {1 profil de dispositif} other {# profils de dispositifs} } ?", - "delete-device-profiles-text": "Attention, après confirmation, tous les profils de dispositifs sélectionnés seront supprimés ainsi que toutes les données associées, y compris les mises à jour OTA.", - "set-default-device-profile-title": "Êtes-vous sûr de vouloir définir le profil de dispositif '{{deviceProfileName}}' comme par défaut ?", - "set-default-device-profile-text": "Après confirmation, ce profil de dispositif sera marqué comme par défaut et utilisé pour les nouveaux dispositifs sans profil spécifié.", - "no-device-profiles-found": "Aucun profil de dispositif trouvé.", + "mobile-dashboard-hint": "Utilisé par l'application mobile comme tableau de bord des détails de l’appareil", + "select-queue-hint": "Sélectionnez dans la liste déroulante.", + "delete-device-profile-title": "Voulez-vous vraiment supprimer le profil d’appareil '{{deviceProfileName}}' ?", + "delete-device-profile-text": "Attention, après confirmation, le profil d’appareil et toutes les données associées, y compris les mises à jour OTA, seront irrécupérables.", + "delete-device-profiles-title": "Voulez-vous vraiment supprimer { count, plural, =1 {1 profil d’appareil} other {# profils d’appareil} } ?", + "delete-device-profiles-text": "Attention, après confirmation, tous les profils d’appareil sélectionnés seront supprimés et toutes les données associées, y compris les mises à jour OTA, seront irrécupérables.", + "set-default-device-profile-title": "Voulez-vous définir le profil d’appareil '{{deviceProfileName}}' comme profil par défaut ?", + "set-default-device-profile-text": "Après confirmation, ce profil sera marqué comme par défaut et utilisé pour tout nouvel appareil sans profil spécifié.", + "no-device-profiles-found": "Aucun profil d’appareil trouvé.", "create-new-device-profile": "Créer un nouveau !", - "mqtt-device-topic-filters": "Filtres de sujet MQTT du dispositif", - "mqtt-device-topic-filters-unique": "Les filtres de sujet MQTT doivent être uniques.", - "mqtt-device-topic-filters-spark-plug": "Nœud EoN MQTT Sparkplug B.", - "mqtt-device-topic-filters-spark-plug-hint": "Permet les connexions de nœuds EoN avec format de charge utile et de sujet Sparkplug B.", - "mqtt-device-topic-filters-spark-plug-attribute-metric-names": "Métriques SparkPlug à stocker comme attributs.", - "mqtt-device-topic-filters-spark-plug-attribute-metric-names-hint": "Noms des métriques SparkPlug qui seront stockées comme attributs de l'appareil. Toutes les autres seront stockées comme télémétrie.", - "mqtt-device-payload-type": "Charge utile MQTT du dispositif", + "mqtt-device-topic-filters": "Filtres de topics MQTT pour l’appareil", + "mqtt-device-topic-filters-unique": "Les filtres de topics MQTT doivent être uniques.", + "mqtt-device-topic-filters-spark-plug": "Nœud Edge of Network (EoN) Sparkplug B MQTT.", + "mqtt-device-topic-filters-spark-plug-hint": "Permet les connexions de nœuds EoN avec format de topic et charge utile Sparkplug B.", + "mqtt-device-topic-filters-spark-plug-attribute-metric-names": "Métriques SparkPlug à stocker en tant qu’attributs.", + "mqtt-device-topic-filters-spark-plug-attribute-metric-names-hint": "Noms des métriques SparkPlug qui seront stockées en tant qu’attributs d’appareil. Toutes les autres seront stockées comme télémétrie.", + "mqtt-device-payload-type": "Charge utile MQTT de l’appareil", "mqtt-device-payload-type-json": "JSON", "mqtt-device-payload-type-proto": "Protobuf", "mqtt-enable-compatibility-with-json-payload-format": "Activer la compatibilité avec d'autres formats de charge utile.", - "mqtt-enable-compatibility-with-json-payload-format-hint": "Lorsque cette option est activée, la plateforme utilisera le format Protobuf par défaut. En cas d'échec de l'analyse, elle utilisera le format JSON. Utile pour les mises à jour de firmware. À désactiver une fois tous les dispositifs mis à jour.", - "mqtt-use-json-format-for-default-downlink-topics": "Utiliser le format JSON pour les sujets descendants par défaut", - "mqtt-use-json-format-for-default-downlink-topics-hint": "Utilise JSON pour les sujets : v1/devices/me/attributes/response/$request_id, etc. Ne s'applique pas aux sujets v2.", - "mqtt-send-ack-on-validation-exception": "Envoyer PUBACK en cas d'échec de validation", - "mqtt-send-ack-on-validation-exception-hint": "Par défaut, la session MQTT est fermée sur erreur. Si activé, envoie un accusé de réception PUBACK à la place.", + "mqtt-enable-compatibility-with-json-payload-format-hint": "Lorsqu'activé, la plateforme utilisera par défaut le format de charge utile Protobuf. En cas d'échec du parsing, elle tentera d'utiliser le format JSON. Utile pour la rétrocompatibilité lors des mises à jour du firmware. Par exemple, la version initiale du firmware utilise Json, tandis que la nouvelle version utilise Protobuf. Pendant la mise à jour du parc d'appareils, il est nécessaire de supporter les deux formats simultanément. Ce mode introduit une légère dégradation des performances, il est donc recommandé de le désactiver une fois tous les appareils mis à jour.", + "mqtt-use-json-format-for-default-downlink-topics": "Utiliser le format Json pour les topics descendants par défaut", + "mqtt-use-json-format-for-default-downlink-topics-hint": "Lorsqu’activé, la plateforme utilisera le format de charge utile Json pour envoyer des attributs et des RPC via les topics suivants : v1/devices/me/attributes/response/$request_id, v1/devices/me/attributes, v1/devices/me/rpc/request/$request_id, v1/devices/me/rpc/response/$request_id. Ce paramètre n'affecte pas les abonnements aux attributs et RPC utilisant les nouveaux topics (v2) : v2/a/res/$request_id, v2/a, v2/r/req/$request_id, v2/r/res/$request_id. Où $request_id est un identifiant de requête entier.", + "mqtt-send-ack-on-validation-exception": "Envoyer PUBACK en cas d’échec de validation de message PUBLISH", + "mqtt-send-ack-on-validation-exception-hint": "Par défaut, la plateforme ferme la session MQTT en cas d'échec de validation du message. Lorsqu’activé, elle envoie un accusé de réception (PUBACK) au lieu de fermer la session.", "mqtt-protocol-version": "Version du protocole", "snmp-add-mapping": "Ajouter un mappage SNMP", "snmp-mapping-not-configured": "Aucun mappage OID vers série temporelle ou attribut configuré", @@ -2261,17 +2280,17 @@ "account-after-timeout-tooltip": "Valeur de délai pour l’inscription au serveur Bootstrap.", "server-type": "Type de serveur", "add-new-server-title": "Ajouter une nouvelle configuration de serveur", - "add-server-config": "Ajouter la configuration du serveur", + "add-server-config": "Ajouter une configuration de serveur", "add-lwm2m-server-config": "Ajouter un serveur LwM2M", "no-config-servers": "Aucun serveur configuré", "others-tab": "Autres paramètres", "ota-update": "Mise à jour OTA", "use-object-19-for-ota-update": "Utiliser l'objet 19 pour les métadonnées de fichier OTA (checksum, taille, version, nom)", - "use-object-19-for-ota-update-hint": "Utiliser l'objet ressource avec ObjectId = 19 pour les mises à jour OTA : FirmWare → InstanceId = 65534, SoftWare → InstanceId = 65535. Le format des données est du JSON encodé en Base64. Ce JSON contient les métadonnées du fichier OTA : \"Checksum\" (SHA256). Champs supplémentaires : \"Title\" (nom de la mise à jour OTA), \"Version\" (version OTA), \"File Name\" (nom du fichier pour le stockage OTA côté client), \"File Size\" (taille OTA en octets).", - "client-strategy": "Stratégie client lors de la connexion", + "use-object-19-for-ota-update-hint": "Utiliser l'objet de ressource ObjectId = 19 pour les mises à jour OTA : FirmWare → InstanceId = 65534, SoftWare → InstanceId = 65535. Le format des données est JSON encapsulé en Base64. Ce JSON contient les métadonnées du fichier OTA : \"Checksum\" (SHA256). Champs supplémentaires : \"Title\" (nom OTA), \"Version\" (version OTA), \"File Name\" (nom de fichier à stocker côté client), \"File Size\" (taille du fichier OTA en octets).", + "client-strategy": "Stratégie du client lors de la connexion", "client-strategy-label": "Stratégie", - "client-strategy-only-observe": "Envoyer uniquement la requête d’observation après connexion initiale", - "client-strategy-read-all": "Lire toutes les ressources & envoyer la requête d’observation après enregistrement", + "client-strategy-only-observe": "Envoyer uniquement une requête Observe après la connexion initiale", + "client-strategy-read-all": "Lire toutes les ressources et envoyer une requête Observe après l’enregistrement", "fw-update": "Mise à jour du firmware", "fw-update-strategy": "Stratégie de mise à jour du firmware", "fw-update-strategy-data": "Pousser le firmware en tant que fichier binaire via Objet 19 Ressource 0 (Data)", @@ -2295,20 +2314,20 @@ "min-evaluation-period": "Période d’évaluation minimale", "max-evaluation-period": "Période d’évaluation maximale" }, - "default-object-id": "Version par défaut de l'objet (Attribut)", + "default-object-id": "Version d’objet par défaut (attribut)", "default-object-id-ver": { "v1-0": "1.0", "v1-1": "1.1", "v1-2": "1.2" }, "observe-strategy": { - "observe-strategy": "Stratégie d'observation", + "observe-strategy": "Stratégie d’observation", "single": "Unique", - "single-description": "Une requête Observe par ressource (plus grande précision, plus de trafic réseau)", - "composite-all": "Composé - tout", - "composite-all-description": "Toutes les ressources sont observées avec une seule requête Composite Observe (plus efficace, moins flexible)", - "composite-by-object": "Composé par objets", - "composite-by-object-description": "Les ressources sont regroupées par type d'objet et observées via des requêtes Composite Observe distinctes (approche équilibrée)" + "single-description": "Une requête Observe par ressource (meilleure précision, plus de trafic réseau)", + "composite-all": "Composite global", + "composite-all-description": "Toutes les ressources sont observées avec une seule requête Observe Composite (plus efficace, moins flexible)", + "composite-by-object": "Composite par objets", + "composite-by-object-description": "Les ressources sont regroupées par type d’objet et observées via des requêtes Observe Composite distinctes (approche équilibrée)" } }, "snmp": { @@ -2375,19 +2394,19 @@ "instances": "Instances", "edge-file": "Fichier Edge", "name-max-length": "Le nom doit contenir moins de 256 caractères", - "label-max-length": "Le label doit contenir moins de 256 caractères", + "label-max-length": "Le libellé doit contenir moins de 256 caractères", "type-max-length": "Le type doit contenir moins de 256 caractères", - "management": "Gestion des Edge", - "no-edges-matching": "Aucun Edge correspondant à '{{entity}}' trouvé.", - "add": "Ajouter un Edge", + "management": "Gestion Edge", + "no-edges-matching": "Aucun Edge correspondant à '{{entity}}' n'a été trouvé.", + "add": "Ajouter Edge", "no-edges-text": "Aucun Edge trouvé", - "edge-details": "Détails du Edge", + "edge-details": "Détails Edge", "add-edge-text": "Ajouter un nouveau Edge", - "delete": "Supprimer le Edge", + "delete": "Supprimer Edge", "delete-edge-title": "Êtes-vous sûr de vouloir supprimer le Edge '{{edgeName}}' ?", - "delete-edge-text": "Attention, après confirmation, le Edge et toutes les données associées seront irrécupérables.", + "delete-edge-text": "Attention, après confirmation le Edge et toutes les données associées deviendront irrécupérables.", "delete-edges-title": "Êtes-vous sûr de vouloir supprimer { count, plural, =1 {1 Edge} other {# Edge} } ?", - "delete-edges-text": "Attention, après confirmation, tous les Edge sélectionnés seront supprimés et toutes les données associées seront irrécupérables.", + "delete-edges-text": "Attention, après confirmation tous les Edge sélectionnés et toutes les données associées seront supprimés définitivement.", "name": "Nom", "name-starts-with": "Le nom du Edge commence par", "name-required": "Le nom est requis.", @@ -2398,11 +2417,11 @@ "id-copied-message": "L'ID du Edge a été copié dans le presse-papiers", "sync": "Synchroniser Edge", "edge-required": "Edge requis", - "edge-type": "Type de Edge", - "edge-type-required": "Le type de Edge est requis.", + "edge-type": "Type de l'Edge", + "edge-type-required": "Le type de l'Edge est requis.", "event-action": "Action d'événement", "entity-id": "ID de l'entité", - "select-edge-type": "Sélectionner le type de Edge", + "select-edge-type": "Sélectionner le type de l'Edge", "assign-to-customer": "Assigner à un client", "assign-to-customer-text": "Veuillez sélectionner le client à qui assigner le(s) Edge", "assign-edge-to-customer": "Assigner le(s) Edge à un client", @@ -2428,45 +2447,45 @@ "loading-edge-instructions": "Chargement des instructions pour Edge...", "label": "Label", "load-entity-error": "Échec du chargement des données. L'entité a été supprimée.", - "assign-new-edge": "Attribuer une nouvelle passerelle", - "unassign-from-edge": "Désattribuer de la passerelle", - "edge-key": "Clé de la passerelle", - "copy-edge-key": "Copier la clé de la passerelle", - "edge-key-copied-message": "La clé de la passerelle a été copiée dans le presse-papiers", - "edge-secret": "Secret de la passerelle", - "copy-edge-secret": "Copier le secret de la passerelle", - "edge-secret-copied-message": "Le secret de la passerelle a été copié dans le presse-papiers", - "manage-assets": "Gérer les actifs", + "assign-new-edge": "Assigner un nouvel Edge", + "unassign-from-edge": "Désassigner de l'Edge", + "edge-key": "Clé Edge", + "copy-edge-key": "Copier la clé Edge", + "edge-key-copied-message": "La clé Edge a été copiée dans le presse-papiers", + "edge-secret": "Secret Edge", + "copy-edge-secret": "Copier le secret Edge", + "edge-secret-copied-message": "Le secret Edge a été copié dans le presse-papiers", + "manage-assets": "Gérer les assets", "manage-devices": "Gérer les appareils", - "manage-entity-views": "Gérer les vues d'entité", + "manage-entity-views": "Gérer les vues d'entités", "manage-dashboards": "Gérer les tableaux de bord", "manage-rulechains": "Gérer les chaînes de règles", - "assets": "Actifs de la passerelle", - "devices": "Appareils de la passerelle", - "entity-views": "Vues d'entité de la passerelle", - "dashboard": "Tableau de bord de la passerelle", - "dashboards": "Tableaux de bord de la passerelle", + "assets": "Assets Edge", + "devices": "Appareils Edge", + "entity-views": "Vues d'entités Edge", + "dashboard": "Tableau de bord Edge", + "dashboards": "Tableaux de bord Edge", "rulechain-templates": "Modèles de chaînes de règles", - "edge-rulechain-templates": "Modèles de chaînes de règles pour passerelle", - "rulechains": "Chaînes de règles de la passerelle", - "search": "Rechercher des passerelles", - "selected-edges": "{ count, plural, =1 {1 passerelle} other {# passerelles} } sélectionnée(s)", - "any-edge": "Toute passerelle", - "no-edge-types-matching": "Aucun type de passerelle correspondant à '{{entitySubtype}}' n'a été trouvé.", - "edge-type-list-empty": "Aucun type de passerelle sélectionné.", - "edge-types": "Types de passerelles", - "enter-edge-type": "Saisir un type de passerelle", - "deployed": "Déployée", + "edge-rulechain-templates": "Modèles de chaînes de règles Edge", + "rulechains": "Chaînes de règles Edge", + "search": "Rechercher des Edge", + "selected-edges": "{ count, plural, =1 {1 Edge} other {# Edge} } sélectionné(s)", + "any-edge": "N’importe quel Edge", + "no-edge-types-matching": "Aucun type d’Edge correspondant à '{{entitySubtype}}' trouvé.", + "edge-type-list-empty": "Aucun type d’Edge sélectionné.", + "edge-types": "Types d’Edge", + "enter-edge-type": "Saisir un type d’Edge", + "deployed": "Déployé", "pending": "En attente", "downlinks": "Liaisons descendantes", "no-downlinks-prompt": "Aucune liaison descendante trouvée", - "sync-process-started-successfully": "Le processus de synchronisation a démarré avec succès !", - "missing-related-rule-chains-title": "La passerelle a des chaînes de règles liées manquantes", - "missing-related-rule-chains-text": "Les chaînes de règles attribuées à la passerelle utilisent des nœuds de règle qui transfèrent des messages vers des chaînes de règles non attribuées à cette passerelle.

Liste des chaînes de règles manquantes :
{{missingRuleChains}}", - "widget-datasource-error": "Ce widget ne prend en charge que les sources de données de type ENTITÉ PASSERELLE", + "sync-process-started-successfully": "Le processus de synchronisation a démarré avec succès!", + "missing-related-rule-chains-title": "Des chaînes de règles associées manquent sur l’Edge", + "missing-related-rule-chains-text": "Les chaînes de règles affectées à l’Edge utilisent des nœuds de règles qui transfèrent des messages vers des chaînes non affectées à cet Edge.

Liste des chaînes de règles manquantes :
{{missingRuleChains}}", + "widget-datasource-error": "Ce widget prend uniquement en charge les sources de données de type EDGE", "upgrade-instructions": "Instructions de mise à jour", - "connected": "Connectée", - "disconnected": "Déconnectée" + "connected": "Connecté", + "disconnected": "Déconnecté" }, "edge-event": { "type-dashboard": "Tableau de bord", @@ -2478,7 +2497,7 @@ "type-alarm": "Alarme", "type-rule-chain": "Chaîne de règles", "type-rule-chain-metadata": "Métadonnées de chaîne de règles", - "type-edge": "Passerelle", + "type-edge": "Edge", "type-user": "Utilisateur", "type-tenant": "Locataire", "type-tenant-profile": "Profil de locataire", @@ -2506,8 +2525,8 @@ "action-type-alarm-clear": "Réinitialisation de l'alarme", "action-type-alarm-assigned": "Alarme attribuée", "action-type-alarm-unassigned": "Alarme désattribuée", - "action-type-assigned-to-edge": "Attribué à une passerelle", - "action-type-unassigned-from-edge": "Désattribué d'une passerelle", + "action-type-assigned-to-edge": "Assigné à Edge", + "action-type-unassigned-from-edge": "Désassigné de l'Edge", "action-type-credentials-request": "Demande d'identifiants", "action-type-entity-merge-request": "Demande de fusion d'entités" }, @@ -2624,17 +2643,17 @@ "type-rulenode": "Nœud de règle", "type-rulenodes": "Nœuds de règle", "list-of-rulenodes": "{ count, plural, =1 {Un nœud de règle} other {Liste de # nœuds de règle} }", - "rulenode-name-starts-with": "Nœuds de règle dont les noms commencent par '{{prefix}}'", + "rulenode-name-starts-with": "Nœuds de règle dont le nom commence par '{{prefix}}'", "type-current-customer": "Client actuel", "type-current-tenant": "Locataire actuel", "type-current-user": "Utilisateur actuel", - "type-current-user-owner": "Propriétaire utilisateur actuel", + "type-current-user-owner": "Propriétaire de l'utilisateur actuel", "type-calculated-field": "Champ calculé", "type-calculated-fields": "Champs calculés", "type-ai-model": "Modèle IA", "type-ai-models": "Modèles IA", - "type-widgets-bundle": "Pack de widgets", - "type-widgets-bundles": "Packs de widgets", + "type-widgets-bundle": "Lot de widgets", + "type-widgets-bundles": "Lots de widgets", "list-of-widgets-bundles": "{ count, plural, =1 {Un pack de widgets} other {Liste de # packs de widgets} }", "type-widget": "Widget", "type-widgets": "Widgets", @@ -2661,13 +2680,13 @@ "type-tb-resource": "Ressource", "type-tb-resources": "Ressources", "list-of-tb-resources": "{ count, plural, =1 {Une ressource} other {Liste de # ressources} }", - "type-ota-package": "Paquet OTA", + "type-ota-package": "Package OTA", "type-ota-packages": "Packages OTA", "list-of-ota-packages": "{ count, plural, =1 {Un package OTA} other {Liste de # packages OTA} }", "type-rpc": "RPC", - "type-queue": "File d'attente", - "type-queue-stats": "Statistiques de file d'attente", - "type-queues-stats": "Statistiques des files d'attente", + "type-queue": "File d’attente", + "type-queue-stats": "Statistiques de file d’attente", + "type-queues-stats": "Statistiques des files d’attente", "type-notification": "Notification", "type-notification-rule": "Règle de notification", "type-notification-rules": "Règles de notification", @@ -2675,7 +2694,7 @@ "type-notification-target": "Destinataire de notification", "type-notification-targets": "Destinataires de notification", "list-of-notification-targets": "{ count, plural, =1 {Un destinataire de notification} other {Liste de # destinataires de notification} }", - "type-notification-request": "Demande de notification", + "type-notification-request": "Requête de notification", "type-notification-template": "Modèle de notification", "type-notification-templates": "Modèles de notification", "list-of-notification-templates": "{ count, plural, =1 {Un modèle de notification} other {Liste de # modèles de notification} }", @@ -2691,7 +2710,7 @@ "list-of-mobile-apps": "{ count, plural, =1 {Une application mobile} other {Liste de # applications mobiles} }", "type-mobile-app-bundle": "Pack mobile", "type-mobile-app-bundles": "Packs mobiles", - "list-of-mobile-app-bundles": "{ count, plural, =1 {Un pack mobile} other {Liste de # packs mobiles} }" + "list-of-mobile-app-bundles": "{ count, plural, =1 {Un bundle mobile} other {Liste de # bundles mobiles} }" }, "entity-field": { "created-time": "Date de création", @@ -2762,20 +2781,20 @@ "unassign-entity-views": "Désassigner les vues d'entité", "unassign-entity-views-action-title": "Désassigner { count, plural, =1 {1 vue d'entité} other {# vues d'entité} } du client", "assign-new-entity-view": "Assigner une nouvelle vue d'entité", - "delete-entity-view-title": "Êtes-vous sûr de vouloir supprimer la vue d'entité '{{entityViewName}}' ?", - "delete-entity-view-text": "Attention, après confirmation, la vue d'entité et toutes ses données seront irrécupérables.", - "delete-entity-views-title": "Êtes-vous sûr de vouloir supprimer { count, plural, =1 {1 vue d'entité} other {# vues d'entité} } ?", - "delete-entity-views-action-title": "Supprimer { count, plural, =1 {1 vue d'entité} other {# vues d'entité} }", - "delete-entity-views-text": "Attention, après confirmation, toutes les vues d'entité sélectionnées seront supprimées avec leurs données.", - "make-public-entity-view-title": "Êtes-vous sûr de vouloir rendre la vue d'entité '{{entityViewName}}' publique ?", - "make-public-entity-view-text": "Après confirmation, la vue d'entité et ses données seront rendues publiques.", - "make-private-entity-view-title": "Êtes-vous sûr de vouloir rendre la vue d'entité '{{entityViewName}}' privée ?", - "make-private-entity-view-text": "Après confirmation, la vue d'entité et ses données seront rendues privées.", - "unassign-entity-view-title": "Êtes-vous sûr de vouloir désassigner la vue d'entité '{{entityViewName}}' ?", - "unassign-entity-view-text": "Après confirmation, la vue d'entité ne sera plus accessible au client.", - "unassign-entity-view": "Désassigner la vue d'entité", - "unassign-entity-views-title": "Êtes-vous sûr de vouloir désassigner { count, plural, =1 {1 vue d'entité} other {# vues d'entité} } ?", - "unassign-entity-views-text": "Après confirmation, toutes les vues d'entité sélectionnées seront désassignées.", + "delete-entity-view-title": "Voulez-vous vraiment supprimer la vue d’entité '{{entityViewName}}' ?", + "delete-entity-view-text": "Attention, après confirmation, la vue d’entité et toutes les données associées seront irrécupérables.", + "delete-entity-views-title": "Voulez-vous vraiment supprimer { count, plural, =1 {1 vue d’entité} other {# vues d’entité} } ?", + "delete-entity-views-action-title": "Supprimer { count, plural, =1 {1 vue d’entité} other {# vues d’entité} }", + "delete-entity-views-text": "Attention, après confirmation, toutes les vues d’entité sélectionnées seront supprimées et toutes les données associées seront irrécupérables.", + "make-public-entity-view-title": "Voulez-vous vraiment rendre la vue d’entité '{{entityViewName}}' publique ?", + "make-public-entity-view-text": "Après confirmation, la vue d’entité et toutes ses données seront rendues publiques et accessibles à d’autres utilisateurs.", + "make-private-entity-view-title": "Voulez-vous vraiment rendre la vue d’entité '{{entityViewName}}' privée ?", + "make-private-entity-view-text": "Après confirmation, la vue d’entité et toutes ses données seront rendues privées et ne seront plus accessibles aux autres utilisateurs.", + "unassign-entity-view-title": "Voulez-vous vraiment désaffecter la vue d’entité '{{entityViewName}}' ?", + "unassign-entity-view-text": "Après confirmation, la vue d’entité sera désaffectée et ne sera plus accessible par le client.", + "unassign-entity-view": "Désaffecter la vue d’entité", + "unassign-entity-views-title": "Voulez-vous vraiment désaffecter { count, plural, =1 {1 vue d’entité} other {# vues d’entité} } ?", + "unassign-entity-views-text": "Après confirmation, toutes les vues d’entité sélectionnées seront désaffectées et ne seront plus accessibles par le client.", "entity-view-type": "Type de vue d'entité", "entity-view-type-required": "Le type de vue d'entité est requis.", "select-entity-view-type": "Sélectionner le type de vue d'entité", @@ -2811,19 +2830,19 @@ "timeseries-placeholder": "Séries temporelles", "target-entity": "Entité cible", "attributes-propagation": "Propagation des attributs", - "attributes-propagation-hint": "La vue d'entité copiera automatiquement les attributs spécifiés de l'entité cible chaque fois que vous enregistrez ou mettez à jour cette vue d'entité. Pour des raisons de performance, les attributs ne sont pas propagés automatiquement à chaque changement. Activez cette propagation via le nœud de règle « copy to view » lié aux messages « Post attributes » et « Attributes Updated ».", + "attributes-propagation-hint": "La vue d’entité copiera automatiquement les attributs spécifiés de l’entité cible à chaque enregistrement ou mise à jour de cette vue. Pour des raisons de performance, les attributs de l’entité cible ne sont pas propagés à la vue d’entité à chaque modification. Vous pouvez activer la propagation automatique en configurant un nœud de règle \"copy to view\" dans votre chaîne de règles et en liant les messages \"Post attributes\" et \"Attributes Updated\" à ce nouveau nœud.", "timeseries-data": "Données de séries temporelles", - "timeseries-data-hint": "Configurez les clés de séries temporelles de l'entité cible qui seront accessibles dans la vue d'entité. Ces données sont en lecture seule.", - "search": "Rechercher des vues d'entité", - "selected-entity-views": "{ count, plural, =1 {1 vue d'entité} other {# vues d'entité} } sélectionnée(s)", - "assign-entity-view-to-edge": "Assigner des vues d'entité à l'Edge", - "assign-entity-view-to-edge-text": "Veuillez sélectionner les vues d'entité à assigner à l'Edge", - "unassign-entity-view-from-edge-title": "Êtes-vous sûr de vouloir désassigner la vue d'entité '{{entityViewName}}' ?", - "unassign-entity-view-from-edge-text": "Après confirmation, la vue d'entité sera désassignée et ne sera plus accessible par l'Edge.", - "unassign-entity-views-from-edge-action-title": "Désassigner { count, plural, =1 {1 vue d'entité} other {# vues d'entité} } de l'Edge", - "unassign-entity-view-from-edge": "Désassigner la vue d'entité", - "unassign-entity-views-from-edge-title": "Êtes-vous sûr de vouloir désassigner { count, plural, =1 {1 vue d'entité} other {# vues d'entité} } ?", - "unassign-entity-views-from-edge-text": "Après confirmation, toutes les vues d'entité sélectionnées seront désassignées et ne seront plus accessibles par l'Edge." + "timeseries-data-hint": "Configurez les clés de séries temporelles de l’entité cible qui seront accessibles à la vue d’entité. Ces données sont en lecture seule.", + "search": "Rechercher des vues d’entité", + "selected-entity-views": "{ count, plural, =1 {1 vue d’entité} other {# vues d’entité} } sélectionnée(s)", + "assign-entity-view-to-edge": "Assigner la(les) vue(s) d’entité à l’Edge", + "assign-entity-view-to-edge-text": "Veuillez sélectionner les vues d’entité à assigner à l’Edge", + "unassign-entity-view-from-edge-title": "Voulez-vous vraiment désaffecter la vue d’entité '{{entityViewName}}' ?", + "unassign-entity-view-from-edge-text": "Après confirmation, la vue d’entité sera désaffectée et ne sera plus accessible par l’Edge.", + "unassign-entity-views-from-edge-action-title": "Désaffecter { count, plural, =1 {1 vue d’entité} other {# vues d’entité} } de l’Edge", + "unassign-entity-view-from-edge": "Désaffecter la vue d’entité", + "unassign-entity-views-from-edge-title": "Voulez-vous vraiment désaffecter { count, plural, =1 {1 vue d’entité} other {# vues d’entité} } ?", + "unassign-entity-views-from-edge-text": "Après confirmation, toutes les vues d’entité sélectionnées seront désaffectées et ne seront plus accessibles par l’Edge." }, "event": { "event-type": "Type d'événement", @@ -3044,18 +3063,18 @@ "duplicate-filter": "Un filtre portant le même nom existe déjà.", "filters": "Filtres", "unable-delete-filter-title": "Impossible de supprimer le filtre", - "unable-delete-filter-text": "Le filtre '{{filter}}' ne peut pas être supprimé car il est utilisé par les widgets suivants :
{{widgetsList}}", - "duplicate-filter-error": "Filtre en double trouvé '{{filter}}'.
Les filtres doivent être uniques au sein du tableau de bord.", - "missing-key-filters-error": "Les filtres clés sont manquants pour le filtre '{{filter}}'.", + "unable-delete-filter-text": "Le filtre '{{filter}}' ne peut pas être supprimé car il est utilisé par le(s) widget(s) suivant(s) :
{{widgetsList}}", + "duplicate-filter-error": "Filtre dupliqué détecté '{{filter}}'.
Les filtres doivent être uniques dans le tableau de bord.", + "missing-key-filters-error": "Il manque des filtres clés pour le filtre '{{filter}}'.", "filter": "Filtre", - "editable": "Éditable", - "editable-hint": "Autoriser l'utilisateur à modifier la valeur du filtre dans les tableaux de bord.", + "editable": "Modifiable", + "editable-hint": "Permettre à l’utilisateur de modifier la valeur du filtre dans les tableaux de bord.", "no-filters-found": "Aucun filtre trouvé.", "no-filter-text": "Aucun filtre spécifié", "add-filter-prompt": "Veuillez ajouter un filtre", "no-filter-matching": "'{{filter}}' introuvable.", - "create-new-filter": "Créer un nouveau !", - "create-new": "Créer nouveau", + "create-new-filter": "Créer un nouveau filtre !", + "create-new": "Créer", "filter-required": "Le filtre est requis.", "operation": { "operation": "Opération", @@ -3086,21 +3105,21 @@ "complex-filter": "Filtre complexe", "edit-complex-filter": "Modifier le filtre complexe", "edit-filter-user-params": "Modifier les paramètres utilisateur du prédicat du filtre", - "filter-user-params": "Paramètres utilisateur du prédicat du filtre", + "filter-user-params": "Paramètres utilisateur du prédicat de filtre", "user-parameters": "Paramètres utilisateur", - "display-label": "Libellé à afficher", + "display-label": "Libellé affiché", "custom-label": "Libellé personnalisé", - "custom-label-hint": "Activer pour définir votre propre étiquette pour le filtre. Si désactivé, une étiquette sera générée automatiquement.", - "order-priority": "Priorité d'ordre des champs", - "key-filter": "Filtre par clé", - "key-filters": "Filtres par clé", + "custom-label-hint": "Activer pour définir un libellé personnalisé pour le filtre. Lorsqu’il est désactivé, un libellé sera généré automatiquement.", + "order-priority": "Ordre d’affichage", + "key-filter": "Filtre clé", + "key-filters": "Filtres clés", "key-name": "Nom de la clé", "key-name-required": "Le nom de la clé est requis.", "key-type": { "key-type": "Type de clé", "attribute": "Attribut", "timeseries": "Séries temporelles", - "entity-field": "Champ d'entité", + "entity-field": "Champ d’entité", "constant": "Constante", "client-attribute": "Attribut client", "server-attribute": "Attribut serveur", @@ -3114,12 +3133,12 @@ "date-time": "Date/Heure" }, "value-type-required": "Le type de valeur de la clé est requis.", - "key-value-type-change-title": "Êtes-vous sûr de vouloir changer le type de valeur de la clé ?", - "key-value-type-change-message": "Si vous confirmez le nouveau type de valeur, tous les filtres de clés saisis seront supprimés.", - "no-key-filters": "Aucun filtre de clé configuré", - "add-key-filter": "Ajouter un filtre de clé", - "remove-key-filter": "Supprimer le filtre de clé", - "edit-key-filter": "Modifier le filtre de clé", + "key-value-type-change-title": "Voulez-vous vraiment changer le type de valeur de la clé ?", + "key-value-type-change-message": "Si vous confirmez le nouveau type de valeur, tous les filtres clés saisis seront supprimés.", + "no-key-filters": "Aucun filtre clé configuré", + "add-key-filter": "Ajouter un filtre clé", + "remove-key-filter": "Supprimer le filtre clé", + "edit-key-filter": "Modifier le filtre clé", "date": "Date", "time": "Heure", "current-tenant": "Locataire actuel", @@ -3132,10 +3151,10 @@ "dynamic-value": "Valeur dynamique", "no-dynamic-value": "Aucune valeur dynamique", "source-attribute": "Attribut source", - "switch-to-dynamic-value": "Basculer vers la valeur dynamique", - "switch-to-default-value": "Basculer vers la valeur par défaut", + "switch-to-dynamic-value": "Passer à une valeur dynamique", + "switch-to-default-value": "Revenir à la valeur par défaut", "inherit-owner": "Hériter du propriétaire", - "source-attribute-not-set": "Si l'attribut source n'est pas défini", + "source-attribute-not-set": "Si l’attribut source n’est pas défini", "unit": "Unité" }, "fullscreen": { @@ -3213,13 +3232,13 @@ "image-preview": "Aperçu de l'image", "update-image": "Mettre à jour l'image", "export-failed-error": "Impossible d'exporter l'image : {{error}}", - "image-json-file": "Fichier JSON d'image", - "invalid-image-json-file-error": "Impossible d'importer l'image : structure JSON invalide.", - "image-is-in-use": "L'image est utilisée par d'autres entités", - "images-are-in-use": "Certaines images sont utilisées par d'autres entités", - "image-is-in-use-text": "L'image '{{title}}' n'a pas été supprimée car elle est utilisée par les entités suivantes :", - "images-are-in-use-text": "Toutes les images n'ont pas été supprimées car elles sont utilisées par d'autres entités.
Vous pouvez voir les entités référencées en cliquant sur le bouton Références dans la ligne de l'image concernée.
Si vous souhaitez tout de même les supprimer, sélectionnez-les dans le tableau ci-dessous puis cliquez sur le bouton Supprimer la sélection.", - "delete-image-in-use-text": "Si vous souhaitez tout de même supprimer l'image, cliquez sur le bouton Supprimer quand même.", + "image-json-file": "Fichier JSON de l’image", + "invalid-image-json-file-error": "Impossible d’importer l’image depuis le JSON : structure de données JSON invalide.", + "image-is-in-use": "L’image est utilisée par d’autres entités", + "images-are-in-use": "Des images sont utilisées par d’autres entités", + "image-is-in-use-text": "L’image '{{title}}' n’a pas été supprimée car elle est utilisée par les entités suivantes :", + "images-are-in-use-text": "Toutes les images n’ont pas été supprimées car elles sont utilisées par d’autres entités.
Vous pouvez consulter les entités référencées en cliquant sur le bouton Références dans la ligne correspondante de l’image.
Si vous souhaitez tout de même supprimer ces images, sélectionnez-les dans le tableau ci-dessous et cliquez sur le bouton Supprimer la sélection.", + "delete-image-in-use-text": "Si vous souhaitez tout de même supprimer l’image, cliquez sur le bouton Supprimer quand même.", "system-entities": "Entités système :", "entities": "entités :", "references": "Références", @@ -3301,7 +3320,7 @@ "community-string": "Chaîne de communauté SNMP" }, "isgateway": "Est une passerelle", - "activity-time-from-gateway-device": "Heure d'activité depuis le périphérique passerelle", + "activity-time-from-gateway-device": "Heure d'activité depuis l'appareil passerelle", "description": "Description", "routing-key": "Clé Edge", "secret": "Secret Edge" @@ -3521,11 +3540,11 @@ "power-button-background": "Arrière-plan du bouton de mise sous tension", "value-box-background": "Arrière-plan de la boîte de valeur", "value-units": "Unités de valeur", - "enable-units-scale": "Activer les unités sur l'échelle", + "enable-units-scale": "Activer les unités sur l’échelle", "filtration-mode": "Mode de filtration", "filtration-mode-hint": "Valeur entière indiquant le mode de filtration actuel.", - "filtration-mode-update": "État de mise à jour du mode de filtration", - "filtration-mode-update-hint": "Action déclenchée lorsque l'utilisateur clique pour modifier le mode de filtration actuel.", + "filtration-mode-update": "Mise à jour du mode de filtration", + "filtration-mode-update-hint": "Action déclenchée lorsque l’utilisateur clique pour changer le mode de filtration actuel.", "filter-mode": "Filtration", "waste-mode": "Déchet", "backwash-mode": "Contre-lavage", @@ -3834,12 +3853,12 @@ "min-version": "Version minimale", "invalid-version-pattern": "Format de version invalide. Veuillez utiliser le format : majeur.mineur.correctif (ex. : 1.0.0).", "mobile-center": "Centre mobile", - "mobile-package": "Package de l'application", - "mobile-package-max-length": "Le package de l'application doit contenir moins de 256 caractères", - "mobile-package-required": "Le package de l'application est requis.", - "mobile-package-pattern": "Format du package de l'application invalide", - "mobile-package-title": "Titre de l'application", - "mobile-package-title-max-length": "Le titre de l'application doit contenir moins de 256 caractères", + "mobile-package": "Package de l’application", + "mobile-package-max-length": "Le package de l’application doit contenir moins de 256 caractères", + "mobile-package-required": "Le package de l’application est requis.", + "mobile-package-pattern": "Format du package de l’application invalide", + "mobile-package-title": "Titre de l’application", + "mobile-package-title-max-length": "Le titre de l’application doit contenir moins de 256 caractères", "no-application": "Aucune application trouvée", "no-bundles": "Aucun bundle trouvé", "platform-type": "Type de plateforme", @@ -3898,7 +3917,7 @@ "max-element-number": "Nombre maximal d'éléments", "page-name": "Nom de la page", "page-name-required": "Le nom de la page est requis.", - "page-name-cannot-contain-only-spaces": "Le nom de la page ne peut contenir uniquement des espaces.", + "page-name-cannot-contain-only-spaces": "Le nom de la page ne peut pas contenir uniquement des espaces.", "page-name-max-length": "Le nom de la page doit contenir moins de 256 caractères", "page-type": "Type de page", "pages-types": { @@ -3919,15 +3938,15 @@ "configuration-dialog": "Dialogue de configuration", "configuration-app": "Application de configuration", "configuration-step": { - "prepare-environment-title": "Préparer l'environnement de développement", - "prepare-environment-text": "L'application mobile Flutter ThingsBoard nécessite le SDK Flutter. Suivez les instructions pour configurer le SDK Flutter.", - "get-source-code-title": "Obtenir le code source de l'application", - "get-source-code-text": "Vous pouvez obtenir le code source de l'application mobile Flutter ThingsBoard en le clonant depuis le dépôt GitHub :", - "configure-app-settings-title": "Configurer les paramètres de l'application", - "configure-app-settings-text": "Téléchargez le fichier de configuration et placez-le dans le répertoire racine du projet que vous avez cloné à l'étape précédente.", + "prepare-environment-title": "Préparer l’environnement de développement", + "prepare-environment-text": "L’application mobile ThingsBoard Flutter nécessite le SDK Flutter. Suivez les instructions pour configurer le SDK Flutter.", + "get-source-code-title": "Obtenir le code source de l’application", + "get-source-code-text": "Vous pouvez obtenir le code source de l’application mobile ThingsBoard Flutter en le clonant depuis le dépôt GitHub :", + "configure-app-settings-title": "Configurer les paramètres de l’application", + "configure-app-settings-text": "Téléchargez le fichier de configuration et placez-le dans le répertoire racine du projet que vous avez cloné à l’étape précédente.", "download-file": "Télécharger le fichier", - "run-app-title": "Exécuter l'application", - "run-app-text": "Exécutez l'application comme décrit dans votre IDE.\nSi vous utilisez le terminal, exécutez l'application avec la commande suivante :", + "run-app-title": "Exécuter l’application", + "run-app-text": "Exécutez l’application comme indiqué dans votre IDE.\nSi vous utilisez le terminal, lancez l’application avec la commande suivante :", "more-information": "Des informations détaillées sont disponibles dans notre documentation de démarrage.", "getting-started": "Démarrage" } @@ -3948,13 +3967,13 @@ "alarm-comment-trigger-settings": "Paramètres du déclencheur de commentaire d'alarme", "alarm-trigger-settings": "Paramètres du déclencheur d'alarme", "all": "Tous", - "api-feature-hint": "Si le champ est vide, le déclencheur s'appliquera à toutes les fonctionnalités API", - "api-usage-trigger-settings": "Paramètres du déclencheur d'utilisation de l'API", - "new-platform-version-trigger-settings": "Paramètres du déclencheur de nouvelle version de la plateforme", - "rate-limits-trigger-settings": "Paramètres du déclencheur de dépassement de limites", - "task-processing-failure-trigger-settings": "Paramètres du déclencheur d'échec du traitement de tâche", - "resources-shortage-trigger-settings": "Paramètres de déclenchement de pénurie de ressources", - "at-least-one-should-be-selected": "Au moins un élément doit être sélectionné", + "api-feature-hint": "Si le champ est vide, le déclencheur s’appliquera à toutes les fonctionnalités API", + "api-usage-trigger-settings": "Paramètres de déclenchement d’usage de l’API", + "new-platform-version-trigger-settings": "Paramètres de déclenchement de nouvelle version de la plateforme", + "rate-limits-trigger-settings": "Paramètres de déclenchement pour dépassement des limites de débit", + "task-processing-failure-trigger-settings": "Paramètres de déclenchement pour échec de traitement de tâche", + "resources-shortage-trigger-settings": "Paramètres de déclenchement pour pénurie de ressources", + "at-least-one-should-be-selected": "Au moins une option doit être sélectionnée", "basic-settings": "Paramètres de base", "button-text": "Texte du bouton", "button-text-required": "Le texte du bouton est requis", @@ -3965,7 +3984,7 @@ "copy-notification-template": "Copier le modèle de notification", "copy-rule": "Copier la règle", "copy-template": "Copier le modèle", - "create-new": "Créer nouveau", + "create-new": "Créer", "created": "Créé", "customize-messages": "Personnaliser les messages", "cpu-threshold": "Seuil CPU", @@ -4005,17 +4024,17 @@ "mobile-app": "Application mobile", "mobile-app-preview": "Aperçu de la notification mobile" }, - "delivery-method-not-configure-click": "Méthode de livraison non configurée. Cliquez pour configurer.", - "delivery-method-not-configure-contact": "Méthode de livraison non configurée. Veuillez contacter votre administrateur système.", + "delivery-method-not-configure-click": "La méthode de livraison n'est pas configurée. Cliquez pour la configurer.", + "delivery-method-not-configure-contact": "La méthode de livraison n'est pas configurée. Contactez votre administrateur système.", "delivery-methods": "Méthodes de livraison", "description": "Description", - "device-activity-trigger-settings": "Paramètres du déclencheur d'activité du dispositif", - "device-list-rule-hint": "Si le champ est vide, le déclencheur s'appliquera à tous les dispositifs", - "device-profiles-list-rule-hint": "Si le champ est vide, le déclencheur s'appliquera à tous les profils de dispositifs", + "device-activity-trigger-settings": "Paramètres de déclenchement d'activité de l'appareil", + "device-list-rule-hint": "Si le champ est vide, le déclencheur s'appliquera à tous les appareils", + "device-profiles-list-rule-hint": "Si le champ est vide, le déclencheur s'appliquera à tous les profils d'appareil", "disabled": "Désactivé", - "edge-trigger-settings": "Paramètres du déclencheur Edge", + "edge-trigger-settings": "Paramètres de déclenchement Edge", "edge-list-rule-hint": "Si le champ est vide, le déclencheur s'appliquera à toutes les instances Edge", - "edit-notification-recipients-group": "Modifier le groupe de destinataires de notification", + "edit-notification-recipients-group": "Modifier le groupe de destinataires des notifications", "edit-notification-template": "Modifier le modèle de notification", "edit-rule": "Modifier la règle", "edit-template": "Modifier le modèle", @@ -4038,7 +4057,7 @@ "link-max-length": "Le lien doit comporter au maximum {{ length }} caractères", "link-type": { "dashboard": "Ouvrir le tableau de bord", - "link": "Ouvrir un lien URL" + "link": "Ouvrir le lien URL" }, "loading-notifications": "Chargement des notifications...", "management": "Gestion des notifications", @@ -4046,20 +4065,20 @@ "mark-as-read": "Marquer comme lu", "message": "Message", "message-required": "Le message est requis", - "message-max-length": "Le message doit contenir au maximum {{ length }} caractères", + "message-max-length": "Le message doit comporter au maximum {{ length }} caractères", "name": "Nom", "name-required": "Le nom est requis", "new-notification": "Nouvelle notification", "no-inbox-notification": "Aucune notification trouvée", "no-notification-request": "Aucune demande de notification", "no-notification-templates": "Aucun modèle de notification trouvé", - "no-notifications-yet": "Aucune notification pour l’instant", - "no-recipients-notification": "Aucun destinataire pour cette notification", + "no-notifications-yet": "Aucune notification pour le moment", + "no-recipients-notification": "Aucun destinataire de notification", "no-recipients-matching": "Aucun destinataire correspondant à '{{entity}}' trouvé.", "no-recipients-text": "Aucun destinataire trouvé", "no-rule": "Aucune règle configurée", "no-rules-notification": "Aucune règle de notification", - "no-severity-found": "Aucune sévérité trouvée", + "no-severity-found": "Aucun niveau de gravité trouvé", "no-severity-matching": "'{{severity}}' introuvable.", "no-template-matching": "Aucune ressource correspondant à '{{template}}' trouvée.", "create-new-template": "Créer un nouveau modèle !", @@ -4086,20 +4105,20 @@ "only-rule-chain-lifecycle-failures": "Uniquement les échecs de cycle de vie de chaîne de règles", "only-rule-node-lifecycle-failures": "Uniquement les échecs de cycle de vie de nœud de règles", "platform-users": "Utilisateurs de la plateforme", - "ram-threshold": "Seuil RAM", - "rate-limits": "Limites de taux", - "rate-limits-hint": "Si le champ est vide, le déclencheur s’appliquera à toutes les limites de taux", + "ram-threshold": "Seuil de RAM", + "rate-limits": "Limites de débit", + "rate-limits-hint": "Si le champ est vide, le déclencheur s'appliquera à toutes les limites de débit", "recipient": "Destinataire", "recipient-group": "Groupe de destinataires", "recipient-type": { - "affected-tenant-administrators": "Administrateurs du locataire concerné", + "affected-tenant-administrators": "Administrateurs de locataires concernés", "affected-user": "Utilisateur concerné", "all-users": "Tous les utilisateurs", - "customer-users": "Utilisateurs client", + "customer-users": "Utilisateurs du client", "system-administrators": "Administrateurs système", - "tenant-administrators": "Administrateurs du locataire", - "user-filters": "Filtre d'utilisateur", - "user-list": "Liste d’utilisateurs", + "tenant-administrators": "Administrateurs de locataires", + "user-filters": "Filtre utilisateur", + "user-list": "Liste des utilisateurs", "users-entity-owner": "Utilisateurs du propriétaire de l'entité" }, "recipients": "Destinataires", @@ -4149,20 +4168,20 @@ "private-channel": "Canal privé", "public-channel": "Canal public" }, - "start-from-scratch": "Commencer de zéro", + "start-from-scratch": "Repartir de zéro", "status": "Statut", "stop-escalation-alarm-status-become": "Arrêter l'escalade lorsque le statut de l'alarme devient :", "storage-threshold": "Seuil de stockage", - "subject": "Sujet", - "subject-required": "Le sujet est requis", - "subject-max-length": "Le sujet doit contenir au maximum {{ length }} caractères", + "subject": "Objet", + "subject-required": "L'objet est requis", + "subject-max-length": "L'objet doit comporter au maximum {{ length }} caractères", "template": "Modèle", "template-name": "Nom du modèle", "template-required": "Le modèle est requis", "template-type": { "alarm": "Alarme", "alarm-assignment": "Attribution d'alarme", - "alarm-comment": "Commentaire d'alarme", + "alarm-comment": "Commentaire sur l'alarme", "api-usage-limit": "Limite d'utilisation de l'API", "device-activity": "Activité de l'appareil", "entities-limit": "Limite d'entités", @@ -4171,10 +4190,10 @@ "rule-engine-lifecycle-event": "Événement du cycle de vie du moteur de règles", "rule-node": "Nœud de règle", "new-platform-version": "Nouvelle version de la plateforme", - "rate-limits": "Limites de débit dépassées", - "edge-communication-failure": "Échec de communication Edge", + "rate-limits": "Limites dépassées", + "edge-communication-failure": "Échec de communication avec l'Edge", "edge-connection": "Connexion Edge", - "task-processing-failure": "Échec du traitement de la tâche", + "task-processing-failure": "Échec du traitement de tâche", "resources-shortage": "Pénurie de ressources" }, "templates": "Modèles", @@ -4188,17 +4207,17 @@ "trigger": { "alarm": "Alarme", "alarm-assignment": "Attribution d'alarme", - "alarm-comment": "Commentaire d'alarme", + "alarm-comment": "Commentaire sur l'alarme", "api-usage-limit": "Limite d'utilisation de l'API", "device-activity": "Activité de l'appareil", "entities-limit": "Limite d'entités", "entity-action": "Action sur l'entité", "rule-engine-lifecycle-event": "Événement du cycle de vie du moteur de règles", "new-platform-version": "Nouvelle version de la plateforme", - "rate-limits": "Limites de débit dépassées", + "rate-limits": "Limites dépassées", "edge-connection": "Connexion Edge", - "edge-communication-failure": "Échec de communication Edge", - "task-processing-failure": "Échec du traitement de la tâche", + "edge-communication-failure": "Échec de communication avec l'Edge", + "task-processing-failure": "Échec du traitement de tâche", "resources-shortage": "Pénurie de ressources", "trigger": "Déclencheur", "trigger-required": "Le déclencheur est requis" @@ -4229,21 +4248,21 @@ } }, "ota-update": { - "add": "Ajouter un paquet", - "assign-firmware": "Micrologiciel assigné", - "assign-firmware-required": "Le micrologiciel assigné est requis", + "add": "Ajouter un package", + "assign-firmware": "Microprogramme assigné", + "assign-firmware-required": "Le microprogramme assigné est requis", "assign-software": "Logiciel assigné", "assign-software-required": "Le logiciel assigné est requis", - "auto-generate-checksum": "Générer automatiquement la somme de contrôle", - "checksum": "Somme de contrôle", - "checksum-hint": "Si la somme de contrôle est vide, elle sera générée automatiquement", - "checksum-algorithm": "Algorithme de somme de contrôle", - "checksum-copied-message": "La somme de contrôle du paquet a été copiée dans le presse-papiers", - "change-firmware": "Changer le micrologiciel peut entraîner la mise à jour de { count, plural, =1 {1 appareil} other {# appareils} }.", - "change-software": "Changer le logiciel peut entraîner la mise à jour de { count, plural, =1 {1 appareil} other {# appareils} }.", + "auto-generate-checksum": "Générer automatiquement le checksum", + "checksum": "Checksum", + "checksum-hint": "Si le checksum est vide, il sera généré automatiquement", + "checksum-algorithm": "Algorithme de checksum", + "checksum-copied-message": "Le checksum du package a été copié dans le presse-papiers", + "change-firmware": "La modification du microprogramme peut entraîner la mise à jour de { count, plural, =1 {1 appareil} other {# appareils} }.", + "change-software": "La modification du logiciel peut entraîner la mise à jour de { count, plural, =1 {1 appareil} other {# appareils} }.", "change-ota-setting-title": "Êtes-vous sûr de vouloir modifier les paramètres OTA ?", - "chose-compatible-device-profile": "Le paquet téléchargé ne sera disponible que pour les appareils ayant le profil choisi.", - "chose-firmware-distributed-device": "Choisissez le micrologiciel à distribuer aux appareils", + "chose-compatible-device-profile": "Le package importé sera disponible uniquement pour les appareils ayant le profil sélectionné.", + "chose-firmware-distributed-device": "Choisissez le microprogramme à distribuer aux appareils", "chose-software-distributed-device": "Choisissez le logiciel à distribuer aux appareils", "content-type": "Type de contenu", "copy-checksum": "Copier la somme de contrôle", @@ -4308,9 +4327,9 @@ "current-password": "Mot de passe actuel", "copy-jwt-token": "Copier le jeton JWT", "jwt-token": "Jeton JWT", - "token-valid-till": "Jeton valide jusqu'à", + "token-valid-till": "Le jeton est valide jusqu'au", "tokenCopiedSuccessMessage": "Le jeton JWT a été copié dans le presse-papiers", - "tokenCopiedWarnMessage": "Le jeton JWT est expiré ! Veuillez actualiser la page." + "tokenCopiedWarnMessage": "Le jeton JWT est expiré ! Veuillez rafraîchir la page." }, "profiles": { "profiles": "Profils" @@ -4334,34 +4353,34 @@ "get-new-code": "Obtenir un nouveau code", "main-2fa-method": "Utiliser comme méthode principale d'authentification à deux facteurs", "dialog": { - "activation-step-description-email": "Lors de votre prochaine connexion, un code de sécurité sera envoyé à votre adresse email.", - "activation-step-description-sms": "Lors de votre prochaine connexion, un code de sécurité sera envoyé au numéro de téléphone.", + "activation-step-description-email": "Lors de votre prochaine connexion, un code de sécurité vous sera demandé. Il sera envoyé à votre adresse e-mail.", + "activation-step-description-sms": "Lors de votre prochaine connexion, un code de sécurité vous sera demandé. Il sera envoyé à votre numéro de téléphone.", "activation-step-description-totp": "Lors de votre prochaine connexion, vous devrez fournir un code d'authentification à deux facteurs.", "activation-step-label": "Activation", - "backup-code-description": "Imprimez ces codes pour les avoir à portée de main lorsque vous devrez vous connecter. Chaque code peut être utilisé une seule fois.", - "backup-code-warn": "Une fois que vous quittez cette page, ces codes ne pourront plus être affichés. Conservez-les en toute sécurité à l'aide des options ci-dessous.", + "backup-code-description": "Imprimez ces codes afin de les avoir à portée de main lorsque vous devrez vous connecter à votre compte. Chaque code de secours ne peut être utilisé qu'une seule fois.", + "backup-code-warn": "Une fois cette page quittée, ces codes ne pourront plus être affichés. Conservez-les en toute sécurité en utilisant les options ci-dessous.", "download-txt": "Télécharger (txt)", - "email-step-description": "Saisissez une adresse email à utiliser comme méthode d'authentification.", - "email-step-label": "Email", - "enable-email-title": "Activer l'authentification par email", - "enable-sms-title": "Activer l'authentification par SMS", - "enable-totp-title": "Activer l'application d'authentification", - "enter-verification-code": "Entrez le code à 6 chiffres ici", + "email-step-description": "Saisissez une adresse e-mail à utiliser comme méthode d’authentification.", + "email-step-label": "E-mail", + "enable-email-title": "Activer l’authentification par e-mail", + "enable-sms-title": "Activer l’authentification par SMS", + "enable-totp-title": "Activer l’application d’authentification", + "enter-verification-code": "Saisissez le code à 6 chiffres ici", "get-backup-code-title": "Obtenir le code de secours", "next": "Suivant", - "scan-qr-code": "Scannez ce code QR avec votre application d'authentification", + "scan-qr-code": "Scannez ce QR code avec votre application d’authentification", "send-code": "Envoyer le code", - "sms-step-description": "Saisissez un numéro de téléphone à utiliser comme méthode d'authentification.", + "sms-step-description": "Saisissez un numéro de téléphone à utiliser comme méthode d’authentification.", "sms-step-label": "Numéro de téléphone", "success": "Succès !", "totp-step-description-install": "Vous pouvez installer des applications comme Google Authenticator, Authy ou Duo.", - "totp-step-description-open": "Ouvrez l'application d'authentification sur votre téléphone mobile.", - "totp-step-label": "Obtenir l'application", + "totp-step-description-open": "Ouvrez l’application d’authentification sur votre téléphone mobile.", + "totp-step-label": "Obtenir l’application", "verification-code": "Code à 6 chiffres", "verification-code-invalid": "Format de code de vérification invalide", "verification-code-incorrect": "Code de vérification incorrect", - "verification-code-many-request": "Trop de requêtes. Vérifiez le code de vérification", - "verification-step-description": "Entrez un code à 6 chiffres que nous venons d'envoyer à {{address}}", + "verification-code-many-request": "Trop de demandes – vérifiez le code", + "verification-step-description": "Saisissez le code à 6 chiffres que nous venons d’envoyer à {{address}}", "verification-step-label": "Vérification" }, "provider": { @@ -4438,8 +4457,8 @@ "any-relation": "Toute relation", "relation-filters": "Filtres de relation", "relation-filter": "Filtre de relation", - "additional-info": "Infos supplémentaires (JSON)", - "invalid-additional-info": "Impossible d'analyser le JSON des infos supplémentaires.", + "additional-info": "Informations supplémentaires (JSON)", + "invalid-additional-info": "Impossible d’analyser le JSON des informations supplémentaires.", "no-relations-text": "Aucune relation trouvée", "not": "Non" }, @@ -4448,20 +4467,20 @@ "all-types": "Tous", "copyId": "Copier l'identifiant de la ressource", "delete": "Supprimer la ressource", - "delete-resource-text": "Attention, après confirmation, la ressource ne pourra pas être récupérée.", + "delete-resource-text": "Attention, après confirmation, la ressource sera irrécupérable.", "delete-resource-title": "Êtes-vous sûr de vouloir supprimer la ressource '{{resourceTitle}}' ?", "delete-resources-action-title": "Supprimer { count, plural, =1 {1 ressource} other {# ressources} }", - "delete-resources-text": "Veuillez noter que les ressources sélectionnées, même si elles sont utilisées dans les profils de périphériques, seront supprimées.", + "delete-resources-text": "Veuillez noter que les ressources sélectionnées, même si elles sont utilisées dans les profils d'appareil, seront supprimées.", "delete-resources-title": "Êtes-vous sûr de vouloir supprimer { count, plural, =1 {1 ressource} other {# ressources} } ?", "download": "Télécharger la ressource", - "drop-file": "Déposez un fichier ressource ou cliquez pour en sélectionner un à télécharger.", - "drop-resource-file-or": "Glissez et déposez un fichier ressource ou", - "empty": "Ressource vide", + "drop-file": "Déposez un fichier ressource ou cliquez pour en sélectionner un à téléverser.", + "drop-resource-file-or": "Glissez-déposez un fichier ressource ou", + "empty": "La ressource est vide", "file-name": "Nom du fichier", "idCopiedMessage": "L'identifiant de la ressource a été copié dans le presse-papiers", - "no-resource-matching": "Aucune ressource correspondant à '{{widgetsBundle}}' n'a été trouvée.", + "no-resource-matching": "Aucune ressource correspondant à '{{widgetsBundle}}' n’a été trouvée.", "no-resource-text": "Aucune ressource trouvée", - "open-widgets-bundle": "Ouvrir la collection de widgets", + "open-widgets-bundle": "Ouvrir le bundle de widgets", "resource": "Ressource", "resource-file": "Fichier ressource", "resource-files": "Fichiers ressource", @@ -4478,15 +4497,21 @@ "jks": "JKS", "js-module": "Module JS", "lwm2m-model": "Modèle LWM2M", - "pkcs-12": "PKCS #12" + "pkcs-12": "PKCS #12", + "general": "Général" }, "resource-sub-type": "Sous-type", "sub-type": { - "image": "Image", + "image": "image", "scada-symbol": "Symbole SCADA", "extension": "Extension", "module": "Module" - } + }, + "resource-is-in-use": "La ressource est utilisée par d'autres entités", + "resources-are-in-use": "Les ressources sont utilisées par d'autres entités", + "resource-is-in-use-text": "La ressource '{{title}}' n'a pas été supprimée car elle est utilisée par les entités suivantes :", + "resources-are-in-use-text": "Toutes les ressources n'ont pas été supprimées car elles sont utilisées par d'autres entités.
Vous pouvez consulter les entités référencées en cliquant sur le bouton Références dans la ligne correspondante.
Si vous souhaitez tout de même supprimer ces ressources, sélectionnez-les dans le tableau ci-dessous et cliquez sur le bouton Supprimer la sélection.", + "delete-resource-in-use-text": "Si vous souhaitez tout de même supprimer la ressource, cliquez sur le bouton Supprimer quand même." }, "javascript": { "add": "Ajouter une ressource JavaScript", @@ -4517,9 +4542,9 @@ }, "rpc": { "error": { - "target-device-is-not-set": "Le périphérique cible n'est pas défini !", + "target-device-is-not-set": "L'appareil cible n'est pas défini !", "invalid-target-entity": "Les commandes RPC ne sont pas prises en charge par l'entité {{entityType}}.", - "failed-to-resolve-target-device": "Échec de résolution du périphérique cible !", + "failed-to-resolve-target-device": "Échec de résolution de l’appareil cible !", "request-timeout": "Délai d'attente de la requête dépassé", "rpc-http-error": "Erreur : {{status}} - {{statusText}}" } @@ -4668,9 +4693,9 @@ "advanced-settings": "Paramètres avancés", "create-entity-if-not-exists": "Créer une entité si elle n'existe pas", "create-entity-if-not-exists-hint": "Si activé, une nouvelle entité avec les paramètres spécifiés sera créée à moins qu'elle n'existe déjà. Les entités existantes seront utilisées telles quelles pour la relation.", - "select-device-connectivity-event": "Sélectionner un événement de connectivité du dispositif", + "select-device-connectivity-event": "Sélectionner un événement de connectivité de l’appareil", "entity-name-pattern": "Modèle de nom", - "device-name-pattern": "Nom du dispositif", + "device-name-pattern": "Nom de l’appareil", "asset-name-pattern": "Nom de l'actif", "entity-view-name-pattern": "Nom de la vue d'entité", "customer-title-pattern": "Titre du client", @@ -4736,7 +4761,7 @@ "attributes-scope-value": "Valeur de la portée des attributs", "attributes-scope-value-copy": "Copier la valeur de portée des attributs", "attributes-scope-hint": "Utilisez la clé de métadonnée 'scope' pour définir dynamiquement la portée par message. Cela remplace la portée définie dans la configuration.", - "notify-device": "Forcer la notification au dispositif", + "notify-device": "Forcer la notification à l’appareil", "send-attributes-updated-notification": "Envoyer une notification d’attributs mis à jour", "send-attributes-updated-notification-hint": "Envoyer une notification sur les attributs mis à jour comme message séparé à la file du moteur de règles.", "send-attributes-deleted-notification": "Envoyer une notification d’attributs supprimés", @@ -4745,8 +4770,8 @@ "update-attributes-only-on-value-change-hint": "Met à jour les attributs à chaque message entrant, même si leur valeur n’a pas changé. Cela augmente l’usage de l’API et réduit les performances.", "update-attributes-only-on-value-change-hint-enabled": "Met à jour les attributs uniquement si leur valeur a changé. Si aucune modification, aucune mise à jour ni notification ne sera envoyée.", "fetch-credentials-to-metadata": "Transférer les identifiants dans les métadonnées", - "notify-device-on-update-hint": "Si activé, force la notification au dispositif lors de la mise à jour des attributs partagés. Sinon, contrôlé via le paramètre 'notifyDevice' dans les métadonnées du message.", - "notify-device-on-delete-hint": "Si activé, force la notification au dispositif lors de la suppression des attributs partagés. Sinon, contrôlé via 'notifyDevice' dans les métadonnées du message.", + "notify-device-on-update-hint": "Si activé, force la notification à l’appareil lors de la mise à jour des attributs partagés. Sinon, contrôlé via le paramètre 'notifyDevice' dans les métadonnées du message.", + "notify-device-on-delete-hint": "Si activé, force la notification à l’appareil lors de la suppression des attributs partagés. Sinon, contrôlé via 'notifyDevice' dans les métadonnées du message.", "latest-timeseries": "Clés de données de séries temporelles récentes", "timeseries-keys": "Clés de séries temporelles", "timeseries-keys-required": "Au moins une clé de série temporelle doit être sélectionnée.", @@ -4799,7 +4824,7 @@ "json-path-expression-required": "L'expression JSONPath est requise", "json-path-expression-hint": "JSONPath indique un chemin vers un ou plusieurs éléments dans une structure JSON. '$' représente la racine.", "relations-query": "Requête sur les relations", - "device-relations-query": "Requête sur les relations du dispositif", + "device-relations-query": "Requête sur les relations de l’appareil", "max-relation-level": "Niveau de relation max.", "max-relation-level-error": "La valeur doit être supérieure à 0 ou non définie.", "max-relation-level-invalid": "La valeur doit être un entier.", @@ -4932,23 +4957,23 @@ "use-simple-client-http-factory": "Utiliser une fabrique HTTP client simple", "ignore-request-body": "Sans corps de requête", "parse-to-plain-text": "Analyser en texte brut", - "parse-to-plain-text-hint": "Si sélectionné, le corps du message sera converti de chaîne JSON en texte brut, par exemple msg = \"Hello,\\t\"world\"\" devient Hello, \"world\"", - "read-timeout": "Délai de lecture (ms)", - "read-timeout-hint": "Une valeur de 0 signifie un délai d'expiration infini", - "max-parallel-requests-count": "Nombre maximal de requêtes parallèles", - "max-parallel-requests-count-hint": "Une valeur de 0 signifie qu'il n'y a pas de limite de traitement parallèle", - "max-response-size": "Taille maximale de réponse (en Ko)", - "max-response-size-hint": "Quantité maximale de mémoire utilisée pour le tampon lors du décodage/encodage des messages HTTP comme les charges JSON ou XML", + "parse-to-plain-text-hint": "Si sélectionné, le corps du message de la requête sera transformé d'une chaîne JSON en texte brut, par exemple : msg = \"Hello,\\t\"world\"\" sera analysé comme Hello, \"world\"", + "read-timeout": "Délai de lecture en millisecondes", + "read-timeout-hint": "La valeur 0 signifie un délai illimité", + "max-parallel-requests-count": "Nombre max. de requêtes parallèles", + "max-parallel-requests-count-hint": "La valeur 0 indique qu'il n'y a pas de limite au traitement parallèle", + "max-response-size": "Taille max. de la réponse (en Ko)", + "max-response-size-hint": "Quantité maximale de mémoire allouée pour le tampon de données lors du décodage ou de l'encodage des messages HTTP, tels que les charges utiles JSON ou XML", "headers": "En-têtes", - "headers-hint": "Utilisez ${metadataKey} pour une valeur provenant des métadonnées, $[messageKey] pour une valeur provenant du corps du message dans les champs en-tête/valeur", + "headers-hint": "Utilisez ${metadataKey} pour une valeur issue des métadonnées, $[messageKey] pour une valeur issue du corps du message dans les champs en-tête/valeur", "header": "En-tête", - "header-required": "L'en-tête est requis", + "header-required": "L’en-tête est requis", "value": "Valeur", "value-required": "La valeur est requise", - "topic-pattern": "Motif de sujet", - "key-pattern": "Motif de clé", - "key-pattern-hint": "Facultatif. Si une partition est précisée, elle sera utilisée. Sinon, la clé est utilisée. Sans clé, un round-robin sera appliqué.", - "topic-pattern-required": "Le motif de sujet est requis", + "topic-pattern": "Modèle de sujet", + "key-pattern": "Modèle de clé", + "key-pattern-hint": "Optionnel. Si un numéro de partition valide est spécifié, il sera utilisé lors de l'envoi de l'enregistrement. Si aucune partition n'est spécifiée, la clé sera utilisée. Sinon, une partition sera assignée en mode round-robin.", + "topic-pattern-required": "Le modèle de sujet est requis", "topic": "Sujet", "topic-required": "Le sujet est requis", "bootstrap-servers": "Serveurs bootstrap", @@ -5008,16 +5033,16 @@ "pubsub-topic-name": "Nom du sujet", "pubsub-topic-name-required": "Le nom du sujet est requis", "message-attributes": "Attributs du message", - "message-attributes-hint": "Utilisez ${metadataKey} pour une valeur provenant des métadonnées, $[messageKey] pour une valeur provenant du corps du message dans les champs nom/valeur", - "connect-timeout": "Délai de connexion (s)", + "message-attributes-hint": "Utilisez ${metadataKey} pour une valeur issue des métadonnées, $[messageKey] pour une valeur issue du corps du message dans les champs nom/valeur", + "connect-timeout": "Délai de connexion (sec)", "connect-timeout-required": "Le délai de connexion est requis.", "connect-timeout-range": "Le délai de connexion doit être compris entre 1 et 200.", "client-id": "ID client", - "client-id-hint": "Optionnel. Laissez vide pour un ID client généré automatiquement. Si vous utilisez un ID explicite, veillez à ce qu'il soit unique, surtout en mode micro-services.", - "append-client-id-suffix": "Ajouter l'ID du service comme suffixe à l'ID client", - "client-id-suffix-hint": "Optionnel. Appliqué si un ID client est défini. Ajoute l'ID de service comme suffixe pour éviter les conflits en mode micro-services.", - "device-id": "ID de l'appareil", - "device-id-required": "L'ID de l'appareil est requis.", + "client-id-hint": "Optionnel. Laissez vide pour générer automatiquement un ID client. Attention : la plupart des brokers MQTT n’autorisent pas plusieurs connexions avec le même ID client. Pour se connecter à de tels brokers, votre ID client MQTT doit être unique. Si la plateforme fonctionne en mode microservices, une copie du nœud de règle est lancée dans chaque microservice. Cela entraînera automatiquement plusieurs clients MQTT avec le même ID, ce qui peut provoquer des échecs du nœud de règle. Pour éviter ces échecs, activez l’option \"Ajouter l’ID de service comme suffixe à l’ID client\" ci-dessous.", + "append-client-id-suffix": "Ajouter l’ID de service comme suffixe à l’ID client", + "client-id-suffix-hint": "Optionnel. Appliqué lorsque \"Client ID\" est spécifié explicitement. Si sélectionné, l'ID du service sera ajouté en suffixe à l'ID client. Permet d'éviter les défaillances lorsque la plateforme fonctionne en mode microservices.", + "device-id": "ID de l’appareil", + "device-id-required": "L’ID de l’appareil est requis.", "clean-session": "Session propre", "enable-ssl": "Activer SSL", "credentials": "Identifiants", @@ -5026,8 +5051,8 @@ "credentials-anonymous": "Anonyme", "credentials-basic": "Basique", "credentials-pem": "PEM", - "credentials-pem-hint": "Au moins un fichier de certificat CA serveur ou une paire certificat client + clé privée client est requis", - "credentials-sas": "Signature d'accès partagé", + "credentials-pem-hint": "Au minimum, un fichier de certificat CA serveur ou une paire de fichiers de certificat client et de clé privée client sont requis", + "credentials-sas": "Signature d'accès partagé (SAS)", "sas-key": "Clé SAS", "sas-key-required": "La clé SAS est requise.", "hostname": "Nom d'hôte", @@ -5041,25 +5066,25 @@ "no-file": "Aucun fichier sélectionné.", "drop-file": "Déposez un fichier ou cliquez pour en sélectionner un à téléverser.", "private-key-password": "Mot de passe de la clé privée", - "use-system-smtp-settings": "Utiliser les paramètres SMTP système", + "use-system-smtp-settings": "Utiliser les paramètres SMTP du système", "use-metadata-dynamic-interval": "Utiliser un intervalle dynamique", - "metadata-dynamic-interval-hint": "Les champs de début et fin d’intervalle supportent la templatization. Valeurs en millisecondes. Utilisez $[messageKey] ou ${metadataKey}.", - "use-metadata-interval-patterns-hint": "Si sélectionné, le nœud utilise les motifs d’intervalle de début/fin du message ou des métadonnées en millisecondes.", + "metadata-dynamic-interval-hint": "Les champs de saisie de début et de fin d'intervalle prennent en charge la templatisation. Notez que la valeur du modèle substitué doit être définie en millisecondes. Utilisez $[messageKey] pour extraire la valeur du message et ${metadataKey} pour extraire la valeur des métadonnées.", + "use-metadata-interval-patterns-hint": "Si sélectionné, le nœud de règle utilise les modèles d'intervalle de début et de fin provenant des métadonnées ou des données du message, en supposant que les intervalles sont en millisecondes.", "use-message-alarm-data": "Utiliser les données d'alarme du message", "overwrite-alarm-details": "Écraser les détails de l'alarme", - "use-alarm-severity-pattern": "Utiliser un motif de sévérité d'alarme", - "check-all-keys": "Vérifier que tous les champs sont présents", - "check-all-keys-hint": "Vérifie la présence de toutes les clés spécifiées dans les données et les métadonnées.", + "use-alarm-severity-pattern": "Utiliser le modèle de gravité de l'alarme", + "check-all-keys": "Vérifier que tous les champs spécifiés sont présents", + "check-all-keys-hint": "Si sélectionné, vérifie que toutes les clés spécifiées sont présentes dans les données et métadonnées du message.", "check-relation-to-specific-entity": "Vérifier la relation avec une entité spécifique", - "check-relation-to-specific-entity-tooltip": "Si activé, vérifie la relation avec une entité spécifique, sinon avec n'importe quelle entité selon direction/type.", - "check-relation-hint": "Vérifie la relation avec une entité (spécifique ou non) selon direction/type.", + "check-relation-to-specific-entity-tooltip": "Si activé, vérifie la présence d'une relation avec une entité spécifique, sinon, vérifie la relation avec n'importe quelle entité. Dans les deux cas, la recherche de relation est basée sur la direction et le type configurés.", + "check-relation-hint": "Vérifie l'existence d'une relation avec une entité spécifique ou avec n'importe quelle entité selon la direction et le type de relation.", "delete-relation-with-specific-entity": "Supprimer la relation avec une entité spécifique", - "delete-relation-with-specific-entity-hint": "Supprime uniquement la relation avec une entité spécifique. Sinon, supprime toutes les relations correspondantes.", - "delete-relation-hint": "Supprime la relation de l'origine du message vers une ou plusieurs entités selon direction/type.", + "delete-relation-with-specific-entity-hint": "Si activé, supprimera uniquement la relation avec une entité spécifique. Sinon, la relation sera supprimée avec toutes les entités correspondantes.", + "delete-relation-hint": "Supprime la relation de l'initiateur du message entrant vers l'entité ou la liste d'entités spécifiées selon la direction et le type.", "remove-current-relations": "Supprimer les relations actuelles", - "remove-current-relations-hint": "Supprime les relations actuelles de l'origine du message selon direction/type.", - "change-originator-to-related-entity": "Changer l'origine en une entité liée", - "change-originator-to-related-entity-hint": "Permet de traiter un message comme venant d'une autre entité.", + "remove-current-relations-hint": "Supprime les relations actuelles de l'initiateur du message entrant en fonction de la direction et du type.", + "change-originator-to-related-entity": "Changer l'initiateur en entité liée", + "change-originator-to-related-entity-hint": "Utilisé pour traiter le message soumis comme s'il provenait d'une autre entité.", "start-interval": "Début de l'intervalle", "end-interval": "Fin de l'intervalle", "start-interval-required": "Le début de l'intervalle est requis.", @@ -5119,15 +5144,15 @@ "email-sender": "Expéditeur de l'email", "fields-to-check": "Champs à vérifier", "add-detail": "Ajouter un détail", - "check-all-keys-tooltip": "Si activé, vérifie la présence de tous les champs listés dans les données et métadonnées du message entrant.", - "fields-to-check-hint": "Appuyez sur \"Entrée\" pour valider la saisie. Champs multiples supportés.", + "check-all-keys-tooltip": "Si activé, vérifie la présence de tous les champs répertoriés dans les noms de champs du message et des métadonnées dans le message entrant et ses métadonnées.", + "fields-to-check-hint": "Appuyez sur \"Entrée\" pour compléter la saisie du nom du champ. Plusieurs noms de champs sont supportés.", "entity-details-list-empty": "Au moins un détail doit être sélectionné.", - "alarm-status": "Statut d'alarme", + "alarm-status": "Statut de l'alarme", "alarm-required": "Au moins un statut d'alarme doit être sélectionné.", "no-entity-details-matching": "Aucun détail d'entité correspondant trouvé.", - "custom-table-name": "Nom de table personnalisé", + "custom-table-name": "Nom de la table personnalisée", "custom-table-name-required": "Le nom de la table est requis", - "custom-table-hint": "La table doit être créée dans votre cluster Cassandra et commencer par 'cs_tb_'. Entrez ici le nom sans le préfixe.", + "custom-table-hint": "La table doit être créée dans votre cluster Cassandra et son nom doit commencer par le préfixe 'cs_tb_' pour éviter l'insertion de données dans les tables communes de TB. Entrez ici le nom de la table sans le préfixe 'cs_tb_'.", "message-field": "Champ du message", "message-field-required": "Le champ du message est requis.", "table-col": "Colonne de la table", @@ -5136,8 +5161,8 @@ "longitude-field-name": "Nom du champ de longitude", "latitude-field-name-required": "Le nom du champ de latitude est requis.", "longitude-field-name-required": "Le nom du champ de longitude est requis.", - "fetch-perimeter-info-from-metadata": "Extraire les infos de périmètre depuis les métadonnées", - "fetch-perimeter-info-from-metadata-tooltip": "Si le type de périmètre est 'Polygone', la valeur du champ '{{perimeterKeyName}}' est utilisée telle quelle. Pour 'Cercle', elle est analysée pour extraire latitude, longitude, rayon et unité.", + "fetch-perimeter-info-from-metadata": "Récupérer les informations de périmètre à partir des métadonnées", + "fetch-perimeter-info-from-metadata-tooltip": "Si le type de périmètre est défini sur 'Polygon', la valeur du champ de métadonnées '{{perimeterKeyName}}' sera utilisée comme définition du périmètre sans analyse supplémentaire de la valeur. Sinon, si le type de périmètre est défini sur 'Circle', la valeur du champ de métadonnées '{{perimeterKeyName}}' sera analysée pour extraire les champs 'latitude', 'longitude', 'radius', 'radiusUnit' qui sont utilisés pour la définition du périmètre circulaire.", "perimeter-key-name": "Nom de clé de périmètre", "perimeter-key-name-hint": "Nom du champ de métadonnées contenant les infos de périmètre.", "perimeter-key-name-required": "Le nom de la clé de périmètre est requis.", @@ -5169,7 +5194,7 @@ "tell-failure-if-absent": "Indiquer un échec", "tell-failure-if-absent-hint": "Si au moins une clé sélectionnée est absente, le message sortant signalera une \"Échec\".", "get-latest-value-with-ts": "Récupérer l’horodatage des dernières valeurs", - "get-latest-value-with-ts-hint": "Inclura l'horodatage dans les valeurs télémétriques, ex : \"temp\": {\"ts\":1574329385897, \"value\":42}", + "get-latest-value-with-ts-hint": "Inclura l'horodatage dans les valeurs télémétriques, ex : \"temp\": \"{\"ts\":1574329385897, \"value\":42}\"", "ignore-null-strings": "Ignorer les chaînes nulles", "ignore-null-strings-hint": "Ignore les champs avec valeur vide.", "add-metadata-key-values-as-kafka-headers": "Ajouter les métadonnées comme en-têtes Kafka", @@ -5197,18 +5222,18 @@ "failure-if-delta-negative": "Signaler un échec si le delta est négatif", "failure-if-delta-negative-tooltip": "Force l’échec du traitement si la valeur delta est négative.", "use-caching": "Utiliser le cache", - "use-caching-tooltip": "Met en cache la valeur de \"{{inputValueKey}}\" depuis le message entrant pour améliorer la performance. Le cache ne sera pas mis à jour si la valeur est modifiée ailleurs.", + "use-caching-tooltip": "Le nœud de règle mettra en cache la valeur de \"{{inputValueKey}}\" qui arrive du message entrant pour améliorer les performances. Notez que le cache ne sera pas mis à jour si vous modifiez la valeur de \"{{inputValueKey}}\" ailleurs.", "add-time-difference-between-readings": "Ajouter la différence de temps entre les lectures de \"{{inputValueKey}}\"", - "add-time-difference-between-readings-tooltip": "Ajoute la clé \"{{periodValueKey}}\" au message sortant si activé.", - "period-value-key": "Clé de la période", - "period-value-key-required": "La clé de la période est requise.", - "general-pattern-hint": "Utilisez ${metadataKey} pour les métadonnées, $[messageKey] pour le corps du message.", - "alarm-severity-pattern-hint": "Utilisez ${metadataKey} pour une valeur provenant des métadonnées, $[messageKey] pour une valeur provenant du corps du message. La gravité de l'alarme doit être un niveau système (CRITICAL, MAJOR, etc.)", - "output-node-name-hint": "Le nom du nœud correspond au type de relation du message de sortie.", - "use-server-ts": "Utiliser l’horodatage serveur", - "use-server-ts-hint": "Utilise le temps actuel du serveur pour les séries temporelles sans horodatage explicite.", - "kv-map-pattern-hint": "Tous les champs d’entrée supportent la templatization.", - "kv-map-single-pattern-hint": "Le champ d’entrée supporte la templatization.", + "add-time-difference-between-readings-tooltip": "Si activé, le nœud de règle ajoutera le \"{{periodValueKey}}\" au message sortant.", + "period-value-key": "Clé de la valeur de la période", + "period-value-key-required": "La clé de la valeur de la période est requise.", + "general-pattern-hint": "Utilisez ${metadataKey} pour la valeur provenant des métadonnées, $[messageKey] pour la valeur provenant du corps du message.", + "alarm-severity-pattern-hint": "Utilisez ${metadataKey} pour la valeur provenant des métadonnées, $[messageKey] pour la valeur provenant du corps du message. La gravité de l'alarme doit être du système (CRITICAL, MAJOR, etc.).", + "output-node-name-hint": "Le nom du nœud de règle correspond au type de relation du message sortant, et il est utilisé pour transmettre les messages à d'autres nœuds de règle dans la chaîne de règles appelante.", + "use-server-ts": "Utiliser le timestamp du serveur", + "use-server-ts-hint": "Utilisez le timestamp actuel du serveur pour les données de séries temporelles qui n'ont pas de timestamp explicite. Cela permet de maintenir un ordre correct lors du traitement des messages provenant de plusieurs sources ou lorsque les messages arrivent dans un ordre incorrect.", + "kv-map-pattern-hint": "Tous les champs d'entrée prennent en charge la templatisation. Utilisez $[messageKey] pour extraire la valeur du message et ${metadataKey} pour extraire la valeur des métadonnées.", + "kv-map-single-pattern-hint": "Le champ d'entrée prend en charge la templatisation. Utilisez $[messageKey] pour extraire la valeur du message et ${metadataKey} pour extraire la valeur des métadonnées.", "shared-scope": "Portée partagée", "server-scope": "Portée serveur", "client-scope": "Portée client", @@ -5244,7 +5269,7 @@ "type-field-input-required": "Le type est requis.", "key-field-input": "Clé", "add-entity-type": "Ajouter un type d'entité", - "add-device-profile": "Ajouter un profil de périphérique", + "add-device-profile": "Ajouter un profil d'appareil", "key-field-input-required": "La clé est requise.", "number-floating-point-field-input": "Nombre de chiffres après la virgule", "number-floating-point-field-input-hint": "Utilisez 0 pour convertir en entier", @@ -5270,20 +5295,20 @@ "presence-monitoring-strategy": "Stratégie de suivi de présence", "presence-monitoring-strategy-on-first-message": "Au premier message", "presence-monitoring-strategy-on-each-message": "À chaque message", - "presence-monitoring-strategy-on-first-message-hint": "Signale 'Inside' ou 'Outside' au premier message après une durée minimale depuis la dernière mise à jour.", - "presence-monitoring-strategy-on-each-message-hint": "Signale 'Inside' ou 'Outside' à chaque message après une mise à jour.", - "fetch-credentials-to": "Extraire les identifiants vers", - "add-originator-attributes-to": "Ajouter les attributs de l’origine à", - "originator-attributes": "Attributs de l’origine", - "fetch-latest-telemetry-with-timestamp": "Extraire la dernière télémétrie avec horodatage", - "fetch-latest-telemetry-with-timestamp-tooltip": "Ajoute l'horodatage dans les métadonnées, ex: \"{{latestTsKeyName}}\": \"{\"ts\":1574329385897, \"value\":42}\"", - "tell-failure": "Signaler un échec si un attribut est manquant", - "tell-failure-tooltip": "Si une des clés n’existe pas, le message signalera un échec.", - "created-time": "Date de création", - "chip-help": "Appuyez sur 'Entrée' pour valider {{inputName}}. \nAppuyez sur 'Retour arrière' pour supprimer. \nValeurs multiples supportées.", + "presence-monitoring-strategy-on-first-message-hint": "Signale le statut de présence 'À l'intérieur' ou 'À l'extérieur' lors du premier message après que la durée minimale configurée soit écoulée depuis la dernière mise à jour du statut de présence 'Entré' ou 'Parti'.", + "presence-monitoring-strategy-on-each-message-hint": "Signale le statut de présence 'À l'intérieur' ou 'À l'extérieur' à chaque message après la mise à jour du statut de présence 'Entré' ou 'Parti'.", + "fetch-credentials-to": "Récupérer les identifiants pour", + "add-originator-attributes-to": "Ajouter les attributs de l'initiateur à", + "originator-attributes": "Attributs de l'initiateur", + "fetch-latest-telemetry-with-timestamp": "Récupérer la dernière télémétrie avec timestamp", + "fetch-latest-telemetry-with-timestamp-tooltip": "Si activé, les dernières valeurs de télémétrie seront ajoutées aux métadonnées sortantes avec un timestamp, par exemple : \"{{latestTsKeyName}}\": \"{\"ts\":1574329385897, \"value\":42}\"", + "tell-failure": "Signaler une erreur si l'un des attributs est manquant", + "tell-failure-tooltip": "Si au moins une clé sélectionnée n'existe pas, le message sortant signalera \"Échec\".", + "created-time": "Heure de création", + "chip-help": "Appuyez sur 'Entrée' pour compléter la saisie de {{inputName}}. \nAppuyez sur 'Retour arrière' pour supprimer {{inputName}}. \nPlusieurs valeurs sont supportées.", "detail": "détail", "field-name": "Nom du champ", - "device-profile": "Profil de périphérique", + "device-profile": "Profil d'appareil", "entity-type": "Type d'entité", "message-type": "Type de message", "timeseries-key": "Clé de série temporelle", @@ -5295,15 +5320,15 @@ "add-mapped-originator-fields-to": "Ajouter les champs de l’origine mappés à", "fields": "Champs", "skip-empty-fields": "Ignorer les champs vides", - "skip-empty-fields-tooltip": "Les champs vides ne seront pas ajoutés au message de sortie ou aux métadonnées de sortie.", + "skip-empty-fields-tooltip": "Les champs avec des valeurs vides ne seront pas ajoutés au message de sortie/métadonnées de sortie.", "fetch-interval": "Intervalle de récupération", "fetch-strategy": "Stratégie de récupération", - "fetch-timeseries-from-to": "Récupérer les séries temporelles de {{startInterval}} {{startIntervalTimeUnit}} en arrière jusqu'à {{endInterval}} {{endIntervalTimeUnit}} en arrière.", - "fetch-timeseries-from-to-invalid": "Récupération des séries temporelles invalide (\"Début de l'intervalle\" doit être inférieur à \"Fin de l'intervalle\").", - "use-metadata-dynamic-interval-tooltip": "Si cette option est sélectionnée, le nœud de règle utilisera un intervalle dynamique basé sur le message et les modèles de métadonnées.", + "fetch-timeseries-from-to": "Récupérer les séries temporelles depuis {{startInterval}} {{startIntervalTimeUnit}} jusqu'à {{endInterval}} {{endIntervalTimeUnit}}.", + "fetch-timeseries-from-to-invalid": "Récupération de séries temporelles invalide (\"Début de l'intervalle\" doit être inférieur à \"Fin de l'intervalle\").", + "use-metadata-dynamic-interval-tooltip": "Si sélectionné, le nœud de règle utilisera des intervalles dynamiques de début et de fin basés sur les modèles de message et de métadonnées.", "all-mode-hint": "Si le mode de récupération \"Tout\" est sélectionné, le nœud de règle récupérera la télémétrie de l'intervalle de récupération avec des paramètres de requête configurables.", - "first-mode-hint": "Si le mode de récupération \"Premier\" est sélectionné, le nœud de règle récupérera la télémétrie la plus proche du début de l'intervalle.", - "last-mode-hint": "Si le mode de récupération \"Dernier\" est sélectionné, le nœud de règle récupérera la télémétrie la plus proche de la fin de l'intervalle.", + "first-mode-hint": "Si le mode de récupération \"Premier\" est sélectionné, le nœud de règle récupérera la télémétrie la plus proche du début de l'intervalle de récupération.", + "last-mode-hint": "Si le mode de récupération \"Dernier\" est sélectionné, le nœud de règle récupérera la télémétrie la plus proche de la fin de l'intervalle de récupération.", "ascending": "Croissant", "descending": "Décroissant", "min": "Minimum", @@ -5313,14 +5338,14 @@ "count": "Nombre", "none": "Aucun", "last-level-relation-tooltip": "Recherche des entités liées uniquement au niveau de relation maximum défini si activé.", - "last-level-device-relation-tooltip": "Recherche des périphériques liés uniquement au niveau spécifié si activé.", + "last-level-device-relation-tooltip": "Recherche des appareils liés uniquement au niveau spécifié si activé.", "data-to-fetch": "Données à récupérer", "mapping-of-customers": "Mappage des clients", "map-fields-required": "Tous les champs de mappage sont requis.", "attributes": "Attributs", - "related-device-attributes": "Attributs du périphérique lié", + "related-device-attributes": "Attributs de l’appareil lié", "add-selected-attributes-to": "Ajouter les attributs sélectionnés à", - "device-profiles": "Profils de périphérique", + "device-profiles": "Profils d'appareils", "mapping-of-tenant": "Mappage du locataire", "add-attribute-key": "Ajouter une clé d’attribut", "message-template": "Modèle de message", @@ -5331,20 +5356,20 @@ "keys-mapping": "Mappage des clés", "add-key": "Ajouter une clé", "recipients": "Destinataires", - "message-subject-and-content": "Objet et contenu du message", - "template-rules-hint": "Les champs supportent la templatization avec $[messageKey] ou ${metadataKey}.", - "originator-customer-desc": "Utilise le client de l’origine du message comme nouvelle origine.", - "originator-tenant-desc": "Utilise le locataire actuel comme origine.", - "originator-related-entity-desc": "Utilise une entité liée comme origine, selon le type et la direction de relation.", - "originator-alarm-originator-desc": "Utilise l’origine de l’alarme si le message provient d’une entité d’alarme.", - "originator-entity-by-name-pattern-desc": "Utilise une entité récupérée par type et modèle de nom.", - "email-from-template-hint": "Utilisez $[messageKey] ou ${metadataKey} pour remplir dynamiquement.", - "recipients-block-main-hint": "Liste d’adresses séparées par des virgules. Supporte la templatization.", - "forward-msg-default-rule-chain": "Transférer au rule chain par défaut de l’origine", - "forward-msg-default-rule-chain-tooltip": "Transfère au rule chain par défaut ou configuré si aucun n’est défini dans le profil.", + "message-subject-and-content": "Sujet et contenu du message", + "template-rules-hint": "Les deux champs d'entrée prennent en charge la templatisation. Utilisez $[messageKey] pour extraire la valeur du message et ${metadataKey} pour extraire la valeur des métadonnées du message.", + "originator-customer-desc": "Utiliser le client de l'initiateur du message entrant comme nouveau créateur.", + "originator-tenant-desc": "Utiliser le locataire actuel comme nouveau créateur.", + "originator-related-entity-desc": "Utiliser l'entité liée comme nouveau créateur. Recherche basée sur le type de relation et la direction configurés.", + "originator-alarm-originator-desc": "Utiliser l'initiateur de l'alarme comme nouveau créateur. Seulement si l'initiateur du message entrant est une entité d'alarme.", + "originator-entity-by-name-pattern-desc": "Utiliser l'entité récupérée de la base de données comme nouveau créateur. Recherche basée sur le type d'entité et le modèle de nom spécifié.", + "email-from-template-hint": "Utilisez $[messageKey] pour extraire la valeur du message et ${metadataKey} pour extraire la valeur des métadonnées.", + "recipients-block-main-hint": "Liste d'adresses séparées par des virgules. Tous les champs d'entrée prennent en charge la templatisation. Utilisez $[messageKey] pour extraire la valeur du message et ${metadataKey} pour extraire la valeur des métadonnées.", + "forward-msg-default-rule-chain": "Transférer le message vers la chaîne de règles par défaut de l'initiateur", + "forward-msg-default-rule-chain-tooltip": "Si activé, le message sera transféré à la chaîne de règles par défaut de l'initiateur, ou à la chaîne de règles configurée, si l'initiateur n'a pas de chaîne de règles par défaut définie dans le profil de l'entité.", "exclude-zero-deltas": "Exclure les deltas nuls du message sortant", - "exclude-zero-deltas-hint": "Ajoute la clé {{outputValueKey}} uniquement si sa valeur est différente de zéro.", - "exclude-zero-deltas-time-difference-hint": "Ajoute les clés {{outputValueKey}} et {{periodValueKey}} uniquement si {{outputValueKey}} ≠ 0.", + "exclude-zero-deltas-hint": "Si activé, la clé de sortie \"{{outputValueKey}}\" sera ajoutée au message sortant si sa valeur n'est pas zéro.", + "exclude-zero-deltas-time-difference-hint": "Si activé, les clés de sortie \"{{outputValueKey}}\" et \"{{periodValueKey}}\" seront ajoutées au message sortant uniquement si la valeur de \"{{outputValueKey}}\" n'est pas zéro.", "search-direction-from": "De l’origine vers l’entité cible", "search-direction-to": "De l’entité cible vers l’origine", "del-relation-direction-from": "Depuis l’origine", @@ -5354,21 +5379,21 @@ "function-name": "Nom de la fonction", "function-name-required": "Le nom de la fonction est requis.", "qualifier": "Qualificateur", - "qualifier-hint": "Par défaut, \"$LATEST\" sera utilisé si vide.", + "qualifier-hint": "Si le qualificateur n'est pas spécifié, le qualificateur par défaut \"$LATEST\" sera utilisé.", "aws-credentials": "Identifiants AWS", "connection-timeout": "Délai de connexion", "connection-timeout-required": "Le délai de connexion est requis.", - "connection-timeout-min": "Valeur minimale : 0", - "connection-timeout-hint": "Temps d’attente (en sec) pour établir la connexion. 0 = infini (non recommandé).", - "request-timeout": "Délai de requête", - "request-timeout-required": "Le délai de requête est requis", - "request-timeout-min": "Valeur minimale : 0", - "request-timeout-hint": "Temps d’attente (en sec) pour exécution de la requête. 0 = infini (non recommandé).", + "connection-timeout-min": "Le délai de connexion minimum est de 0.", + "connection-timeout-hint": "Le temps d'attente en secondes lors de l'établissement initial d'une connexion avant l'abandon et le délai d'attente. Une valeur de 0 signifie l'infini et n'est pas recommandée.", + "request-timeout": "Délai d'attente de la demande", + "request-timeout-required": "Le délai d'attente de la demande est requis", + "request-timeout-min": "Le délai d'attente minimum pour la demande est de 0", + "request-timeout-hint": "Le temps d'attente en secondes pour que la demande soit terminée avant l'abandon et le délai d'attente. Une valeur de 0 signifie l'infini et n'est pas recommandée.", "units": "Unités", - "tell-failure-aws-lambda": "Signaler un échec si l’exécution AWS Lambda échoue", - "tell-failure-aws-lambda-hint": "Déclenche un échec du traitement si AWS Lambda lève une exception.", - "basic-mode": "Mode basique", - "advanced-mode": "Mode avancé", + "tell-failure-aws-lambda": "Signaler un échec si l'exécution de la fonction AWS Lambda génère une exception", + "tell-failure-aws-lambda-hint": "Le nœud de règle force l'échec du traitement du message si l'exécution de la fonction AWS Lambda génère une exception.", + "basic-mode": "Basique", + "advanced-mode": "Avancé", "save-time-series": { "processing-settings": "Paramètres de traitement", "processing-settings-hint": "Définissez comment les messages entrants sont traités. Les paramètres de base permettent de sélectionner des stratégies préconfigurées, tandis que les paramètres avancés permettent de choisir des stratégies individuelles pour chaque action.", @@ -5430,34 +5455,35 @@ "after-template-evaluation-hint": "Après évaluation du modèle, la valeur doit être true pour HTML, et false pour Texte brut." }, "ai": { - "ai-model": "Modèle IA", + "ai-model": "Modèle d'IA", "model": "Modèle", - "ai-model-hint": "Sélectionnez le modèle IA préconfiguré pour traiter les requêtes envoyées par ce nœud de règle, ou utilisez \"Créer un nouveau\" pour en configurer un nouveau.", - "prompt-settings": "Paramètres de prompt", - "prompt-settings-hint": "Le prompt système optionnel définit le rôle général et les contraintes de l'IA, tandis que le prompt utilisateur précise la tâche à exécuter. Les deux champs prennent en charge la modélisation par modèle (templatization).", - "system-prompt": "Prompt système", - "system-prompt-max-length": "Le prompt système doit comporter 500 000 caractères ou moins.", - "system-prompt-blank": "Le prompt système ne doit pas être vide.", - "user-prompt": "Prompt utilisateur", - "user-prompt-required": "Le prompt utilisateur est requis.", - "user-prompt-max-length": "Le prompt utilisateur doit comporter 500 000 caractères ou moins.", - "user-prompt-blank": "Le prompt utilisateur ne doit pas être vide.", + "ai-model-hint": "Sélectionnez le modèle d'IA préconfiguré pour traiter les demandes envoyées par ce nœud de règle, ou utilisez \"Créer un nouveau\" pour configurer un nouveau modèle.", + "prompt-settings": "Paramètres de l'invite", + "prompt-settings-hint": "L'invite système facultative définit le rôle général et les contraintes de l'IA, tandis que l'invite utilisateur définit la tâche spécifique à accomplir. Les deux champs prennent également en charge la templatisation.", + "system-prompt": "Invite système", + "system-prompt-max-length": "L'invite système doit comporter 500 000 caractères ou moins.", + "system-prompt-blank": "L'invite système ne doit pas être vide.", + "user-prompt": "Invite utilisateur", + "user-prompt-required": "L'invite utilisateur est requise.", + "user-prompt-max-length": "L'invite utilisateur doit comporter 500 000 caractères ou moins.", + "user-prompt-blank": "L'invite utilisateur ne doit pas être vide.", "response-format": "Format de réponse", "response-text": "Texte", "response-json": "JSON", "response-json-schema": "Schéma JSON", - "response-format-hint-TEXT": "Permet au modèle de générer un texte libre, qui peut ou non être un objet JSON valide. Si la sortie n’est pas un objet JSON valide, elle sera automatiquement encapsulée dans un objet JSON sous la clé \"response\".", - "response-format-hint-JSON": "Le modèle doit générer une réponse sous forme de JSON valide. Si la sortie n’est pas un objet JSON valide, elle sera automatiquement encapsulée dans un objet JSON sous la clé \"response\".", - "response-format-hint-JSON_SCHEMA": "Le modèle doit générer un JSON conforme à la structure et aux types de données définis dans le schéma fourni. Si la sortie n’est pas un objet JSON valide, elle sera automatiquement encapsulée dans un objet JSON sous la clé \"response\".", - "response-json-schema-hint": "Bien que tout schéma JSON valide puisse être saisi, ce nœud de règle ne prend en charge qu’un sous-ensemble limité de ses fonctionnalités. Consultez la documentation du nœud pour plus de détails.", + "response-format-hint-TEXT": "Permet au modèle de générer un texte arbitraire, qui peut ou non être un objet JSON valide. Si la sortie n'est pas un objet JSON valide, elle sera automatiquement enveloppée dans un objet JSON sous la clé \"response\".", + "response-format-hint-JSON": "Le modèle doit générer une réponse qui soit un JSON valide. Si la sortie n'est pas un objet JSON valide, elle sera automatiquement enveloppée dans un objet JSON sous la clé \"response\".", + "response-format-hint-JSON_SCHEMA": "Le modèle doit générer un JSON qui correspond à la structure spécifique et aux types de données définis dans le schéma fourni. Si la sortie n'est pas un objet JSON valide, elle sera automatiquement enveloppée dans un objet JSON sous la clé \"response\".", + "response-json-schema-hint": "Bien que tout schéma JSON valide puisse être saisi, ce nœud de règle ne prend en charge qu'un sous-ensemble limité de ses fonctionnalités. Consultez la documentation du nœud pour plus de détails.", "response-json-schema-required": "Le schéma JSON est requis", "advanced-settings": "Paramètres avancés", "timeout": "Délai d'attente", - "timeout-hint": "Temps maximal d’attente d’une réponse \nde la part du modèle IA avant l’arrêt de la requête.", + "timeout-hint": "Temps maximum à attendre pour une réponse \ndu modèle d'IA avant que la demande ne soit terminée.", "timeout-required": "Le délai d'attente est requis", "timeout-validation": "Doit être compris entre 1 seconde et 10 minutes.", - "force-acknowledgement": "Forcer l’accusé de réception", - "force-acknowledgement-hint": "Si activé, le message entrant est accusé immédiatement. La réponse du modèle est ensuite mise en file d’attente comme un nouveau message distinct." + "force-acknowledgement": "Forcer l'accusé de réception", + "force-acknowledgement-hint": "Si activé, le message entrant est immédiatement reconnu. La réponse du modèle est ensuite mise en file d'attente en tant que message distinct.", + "ai-resources": "Ressources IA" } }, "timezone": { @@ -5757,32 +5783,32 @@ "rule-engine-exceptions-ttl-days": "Durée de vie des exceptions du moteur de règles", "rule-engine-exceptions-ttl-days-required": "La durée est requise", "rule-engine-exceptions-ttl-days-range": "La durée ne peut pas être négative", - "max-rule-node-executions-per-message": "Nombre maximal d'exécutions par message d'un nœud de règle", - "max-rule-node-executions-per-message-required": "Le nombre est requis.", - "max-rule-node-executions-per-message-range": "Le nombre ne peut pas être négatif", - "max-emails": "Nombre maximal d'e-mails envoyés", - "max-emails-required": "Le nombre d'e-mails est requis.", - "max-emails-range": "Le nombre ne peut pas être négatif", + "max-rule-node-executions-per-message": "Nombre maximum d'exécutions de nœud de règle par message", + "max-rule-node-executions-per-message-required": "Le nombre maximum d'exécutions de nœud de règle par message est requis.", + "max-rule-node-executions-per-message-range": "Le nombre maximum d'exécutions de nœud de règle par message ne peut pas être négatif", + "max-emails": "Nombre maximum d'e-mails envoyés", + "max-emails-required": "Le nombre maximum d'e-mails envoyés est requis.", + "max-emails-range": "Le nombre maximum d'e-mails envoyés ne peut pas être négatif", "sms-enabled": "SMS activé", - "max-sms": "Nombre maximal de SMS envoyés", - "max-sms-required": "Le nombre de SMS est requis.", - "max-sms-range": "Le nombre ne peut pas être négatif", - "max-created-alarms": "Nombre maximal d'alarmes créées", - "max-created-alarms-required": "Le nombre est requis.", - "max-created-alarms-range": "Le nombre ne peut pas être négatif", - "no-queue": "Aucune file d’attente configurée", - "add-queue": "Ajouter une file d’attente", - "queues-with-count": "Files d’attente ({{count}})", + "max-sms": "Nombre maximum de SMS envoyés", + "max-sms-required": "Le nombre maximum de SMS envoyés est requis.", + "max-sms-range": "Le nombre maximum de SMS envoyés ne peut pas être négatif", + "max-created-alarms": "Nombre maximum d'alarmes créées", + "max-created-alarms-required": "Le nombre maximum d'alarmes créées est requis.", + "max-created-alarms-range": "Le nombre maximum d'alarmes créées ne peut pas être négatif", + "no-queue": "Aucune file d'attente configurée", + "add-queue": "Ajouter une file d'attente", + "queues-with-count": "Files d'attente ({{count}})", "tenant-rest-limits": "Requêtes REST pour le locataire", "customer-rest-limits": "Requêtes REST pour le client", - "incorrect-pattern-for-rate-limits": "Le format est une liste de paires séparées par des virgules, contenant une capacité et une période (en secondes), séparées par deux-points, par ex. 100:1,2000:60", + "incorrect-pattern-for-rate-limits": "Le format est une liste séparée par des virgules de paires de capacité et de période (en secondes) avec un deux-points entre, par exemple 100:1,2000:60", "too-small-value-zero": "La valeur doit être supérieure à 0", "too-small-value-one": "La valeur doit être supérieure à 1", - "queue-size-is-limited-by-system-configuration": "La taille de la file d’attente est également limitée par la configuration système.", - "cassandra-write-tenant-core-limits-configuration": "Requêtes d’écriture Cassandra via l’API REST", - "cassandra-read-tenant-core-limits-configuration": "Requêtes de lecture Cassandra via l’API REST et WS (télémétrie)", - "cassandra-write-tenant-rule-engine-limits-configuration": "Requêtes d’écriture Cassandra du moteur de règles (télémétrie)", - "cassandra-read-tenant-rule-engine-limits-configuration": "Requêtes de lecture Cassandra du moteur de règles (télémétrie)", + "queue-size-is-limited-by-system-configuration": "La taille de la file d'attente est également limitée par la configuration du système.", + "cassandra-write-tenant-core-limits-configuration": "Requêtes d'écriture Cassandra API REST", + "cassandra-read-tenant-core-limits-configuration": "Requêtes de lecture Cassandra API REST et WS télémétrie", + "cassandra-write-tenant-rule-engine-limits-configuration": "Requêtes d'écriture Cassandra moteur de règles télémétrie", + "cassandra-read-tenant-rule-engine-limits-configuration": "Requêtes de lecture Cassandra moteur de règles télémétrie", "ws-limit-max-sessions-per-tenant": "Nombre maximal de sessions par locataire", "ws-limit-max-sessions-per-customer": "Nombre maximal de sessions par client", "ws-limit-max-sessions-per-regular-user": "Nombre maximal de sessions par utilisateur régulier", @@ -5799,36 +5825,36 @@ "advanced-settings": "Paramètres avancés", "edit-limit": "Modifier la limite", "calculated-field-debug-event-rate-limit": "Événements de débogage des champs calculés", - "edit-calculated-field-debug-event-rate-limit": "Modifier les limites de débit des événements de débogage des champs calculés", - "edit-transport-tenant-msg-title": "Modifier les limites de débit des messages transport du locataire", - "edit-transport-tenant-telemetry-msg-title": "Modifier les limites de débit des messages de télémétrie transport du locataire", - "edit-transport-tenant-telemetry-data-points-title": "Modifier les limites de débit des points de données de télémétrie transport du locataire", - "edit-transport-device-msg-title": "Modifier les limites de débit des messages transport de l'appareil", - "edit-transport-device-telemetry-msg-title": "Modifier les limites de débit des messages de télémétrie transport de l'appareil", - "edit-transport-device-telemetry-data-points-title": "Modifier les limites de débit des points de données de télémétrie transport de l'appareil", - "edit-transport-gateway-msg-title": "Modifier les limites de débit des messages transport de la passerelle", - "edit-transport-gateway-telemetry-msg-title": "Modifier les limites de débit des messages de télémétrie transport de la passerelle", - "edit-transport-gateway-telemetry-data-points-title": "Modifier les limites de débit des points de données de télémétrie transport de la passerelle", - "edit-transport-gateway-device-msg-title": "Modifier les limites de débit des messages transport des appareils de la passerelle", - "edit-transport-gateway-device-telemetry-msg-title": "Modifier les limites de débit des messages de télémétrie transport des appareils de la passerelle", - "edit-transport-gateway-device-telemetry-data-points-title": "Modifier les limites de débit des points de données de télémétrie transport des appareils de la passerelle", - "edit-tenant-rest-limits-title": "Modifier les limites de débit des requêtes REST du locataire", - "edit-customer-rest-limits-title": "Modifier les limites de débit des requêtes REST du client", - "edit-ws-limit-updates-per-session-title": "Modifier les limites de débit des mises à jour WS par session", - "edit-cassandra-write-tenant-core-limits-configuration": "Modifier les requêtes d’écriture Cassandra via l’API REST", - "edit-cassandra-read-tenant-core-limits-configuration": "Modifier les requêtes de lecture Cassandra via l’API REST et WS (télémétrie)", - "edit-cassandra-write-tenant-rule-engine-limits-configuration": "Modifier les requêtes d’écriture Cassandra du moteur de règles (télémétrie)", - "edit-cassandra-read-tenant-rule-engine-limits-configuration": "Modifier les requêtes de lecture Cassandra du moteur de règles (télémétrie)", - "edit-tenant-entity-export-rate-limit-title": "Modifier les limites de création de version d’entité", - "edit-tenant-entity-import-rate-limit-title": "Modifier les limites de chargement de version d’entité", - "edit-tenant-notification-request-rate-limit-title": "Modifier les limites des requêtes de notification", - "edit-tenant-notification-requests-per-rule-rate-limit-title": "Modifier les limites des requêtes de notification par règle", + "edit-calculated-field-debug-event-rate-limit": "Modifier les limites de taux des événements de débogage des champs calculés", + "edit-transport-tenant-msg-title": "Modifier les limites de taux des messages de transport pour le locataire", + "edit-transport-tenant-telemetry-msg-title": "Modifier les limites de taux des messages de télémétrie de transport pour le locataire", + "edit-transport-tenant-telemetry-data-points-title": "Modifier les limites de taux des points de données de télémétrie de transport pour le locataire", + "edit-transport-device-msg-title": "Modifier les limites de taux des messages de transport pour l'appareil", + "edit-transport-device-telemetry-msg-title": "Modifier les limites de taux des messages de télémétrie de transport pour l'appareil", + "edit-transport-device-telemetry-data-points-title": "Modifier les limites de taux des points de données de télémétrie de transport pour l'appareil", + "edit-transport-gateway-msg-title": "Modifier les limites de taux des messages de transport pour la passerelle", + "edit-transport-gateway-telemetry-msg-title": "Modifier les limites de taux des messages de télémétrie de transport pour la passerelle", + "edit-transport-gateway-telemetry-data-points-title": "Modifier les limites de taux des points de données de télémétrie de transport pour la passerelle", + "edit-transport-gateway-device-msg-title": "Modifier les limites de taux des messages de transport pour l'appareil de la passerelle", + "edit-transport-gateway-device-telemetry-msg-title": "Modifier les limites de taux des messages de télémétrie de transport pour l'appareil de la passerelle", + "edit-transport-gateway-device-telemetry-data-points-title": "Modifier les limites de taux des points de données de télémétrie de transport pour l'appareil de la passerelle", + "edit-tenant-rest-limits-title": "Modifier les limites des requêtes REST pour le locataire", + "edit-customer-rest-limits-title": "Modifier les limites des requêtes REST pour le client", + "edit-ws-limit-updates-per-session-title": "Modifier les limites des mises à jour WS par session", + "edit-cassandra-write-tenant-core-limits-configuration": "Modifier les requêtes d'écriture Cassandra de l'API REST", + "edit-cassandra-read-tenant-core-limits-configuration": "Modifier les requêtes de lecture Cassandra de l'API REST et de la télémétrie WS", + "edit-cassandra-write-tenant-rule-engine-limits-configuration": "Modifier les requêtes d'écriture Cassandra de la télémétrie du moteur de règles", + "edit-cassandra-read-tenant-rule-engine-limits-configuration": "Modifier les requêtes de lecture Cassandra de la télémétrie du moteur de règles", + "edit-tenant-entity-export-rate-limit-title": "Modifier les limites de taux de création d'entités", + "edit-tenant-entity-import-rate-limit-title": "Modifier les limites de taux de chargement d'entités", + "edit-tenant-notification-request-rate-limit-title": "Modifier les limites de taux des demandes de notification", + "edit-tenant-notification-requests-per-rule-rate-limit-title": "Modifier les limites de taux des demandes de notification par règle de notification", "edit-edge-events-rate-limit": "Modifier les limites des événements Edge", "edit-edge-events-per-edge-rate-limit": "Modifier les limites des événements Edge par instance", "edge-events-rate-limit": "Événements Edge", "edge-events-per-edge-rate-limit": "Événements Edge par instance", "edit-edge-uplink-messages-rate-limit": "Modifier les limites des messages montants Edge", - "edit-edge-uplink-messages-per-edge-rate-limit": "Modifier les limites des messages montants Edge par instance", + "edit-edge-uplink-messages-per-edge-rate-limit": "Modifier les messages montants Edge conformément aux limites de débit Edge", "edge-uplink-messages-rate-limit": "Messages montants Edge", "edge-uplink-messages-per-edge-rate-limit": "Messages montants Edge par instance", "messages-per": "messages par", @@ -5838,23 +5864,23 @@ "number-of-messages-min": "La valeur minimale est 1.", "preview": "Aperçu", "per-seconds": "Par secondes", - "per-seconds-required": "La durée est requise.", + "per-seconds-required": "Le taux de temps est requis.", "per-seconds-min": "La valeur minimale est 1.", - "per-seconds-duplicate": "Taux de temps en double. Chaque intervalle de temps doit être unique.", - "rate-limits": "Limites de débit", + "per-seconds-duplicate": "Taux de temps dupliqué. Chaque intervalle de temps doit être unique.", + "rate-limits": "Limites de taux", "remove-limit": "Supprimer la limite", - "transport-tenant-msg": "Messages de transport du locataire", - "transport-tenant-telemetry-msg": "Messages de télémétrie du locataire", - "transport-tenant-telemetry-data-points": "Points de données de télémétrie du locataire", - "transport-device-msg": "Messages de l’appareil", - "transport-device-telemetry-msg": "Messages de télémétrie de l’appareil", - "transport-device-telemetry-data-points": "Points de données de télémétrie de l’appareil", - "transport-gateway-msg": "Messages de la passerelle", - "transport-gateway-telemetry-msg": "Messages de télémétrie de la passerelle", - "transport-gateway-telemetry-data-points": "Points de données de télémétrie de la passerelle", - "transport-gateway-device-msg": "Messages des appareils de la passerelle", - "transport-gateway-device-telemetry-msg": "Messages de télémétrie des appareils de la passerelle", - "transport-gateway-device-telemetry-data-points": "Points de données de télémétrie des appareils de la passerelle", + "transport-tenant-msg": "Messages de transport pour le locataire", + "transport-tenant-telemetry-msg": "Messages de télémétrie de transport pour le locataire", + "transport-tenant-telemetry-data-points": "Points de données de télémétrie de transport pour le locataire", + "transport-device-msg": "Messages de transport pour l'appareil", + "transport-device-telemetry-msg": "Messages de télémétrie de transport pour l'appareil", + "transport-device-telemetry-data-points": "Points de données de télémétrie de transport pour l'appareil", + "transport-gateway-msg": "Messages de transport pour la passerelle", + "transport-gateway-telemetry-msg": "Messages de télémétrie de transport pour la passerelle", + "transport-gateway-telemetry-data-points": "Points de données de télémétrie de transport pour la passerelle", + "transport-gateway-device-msg": "Messages de transport pour l'appareil de la passerelle", + "transport-gateway-device-telemetry-msg": "Messages de télémétrie de transport pour l'appareil de la passerelle", + "transport-gateway-device-telemetry-data-points": "Points de données de télémétrie de transport pour l'appareil de la passerelle", "sec": "sec" } }, @@ -5987,83 +6013,84 @@ "label": "Étiquette", "value": "Valeur", "date": "Date", - "show-date-time-interval": "Afficher l’intervalle date/heure", - "show-date-time-interval-hint": "Afficher l’intervalle date/heure en fonction de l’agrégation des données.", + "show-date-time-interval": "Afficher l'intervalle de date et d'heure", + "show-date-time-interval-hint": "Afficher l'intervalle de date et d'heure selon l'agrégation des données.", "hide-zero-tooltip-values": "Masquer les valeurs nulles", - "background-color": "Couleur d’arrière-plan", - "background-blur": "Flou d’arrière-plan" + "show-stack-total": "Afficher la valeur totale en mode empilé", + "background-color": "Couleur de fond", + "background-blur": "Flou de fond" }, "unit": { - "set-unit-conversion": "Définir la conversion d’unités", + "set-unit-conversion": "Définir la conversion d'unités", "unit-settings": { - "unit-settings": "Paramètres d’unité", + "unit-settings": "Paramètres des unités", "source-unit": "Unité source", - "source-unit-hint": "Il s’agit de l’unité de la valeur stockée. L’unité à partir de laquelle vous effectuez la conversion. Entrez le symbole utilisé par vos données sources (ex. : m, km, ft, in).", + "source-unit-hint": "Il s'agit de l'unité de la valeur stockée. L'unité dont vous effectuez la conversion. Entrez le symbole utilisé par vos données sources (par exemple, m, km, ft, in).", "target-metric-unit": "Unité métrique cible", - "target-metric-unit-hint": "Choisissez l’unité métrique (SI) vers laquelle vous souhaitez convertir votre valeur source (ex. : cm, mm, km).", + "target-metric-unit-hint": "Choisissez l'unité métrique (SI) dans laquelle vous souhaitez convertir votre valeur source (par exemple, cm, mm, km).", "target-imperial-unit": "Unité impériale cible", - "target-imperial-unit-hint": "Choisissez l’unité impériale vers laquelle vous souhaitez convertir votre valeur source (ex. : in, ft, yd).", + "target-imperial-unit-hint": "Choisissez l'unité impériale dans laquelle vous souhaitez convertir votre valeur source (par exemple, in, ft, yd).", "target-hybrid-unit": "Unité hybride cible", - "target-hybrid-unit-hint": "Choisissez l’unité hybride vers laquelle vous souhaitez convertir votre valeur source (ex. : cm, in, km). Les unités hybrides combinent des unités métriques ou impériales.", - "enable-unit-conversion": "Activer la conversion d’unités", - "enable-unit-conversion-hint": "Activez cette option pour appliquer la conversion. Si désactivée, votre valeur source sera transmise sans modification. Désactivée s’il n’existe qu’une seule unité dans le groupe de mesure correspondant (ex. : flux lumineux, AQI)." + "target-hybrid-unit-hint": "Choisissez l'unité hybride dans laquelle vous souhaitez convertir votre valeur source (par exemple, cm, in, km). Les unités hybrides combinent les unités métriques ou impériales.", + "enable-unit-conversion": "Activer la conversion d'unités", + "enable-unit-conversion-hint": "Activez cette option pour activer la conversion. Si désactivé, votre valeur source passera inchangée. Désactivé s'il n'y a qu'une seule unité dans le groupe de mesures correspondant (par exemple, flux lumineux, AQI)." }, - "unit-system": "Système d’unités", + "unit-system": "Système d'unités", "unit-system-type": { - "AUTO": "Auto", + "AUTO": "Automatique", "METRIC": "Métrique", "IMPERIAL": "Impérial", "HYBRID": "Hybride" }, "measures": { - "absorbed-dose-rate": "Débit de dose absorbée", + "absorbed-dose-rate": "Taux de dose absorbée", "acceleration": "Accélération", "acidity": "Acidité", - "air-quality-index": "Indice de qualité de l’air", - "amount-of-substance": "Quantité de matière", + "air-quality-index": "Indice de qualité de l'air", + "amount-of-substance": "Quantité de substance", "angle": "Angle", "angular-acceleration": "Accélération angulaire", "area": "Surface", - "area-density": "Densité surfacique", - "capacitance": "Capacité électrique", + "area-density": "Densité de surface", + "capacitance": "Capacité", "catalytic-activity": "Activité catalytique", "catalytic-concentration": "Concentration catalytique", "charge": "Charge", "current-density": "Densité de courant", - "data-transfer-rate": "Débit de transfert de données", + "data-transfer-rate": "Taux de transfert de données", "density": "Densité", "digital": "Numérique", - "dimension-ratio": "Rapport de dimensions", + "dimension-ratio": "Rapport dimensionnel", "dynamic-viscosity": "Viscosité dynamique", - "earthquake-magnitude": "Magnitude sismique", + "earthquake-magnitude": "Magnitude du séisme", "electric-charge-density": "Densité de charge électrique", "electric-current": "Courant électrique", "electric-dipole-moment": "Moment dipolaire électrique", "electric-field-strength": "Intensité du champ électrique", "electric-flux": "Flux électrique", "electric-permittivity": "Permittivité électrique", - "electric-polarizability": "Polarisabilité électrique", + "electric-polarizability": "Polarizabilité électrique", "electrical-conductance": "Conductance électrique", "electrical-conductivity": "Conductivité électrique", "energy": "Énergie", - "energy-density": "Densité d’énergie", + "energy-density": "Densité d'énergie", "force": "Force", "frequency": "Fréquence", - "fuel-efficiency": "Rendement énergétique", + "fuel-efficiency": "Efficacité énergétique", "heat-capacity": "Capacité thermique", - "illuminance": "Éclairement lumineux", + "illuminance": "Éclairement", "inductance": "Inductance", "kinematic-viscosity": "Viscosité cinématique", "length": "Longueur", - "light-exposure": "Exposition lumineuse", - "linear-charge-density": "Densité linéique de charge", + "light-exposure": "Exposition à la lumière", + "linear-charge-density": "Densité de charge linéaire", "logarithmic-ratio": "Rapport logarithmique", "luminous-efficacy": "Efficacité lumineuse", "luminous-flux": "Flux lumineux", "luminous-intensity": "Intensité lumineuse", - "magnetic-field-gradient": "Gradient de champ magnétique", + "magnetic-field-gradient": "Gradient du champ magnétique", "magnetic-flux": "Flux magnétique", - "magnetic-flux-density": "Induction magnétique", + "magnetic-flux-density": "Densité de flux magnétique", "magnetic-moment": "Moment magnétique", "magnetic-permeability": "Perméabilité magnétique", "mass": "Masse", @@ -6078,23 +6105,23 @@ "power-density": "Densité de puissance", "pressure": "Pression", "radiance": "Radiance", - "radiant-intensity": "Intensité de rayonnement", - "radiation-dose": "Dose de rayonnement", + "radiant-intensity": "Intensité radiant", + "radiation-dose": "Dose de radiation", "radioactive-decay": "Désintégration radioactive", "radioactivity": "Radioactivité", - "radioactivity-concentration": "Concentration radioactive", + "radioactivity-concentration": "Concentration en radioactivité", "reciprocal-length": "Longueur réciproque", "resistance": "Résistance", "reynolds-number": "Nombre de Reynolds", - "signal-level": "Niveau du signal", + "signal-level": "Niveau de signal", "solid-angle": "Angle solide", "specific-energy": "Énergie spécifique", "specific-heat-capacity": "Capacité thermique spécifique", "specific-humidity": "Humidité spécifique", "specific-volume": "Volume spécifique", "speed": "Vitesse", - "surface-charge-density": "Densité de charge surfacique", - "surface-tension": "Tension superficielle", + "surface-charge-density": "Densité de charge de surface", + "surface-tension": "Tension de surface", "temperature": "Température", "thermal-conductivity": "Conductivité thermique", "time": "Temps", @@ -6102,7 +6129,7 @@ "turbidity": "Turbidité", "voltage": "Tension", "volume": "Volume", - "volume-flow": "Débit volumique" + "volume-flow": "Débit volumétrique" }, "millimeter": "Millimètre", "centimeter": "Centimètre", @@ -6114,8 +6141,8 @@ "kilometer": "Kilomètre", "inch": "Pouce", "foot": "Pied", - "foot-us": "Pied (US survey)", - "yard": "Yard", + "foot-us": "Pied (enquête US)", + "yard": "Jarde", "mile": "Mille", "nautical-mile": "Mille nautique", "astronomical-unit": "Unité astronomique", @@ -6160,8 +6187,8 @@ "cubic-inch": "Pouce cube", "cubic-foot": "Pied cube", "cubic-yard": "Yard cube", - "fluid-ounce": "Once liquide", - "fluid-ounce-per-second": "Once liquide par seconde", + "fluid-ounce": "Once fluide", + "fluid-ounce-per-second": "Once fluide par seconde", "pint": "Pinte", "quart": "Quart", "gallon": "Gallon", @@ -6176,7 +6203,7 @@ "kelvin": "Kelvin", "rankine": "Rankine", "fahrenheit": "Fahrenheit", - "percent": "Pourcentage", + "percent": "Pourcent", "meter-per-second": "Mètre par seconde", "kilometer-per-hour": "Kilomètre par heure", "foot-per-second": "Pied par seconde", @@ -6209,9 +6236,9 @@ "pascal-per-square-meter": "Pascal par mètre carré", "pound-per-square-inch": "Livre par pouce carré", "newton-per-square-meter": "Newton par mètre carré", - "kilogram-force-per-square-meter": "Kilogramme-force par mètre carré", + "kilogram-force-per-square-meter": "Force de kilogramme par mètre carré", "pascal-per-square-centimeter": "Pascal par centimètre carré", - "ton-force-per-square-inch": "Tonne-force par pouce carré", + "ton-force-per-square-inch": "Force en tonne par pouce carré", "kilonewton-per-square-meter": "Kilonewton par mètre carré", "newton-per-square-millimeter": "Newton par millimètre carré", "microjoule": "Microjoule", @@ -6226,11 +6253,11 @@ "milliwatt-hour": "Milliwatt-heure", "megawatt-hour": "Mégawatt-heure", "gigawatt-hour": "Gigawatt-heure", - "electron-volts": "Électron-volt", + "electron-volts": "Volts électroniques", "joules-per-coulomb": "Joules par coulomb", "british-thermal-unit": "Unité thermique britannique", "thousand-british-thermal-unit": "Mille unités thermiques britanniques", - "million-british-thermal-unit": "Million d’unités thermiques britanniques", + "million-british-thermal-unit": "Million d'unités thermiques britanniques", "foot-pound": "Pied-livre", "calorie": "Calorie", "small-calorie": "Petite calorie", @@ -6260,16 +6287,16 @@ "kilowatt-per-square-meter": "Kilowatt par mètre carré", "watt-per-square-inch": "Watt par pouce carré", "kilowatt-per-square-inch": "Kilowatt par pouce carré", - "horsepower": "Cheval-vapeur", + "horsepower": "Chevaux-vapeur", "btu-per-hour": "Unités thermiques britanniques par heure", "btu-per-second": "Unités thermiques britanniques par seconde", "btu-per-day": "Unités thermiques britanniques par jour", "mbtu-per-hour": "Mille unités thermiques britanniques par heure", "mbtu-per-second": "Mille unités thermiques britanniques par seconde", "mbtu-per-day": "Mille unités thermiques britanniques par jour", - "mmbtu-per-hour": "Million d’unités thermiques britanniques par heure", - "mmbtu-per-second": "Million d’unités thermiques britanniques par seconde", - "mmbtu-per-day": "Million d’unités thermiques britanniques par jour", + "mmbtu-per-hour": "Million d'unités thermiques britanniques par heure", + "mmbtu-per-second": "Million d'unités thermiques britanniques par seconde", + "mmbtu-per-day": "Million d'unités thermiques britanniques par jour", "foot-pound-per-second": "Pied-livre par seconde", "coulomb": "Coulomb", "millicoulomb": "Millicoulomb", @@ -6293,8 +6320,8 @@ "barn": "Barn", "circular-inch": "Pouce circulaire", "milliampere-hour": "Milliampère-heure", - "ampere-hours": "Ampère-heure", - "kiloampere-hours": "Kiloampère-heure", + "ampere-hours": "Ampère-heures", + "kiloampere-hours": "Kiloampère-heures", "nanoampere": "Nanoampère", "picoampere": "Picoampère", "microampere": "Microampère", @@ -6307,7 +6334,7 @@ "ampere-per-square-meter": "Ampère par mètre carré", "ampere-per-meter": "Ampère par mètre", "oersted": "Oersted", - "bohr-magneton": "Magneton de Bohr", + "bohr-magneton": "Magnéton de Bohr", "ampere-meter-squared": "Ampère-mètre carré", "nanovolt": "Nanovolt", "picovolt": "Picovolt", @@ -6316,8 +6343,8 @@ "volt": "Volt", "kilovolt": "Kilovolt", "megavolt": "Mégavolt", - "dbmV": "Décibel-volt", - "dbm": "Décibel-milliwatt", + "dbmV": "Décibel volt", + "dbm": "Décibel-milliwatts", "volt-meter": "Volt-mètre", "kilovolt-meter": "Kilovolt-mètre", "megavolt-meter": "Mégavolt-mètre", @@ -6328,20 +6355,20 @@ "microohm": "Microohm", "milliohm": "Milliohm", "kilohm": "Kilohm", - "megohm": "Mégaohm", - "gigohm": "Gigaohm", + "megohm": "Mégohm", + "gigohm": "Gigoohm", "millihertz": "Millihertz", "hertz": "Hertz", "kilohertz": "Kilohertz", "megahertz": "Mégahertz", "gigahertz": "Gigahertz", - "terahertz": "Térrahertz", - "rpm": "Tours par minute", + "terahertz": "Terahertz", + "rpm": "Révolutions par minute", "candela-per-square-meter": "Candela par mètre carré", "candela": "Candela", "lumen": "Lumen", "lux": "Lux", - "foot-candle": "Pied-bougie", + "foot-candle": "Bougie-pied", "lumen-per-square-meter": "Lumen par mètre carré", "lux-second": "Lux-seconde", "lumen-second": "Lumen-seconde", @@ -6352,18 +6379,18 @@ "millimole": "Millimole", "kilomole": "Kilomole", "mole-per-cubic-meter": "Mole par mètre cube", - "rssi": "Indicateur de puissance du signal reçu (RSSI)", + "rssi": "Indicateur de la puissance du signal reçu", "ppm": "Parties par million", "ppb": "Parties par milliard", "micrograms-per-cubic-meter": "Microgrammes par mètre cube", - "aqi": "Indice de qualité de l'air (AQI)", + "aqi": "AQI", "gram-per-cubic-meter": "Gramme par mètre cube", - "gram-per-kilogram": "Humidité spécifique", + "gram-per-kilogram": "Grammes par kilogramme", "millimeters-per-second": "Millimètres par seconde", - "neper": "Néper", + "neper": "Neper", "bel": "Bel", "decibel": "Décibel", - "meters-per-second-squared": "Mètres par seconde carrée", + "meters-per-second-squared": "Mètres par seconde au carré", "becquerel": "Becquerel", "curie": "Curie", "gray": "Gray", @@ -6395,22 +6422,22 @@ "milligram-per-cubic-meter": "Milligramme par mètre cube", "pound-per-cubic-foot": "Livre par pied cube", "ounces-per-cubic-inch": "Onces par pouce cube", - "tons-per-cubic-yard": "Tonnes par yard cube", - "particle-density": "Densité de particules", + "tons-per-cubic-yard": "Tonnes par mètre cube", + "particle-density": "Densité des particules", "kilometers-per-liter": "Kilomètres par litre", "miles-per-gallon": "Miles par gallon", "liters-per-100-km": "Litres par 100 km", - "gallons-per-mile": "Gallons par mille", + "gallons-per-mile": "Gallons par mile", "liters-per-hour": "Litres par heure", "gallons-per-hour": "Gallons par heure", "beats-per-minute": "Battements par minute", "millimeters-of-mercury": "Millimètres de mercure", "milligrams-per-deciliter": "Milligrammes par décilitre", - "g-force": "Force g", + "g-force": "Force G", "kilonewton": "Kilonewton", - "kilogram-force": "Kilogramme-force", - "pound-force": "Livre-force", - "kilopound-force": "Kilolivre-force", + "kilogram-force": "Force kilogramme", + "pound-force": "Force livre", + "kilopound-force": "Force kilolivre", "dyne": "Dyne", "poundal": "Poundal", "kip": "Kip", @@ -6430,7 +6457,7 @@ "day": "Jour", "week": "Semaine", "month": "Mois", - "year": "Année", + "year": "An", "cubic-foot-per-minute": "Pied cube par minute", "cubic-meters-per-hour": "Mètres cubes par heure", "cubic-meters-per-second": "Mètres cubes par seconde", @@ -6461,9 +6488,9 @@ "gigabyte-per-second": "Gigaoctet par seconde", "degree": "Degré", "radian": "Radian", - "gradian": "Grade", - "arcminute": "Minute d’arc", - "arcsecond": "Seconde d’arc", + "gradian": "Gradian", + "arcminute": "Arcminute", + "arcsecond": "Arcseconde", "milliradian": "Milliradian", "revolution": "Révolution", "siemens": "Siemens", @@ -6480,7 +6507,7 @@ "kilofarad": "Kilofarad", "megafarad": "Mégafarad", "gigafarad": "Gigafarad", - "terfarad": "Térafarad", + "terfarad": "Terafarad", "farad-per-meter": "Farad par mètre", "tesla": "Tesla", "gauss": "Gauss", @@ -6490,7 +6517,7 @@ "nanotesla": "Nanotesla", "kilotesla": "Kilotesla", "megatesla": "Mégatesla", - "millitesla-square-meters": "Millitesla mètre carré", + "millitesla-square-meters": "Millitesla mètres carrés", "gamma": "Gamma", "lambda": "Lambda", "square-meter-per-second": "Mètre carré par seconde", @@ -6507,15 +6534,15 @@ "newton-second-per-square-meter": "Newton-seconde par mètre carré", "dyne-second-per-square-centimeter": "Dyne-seconde par centimètre carré", "kilogram-per-meter-second": "Kilogramme par mètre-seconde", - "tesla-square-meters": "Tesla mètre carré", + "tesla-square-meters": "Tesla mètres carrés", "maxwell": "Maxwell", "tesla-per-meter": "Tesla par mètre", "gauss-per-centimeter": "Gauss par centimètre", "weber": "Weber", "microweber": "Microweber", "milliweber": "Milliweber", - "gauss-square-centimeter": "Gauss centimètre carré", - "kilogauss-square-centimeter": "Kilogauss centimètre carré", + "gauss-square-centimeter": "Gauss-centimètre carré", + "kilogauss-square-centimeter": "Kilogauss-centimètre carré", "henry": "Henry", "millihenry": "Millihenry", "microhenry": "Microhenry", @@ -6532,14 +6559,14 @@ "volts-per-meter": "Volts par mètre", "kilovolts-per-meter": "Kilovolts par mètre", "radian-per-second": "Radian par seconde", - "radian-per-second-squared": "Radian par seconde carrée", + "radian-per-second-squared": "Radian par seconde au carré", "revolutions-per-minute-per-second": "Accélération angulaire", "deg-per-second": "Degrés par seconde", "rotation-per-minute": "Rotation par minute", "degrees-brix": "Degrés Brix", "katal": "Katal", "katal-per-cubic-metre": "Katal par mètre cube", - "paris-inch": "Pouce de Paris" + "paris-inch": "Pouce Paris" }, "user": { "user": "Utilisateur", @@ -6690,26 +6717,26 @@ }, "widget": { "widget-library": "Bibliothèque de widgets", - "widget-bundle": "Pack de widgets", - "all-bundles": "Tous les packs", - "select-widgets-bundle": "Sélectionner un pack de widgets", + "widget-bundle": "Bundle de widgets", + "all-bundles": "Tous les bundles", + "select-widgets-bundle": "Sélectionner un bundle de widgets", "widgets": "Widgets", "all-widgets": "Tous les widgets", "widget": "Widget", "select-widget": "Sélectionner un widget", "no-widgets-matching": "Aucun widget correspondant à '{{entity}}' trouvé.", - "no-widgets": "Aucun widget pour l’instant", + "no-widgets": "Aucun widget pour l'instant", "no-widgets-text": "Aucun widget trouvé", "management": "Gestion des widgets", - "editor": "Éditeur de widgets", - "confirm-to-exit-editor-html": "Vous avez des paramètres de widget non enregistrés.
Êtes-vous sûr de vouloir quitter cette page ?", - "widget-type-not-found": "Problème lors du chargement de la configuration du widget.
Le type de widget associé a probablement été supprimé.", - "widget-type-load-error": "Le widget n’a pas pu être chargé en raison des erreurs suivantes :", + "editor": "Éditeur de widget", + "confirm-to-exit-editor-html": "Vous avez des paramètres de widget non enregistrés.
Êtes-vous sûr de vouloir quitter cette page ?", + "widget-type-not-found": "Problème de chargement de la configuration du widget.
Probablement que le type de widget associé\n a été supprimé.", + "widget-type-load-error": "Le widget n'a pas été chargé en raison des erreurs suivantes :", "remove": "Supprimer le widget", "delete": "Supprimer le widget", "edit": "Éditer le widget", - "remove-widget-title": "Êtes-vous sûr de vouloir supprimer le widget '{{widgetTitle}}' ?", - "remove-widget-text": "Après confirmation, le widget et toutes les données associées seront définitivement perdus.", + "remove-widget-title": "Êtes-vous sûr de vouloir supprimer le widget '{{widgetTitle}}' ?", + "remove-widget-text": "Après confirmation, le widget et toutes les données associées deviendront irrécupérables.", "replace-reference-with-widget-copy": "Remplacer la référence par une copie du widget", "timeseries": "Séries temporelles", "search-data": "Rechercher des données", @@ -6819,30 +6846,30 @@ "open-normal": "Normal", "open-in-separate-dialog": "Ouvrir dans une boîte de dialogue séparée", "open-in-popover": "Ouvrir dans une infobulle", - "dialog-title": "Titre de la boîte de dialogue", - "dialog-hide-dashboard-toolbar": "Masquer la barre d'outils du tableau de bord dans la boîte de dialogue", - "dialog-width": "Largeur de la boîte de dialogue en pourcentage de la largeur de l'écran", - "dialog-height": "Hauteur de la boîte de dialogue en pourcentage de la hauteur de l'écran", - "dialog-size-range-error": "La taille de la boîte de dialogue doit être comprise entre 1 et 100.", - "popover-preferred-placement": "Placement préféré de l'infobulle", + "dialog-title": "Titre du dialogue", + "dialog-hide-dashboard-toolbar": "Masquer la barre d'outils du tableau de bord dans le dialogue", + "dialog-width": "Largeur du dialogue en pourcentage par rapport à la largeur de la fenêtre", + "dialog-height": "Hauteur du dialogue en pourcentage par rapport à la hauteur de la fenêtre", + "dialog-size-range-error": "La valeur en pourcentage de la taille du dialogue doit être comprise entre 1 et 100.", + "popover-preferred-placement": "Placement préféré du popover", "popover-placement-top": "Haut", "popover-placement-topLeft": "Haut gauche", - "popover-placement-topRight": "Haut droit", + "popover-placement-topRight": "Haut droite", "popover-placement-right": "Droite", - "popover-placement-rightTop": "Haut droite", - "popover-placement-rightBottom": "Bas droite", + "popover-placement-rightTop": "Droite haut", + "popover-placement-rightBottom": "Droite bas", "popover-placement-bottom": "Bas", "popover-placement-bottomLeft": "Bas gauche", "popover-placement-bottomRight": "Bas droite", "popover-placement-left": "Gauche", - "popover-placement-leftTop": "Haut gauche", - "popover-placement-leftBottom": "Bas gauche", - "popover-hide-on-click-outside": "Masquer l'infobulle en cliquant à l'extérieur", - "popover-hide-dashboard-toolbar": "Masquer la barre d'outils du tableau de bord dans l'infobulle", - "popover-width": "Largeur de l'infobulle", - "popover-height": "Hauteur de l'infobulle", - "popover-style": "Style de l'infobulle", - "open-new-browser-tab": "Ouvrir dans un nouvel onglet", + "popover-placement-leftTop": "Gauche haut", + "popover-placement-leftBottom": "Gauche bas", + "popover-hide-on-click-outside": "Masquer le popover lors d'un clic en dehors", + "popover-hide-dashboard-toolbar": "Masquer la barre d'outils du tableau de bord dans le popover", + "popover-width": "Largeur du popover", + "popover-height": "Hauteur du popover", + "popover-style": "Style du popover", + "open-new-browser-tab": "Ouvrir dans un nouvel onglet du navigateur", "open-URL": "Ouvrir une URL", "URL": "URL", "url-required": "L'URL est requise.", @@ -6986,15 +7013,15 @@ "column-index-required": "L’index de colonne est requis.", "not-set": "Non défini", "action-name": "Nom", - "action-name-required": "Le nom de l’action est requis.", - "action-name-not-unique": "Une autre action avec le même nom existe déjà.\nLe nom de l’action doit être unique pour une même source.", + "action-name-required": "Le nom de l'action est requis.", + "action-name-not-unique": "Une autre action avec le même nom existe déjà.\nLe nom de l'action doit être unique dans la même source d'action.", "action-icon": "Icône", "header-button": { "button-settings": "Paramètres du bouton", "button-type": "Type de bouton", - "button-type-basic": "Basique", - "button-type-raised": "Surélevé", - "button-type-stroked": "Avec contour", + "button-type-basic": "De base", + "button-type-raised": "Élevé", + "button-type-stroked": "Contourné", "button-type-flat": "Plat", "button-type-icon": "Icône", "button-type-mini-fab": "FAB", @@ -7022,9 +7049,9 @@ "advanced-settings": "Paramètres avancés", "data-settings": "Paramètres de données", "limits": "Limites", - "no-data-display-message": "Message alternatif pour « Aucune donnée à afficher »", - "data-page-size": "Nombre maximal d'entités par source de données", - "settings-component-not-found": "Composant du formulaire de paramètres introuvable pour le sélecteur '{{selector}}'", + "no-data-display-message": "\"Aucune donnée à afficher\" message alternatif", + "data-page-size": "Nombre maximum d'entités par source de données", + "settings-component-not-found": "Composant de formulaire de paramètres non trouvé pour le sélecteur '{{selector}}'", "preview": "Aperçu", "set": "Définir", "set-message": "Définir le message", @@ -8092,7 +8119,7 @@ "knob": { "behavior": "Comportement", "initial-value": "Valeur initiale", - "initial-value-hint": "Action permettant d’obtenir la valeur initiale du bouton rotatif.", + "initial-value-hint": "Action permettant d'obtenir la valeur initiale du bouton rotatif.", "on-value-change": "Lors du changement de valeur", "on-value-change-hint": "Action déclenchée lorsque la valeur du bouton rotatif est modifiée.", "range": "Plage", @@ -9001,7 +9028,7 @@ "pie-chart-card-style": "Style de la carte graphique en secteurs" }, "radar-chart": { - "radar-appearance": "Apparence du radar", + "radar-appearance": "Apparence radar", "shape": "Forme", "shape-polygon": "Polygone", "shape-circle": "Cercle", @@ -9010,13 +9037,13 @@ "points": "Points", "points-label": "Étiquette des points", "radar-axis": "Axe radar", - "axis-label": "Étiquette des axes", + "axis-label": "Étiquette de l'axe", "ticks-label": "Étiquette des graduations", "radar-chart-style": "Style du graphique radar", "max-axes-scaling": "Échelle maximale des axes", - "max-axes-scaling-hint": "Choisissez si chaque axe radar a sa propre valeur maximale (Séparée) ou partage la valeur maximale parmi toutes les axes en fonction des données du widget (Commune).", - "separate": "Séparée", - "common": "Commune" + "max-axes-scaling-hint": "Choisissez si chaque axe radar a sa propre valeur maximale (Séparé) ou partage la valeur la plus élevée de l'ensemble des axes selon les données du widget (Commun).", + "separate": "Séparé", + "common": "Commun" }, "time-series-chart": { "chart": "Graphique", @@ -9222,16 +9249,16 @@ "add-time-series": "Ajouter une série temporelle", "execute-rpc-text": "Exécuter la méthode RPC '{{methodName}}'", "get-time-series-text": "Utiliser la série temporelle '{{key}}'", - "get-attribute-text": "Utiliser l'attribut '{{key}}'", - "get-alarm-status-text": "Utiliser le statut de l'alarme", - "get-dashboard-state-text": "Utiliser l'état du tableau de bord", - "get-dashboard-state-object-text": "Utiliser l'objet d'état du tableau de bord", - "when-dashboard-state-is-text": "Lorsque l'identifiant d'état du tableau de bord est '{{state}}'", - "when-dashboard-state-function-is-text": "Lorsque f(identifiant d'état du tableau de bord) est '{{state}}'", - "when-dashboard-state-object-function-is-text": "Lorsque f(objet d'état du tableau de bord) est '{{state}}'", - "set-attribute-to-value-text": "Définir l'attribut '{{key}}' sur : {{value}}", - "add-time-series-value-text": "Ajouter la valeur {{value}} à la série temporelle '{{key}}'", - "set-attribute-text": "Définir l'attribut '{{key}}'", + "get-attribute-text": "Utiliser l’attribut '{{key}}'", + "get-alarm-status-text": "Utiliser l’état de l’alarme", + "get-dashboard-state-text": "Utiliser l’état du tableau de bord", + "get-dashboard-state-object-text": "Utiliser l’objet d’état du tableau de bord", + "when-dashboard-state-is-text": "Lorsque l’identifiant d’état du tableau de bord est '{{state}}'", + "when-dashboard-state-function-is-text": "Lorsque f(identifiant d’état du tableau de bord) est '{{state}}'", + "when-dashboard-state-object-function-is-text": "Lorsque f(objet d’état du tableau de bord) est '{{state}}'", + "set-attribute-to-value-text": "Définir l’attribut '{{key}}' sur : {{value}}", + "add-time-series-value-text": "Ajouter la valeur de série temporelle '{{key}}' : {{value}}", + "set-attribute-text": "Définir l’attribut '{{key}}'", "add-time-series-text": "Ajouter la série temporelle '{{key}}'", "action": "Action", "value": "Valeur", @@ -9404,7 +9431,7 @@ "sys-admin": { "step1": { "title": "Créer un Locataire et un Administrateur de Locataire", - "content": "

Un locataire est une personne ou une organisation qui possède ou produit des dispositifs et des actifs. Le locataire peut avoir plusieurs administrateurs, clients, dispositifs et actifs.

L'administrateur de locataire peut créer et gérer des dispositifs, actifs, clients et tableaux de bord dans le compte du locataire.

Suivez la documentation pour savoir comment procéder :

", + "content": "

Un locataire est une personne ou une organisation qui possède ou produit des appareils et des actifs. Le locataire peut avoir plusieurs administrateurs, clients, appareils et actifs.

L'administrateur de locataire peut créer et gérer des appareils, actifs, clients et tableaux de bord dans le compte du locataire.

Suivez la documentation pour savoir comment procéder :

", "how-to-create-tenant": "Comment créer un Locataire et un Administrateur de Locataire" }, "step2": { @@ -9432,13 +9459,13 @@ }, "tenant-admin": { "step1": { - "title": "Créer un dispositif", - "content": "

Approvisionnons votre premier dispositif sur la plateforme via l'interface utilisateur. Suivez la documentation pour savoir comment procéder :

", - "how-to-create-device": "Comment créer un dispositif" + "title": "Créer un appareil", + "content": "

Approvisionnons votre premier appareil sur la plateforme via l'interface utilisateur. Suivez la documentation pour savoir comment procéder :

", + "how-to-create-device": "Comment créer un appareil" }, "step2": { - "title": "Connecter le dispositif", - "content-before": "

Pour connecter le dispositif, vous devez obtenir ses identifiants. Nous recommandons d'utiliser les identifiants auto-générés par défaut, à savoir le jeton d'accès pour ce guide.

  • Allez dans le tableau des dispositifs
  • Cliquez sur la ligne du dispositif pour ouvrir les détails
  • Appuyez sur le bouton \"Copier le jeton d'accès\"

Utilisez les commandes simples suivantes pour publier des données via HTTP. N'oubliez pas de remplacer $ACCESS_TOKEN par le jeton d'accès de votre dispositif :

", + "title": "Connecter l’appareil", + "content-before": "

Pour connecter l’appareil, vous devez obtenir ses identifiants. Nous recommandons d'utiliser les identifiants auto-générés par défaut, à savoir le jeton d'accès pour ce guide.

  • Allez dans le tableau des appareils
  • Cliquez sur la ligne de l’appareil pour ouvrir les détails
  • Appuyez sur le bouton \"Copier le jeton d'accès\"

Utilisez les commandes simples suivantes pour publier des données via HTTP. N'oubliez pas de remplacer $ACCESS_TOKEN par le jeton d'accès de votre appareil :

", "ubuntu": { "install-curl": "Installer cURL pour Ubuntu :" }, @@ -9448,13 +9475,13 @@ "windows": { "install-curl": "Depuis Windows 10 b17063, cURL est disponible par défaut." }, - "replace-access-token": "Remplacez $ACCESS_TOKEN par le jeton de votre dispositif :", + "replace-access-token": "Remplacez $ACCESS_TOKEN par le jeton de votre appareil :", "content-after": "

Vous pouvez également utiliser d'autres protocoles tels que MQTT, CoAP, etc.

Suivez la documentation pour savoir comment procéder :

", - "how-to-connect-device": "Comment connecter un dispositif" + "how-to-connect-device": "Comment connecter un appareil" }, "step3": { "title": "Créer un tableau de bord", - "content": "

Créez un tableau de bord pour visualiser les données des entités telles que les dispositifs, les actifs, etc.

Suivez la documentation pour savoir comment procéder :

", + "content": "

Créez un tableau de bord pour visualiser les données des entités telles que les appareils, les actifs, etc.

Suivez la documentation pour savoir comment procéder :

", "how-to-create-dashboard": "Comment créer un tableau de bord" }, "step4": { @@ -9466,13 +9493,13 @@ "step5": { "title": "Créer une alarme", "content-before": "

Pour déclencher l'alarme, envoyez une nouvelle valeur de télémétrie de 26°C ou plus.

", - "replace-access-token": "Remplacez $ACCESS_TOKEN par le jeton de votre dispositif :", + "replace-access-token": "Remplacez $ACCESS_TOKEN par le jeton de votre appareil :", "content-after": "

Suivez la documentation pour savoir comment procéder :

", "how-to-create-alarm": "Comment créer une alarme" }, "step6": { "title": "Créer un client et partager le tableau de bord", - "content": "

En créant des tableaux de bord pour les utilisateurs finaux, un utilisateur client ne peut voir que ses propres dispositifs. Les données d'autres clients lui seront invisibles.

Suivez la documentation pour savoir comment procéder :

" + "content": "

En créant des tableaux de bord pour les utilisateurs finaux, un utilisateur client ne peut voir que ses propres appareils. Les données d'autres clients lui seront invisibles.

Suivez la documentation pour savoir comment procéder :

" } } } @@ -9522,4 +9549,4 @@ "language": { "language": "Langue" } -} +} \ No newline at end of file diff --git a/ui-ngx/src/assets/locale/locale.constant-it_IT.json b/ui-ngx/src/assets/locale/locale.constant-it_IT.json index add8432b40..45f2819123 100644 --- a/ui-ngx/src/assets/locale/locale.constant-it_IT.json +++ b/ui-ngx/src/assets/locale/locale.constant-it_IT.json @@ -237,12 +237,12 @@ "no-oauth2-clients": "Nessun client OAuth 2.0 trovato", "search-oauth2-clients": "Cerca client OAuth 2.0", "delete-client-title": "Sei sicuro di voler eliminare il client OAuth 2.0 '{{clientName}}'?", - "delete-client-text": "Attenzione, dopo la conferma il client e tutti i dati correlati saranno irrimediabilmente persi.", + "delete-client-text": "Attenzione, dopo la conferma il client e tutti i dati correlati diventeranno irrecuperabili.", "delete-mobile-app-title": "Sei sicuro di voler eliminare l'applicazione mobile '{{applicationName}}'?", - "delete-mobile-app-text": "Attenzione, dopo la conferma l'applicazione mobile e tutti i dati correlati saranno irrimediabilmente persi.", + "delete-mobile-app-text": "Attenzione, dopo la conferma l'applicazione mobile e tutti i dati correlati diventeranno irrecuperabili.", "title": "Titolo", "client-title-required": "Il titolo è obbligatorio", - "client-title-max-length": "Il titolo deve essere inferiore a 100 caratteri", + "client-title-max-length": "Il titolo dovrebbe essere lungo meno di 100 caratteri", "advanced-settings": "Impostazioni avanzate", "domain-details": "Dettagli dominio", "no-domains": "Nessun dominio trovato", @@ -440,15 +440,15 @@ "authentication-settings": "Impostazioni di autenticazione", "auth-method": "Metodo di autenticazione", "auth-method-username-password": "Password / token di accesso", - "auth-method-username-password-hint": "Gli utenti GitHub devono usare token di accesso con permessi di scrittura al repository.", + "auth-method-username-password-hint": "Gli utenti di GitHub devono utilizzare i token di accesso con permessi di scrittura sul repository.", "auth-method-private-key": "Chiave privata", "password-access-token": "Password / token di accesso", "change-password-access-token": "Cambia password / token di accesso", "private-key": "Chiave privata", - "drop-private-key-file-or": "Trascina e rilascia un file con chiave privata oppure", - "passphrase": "Passphrase", - "enter-passphrase": "Inserisci passphrase", - "change-passphrase": "Cambia passphrase", + "drop-private-key-file-or": "Trascina e rilascia un file di chiave privata oppure", + "passphrase": "Frase segreta", + "enter-passphrase": "Inserisci la frase segreta", + "change-passphrase": "Cambia la frase segreta", "check-access": "Verifica accesso", "check-repository-access-success": "Accesso al repository verificato con successo!", "delete-repository-settings-title": "Sei sicuro di voler eliminare le impostazioni del repository?", @@ -540,12 +540,18 @@ "resources": "Risorse", "notifications": "Notifiche", "notifications-settings": "Impostazioni notifiche", - "slack-api-token": "Token API Slack", + "slack-api-token": "Token API di Slack", "slack": "Slack", - "slack-settings": "Impostazioni Slack", + "slack-settings": "Impostazioni di Slack", "mobile-settings": "Impostazioni mobile", "firebase-service-account-file": "File JSON delle credenziali dell'account di servizio Firebase", - "select-firebase-service-account-file": "Trascina e rilascia il file delle credenziali dell'account di servizio Firebase oppure " + "select-firebase-service-account-file": "Trascina e rilascia il file delle credenziali dell'account di servizio Firebase oppure", + "trendz": "Trendz", + "trendz-settings": "Impostazioni di Trendz", + "trendz-url": "URL di Trendz", + "trendz-url-required": "L'URL di Trendz è obbligatorio", + "trendz-api-key": "Chiave API di Trendz", + "trendz-enable": "Abilita Trendz" }, "alarm": { "alarm": "Allarme", @@ -671,14 +677,14 @@ "add": "Aggiungi alias", "edit": "Modifica alias", "name": "Nome alias", - "name-required": "Il nome dell'alias è obbligatorio", + "name-required": "Il nome alias è obbligatorio", "duplicate-alias": "Esiste già un alias con lo stesso nome.", - "filter-type-single-entity": "Singola entità", - "filter-type-entity-list": "Lista di entità", + "filter-type-single-entity": "Entità singola", + "filter-type-entity-list": "Elenco di entità", "filter-type-entity-name": "Nome entità", - "filter-type-entity-type": "Tipo entità", - "filter-type-state-entity": "Entità da stato della dashboard", - "filter-type-state-entity-description": "Entità presa dai parametri dello stato della dashboard", + "filter-type-entity-type": "Tipo di entità", + "filter-type-state-entity": "Entità dallo stato del dashboard", + "filter-type-state-entity-description": "Entità presa dai parametri dello stato del dashboard", "filter-type-asset-type": "Tipo di asset", "filter-type-asset-type-description": "Asset di tipo '{{assetTypes}}'", "filter-type-asset-type-and-name-description": "Asset di tipo '{{assetTypes}}' con nome che inizia con '{{prefix}}'", @@ -704,39 +710,40 @@ "filter-type-apiUsageState": "Stato utilizzo API", "entity-filter": "Filtro entità", "resolve-multiple": "Risolvi come entità multiple", - "resolve-multiple-hint": "Abilita per visualizzare dati da tutte le entità filtrate simultaneamente.\nSe disabilitato, il widget mostra i dati della sola entità selezionata.", + "resolve-multiple-hint": "Abilita per visualizzare i dati di tutte le entità filtrate contemporaneamente. \nSe disabilitato, il widget mostrerà solo i dati dell'entità selezionata.", "filter-type": "Tipo di filtro", "filter-type-required": "Il tipo di filtro è obbligatorio.", "entity-filter-no-entity-matched": "Nessuna entità corrispondente al filtro specificato trovata.", "no-entity-filter-specified": "Nessun filtro entità specificato", - "root-state-entity": "Usa entità stato dashboard come radice", - "last-level-relation": "Recupera solo ultima relazione di livello", + "root-state-entity": "Usa l'entità dello stato del dashboard come root", + "last-level-relation": "Recupera solo la relazione dell'ultimo livello", "root-entity": "Entità radice", "state-entity-parameter-name": "Nome parametro entità stato", "default-state-entity": "Entità stato predefinita", - "default-entity-parameter-name": "Predefinito", - "max-relation-level": "Livello massimo relazione", + "default-entity-parameter-name": "Per impostazione predefinita", + "query-options": "Opzioni di query", + "max-relation-level": "Livello massimo di relazione", "unlimited-level": "Livello illimitato", - "state-entity": "Entità stato della dashboard", + "state-entity": "Entità stato del dashboard", "all-entities": "Tutte le entità", "any-relation": "qualsiasi" }, "asset": { "asset": "Asset", - "assets": "Asset", - "management": "Gestione asset", + "assets": "Assets", + "management": "Gestione degli asset", "view-assets": "Visualizza asset", "add": "Aggiungi asset", - "asset-type-max-length": "Il tipo di asset deve essere inferiore a 256 caratteri", + "asset-type-max-length": "Il tipo di asset deve essere inferiore a 256", "assign-to-customer": "Assegna al cliente", - "assign-asset-to-customer": "Assegna asset al cliente", + "assign-asset-to-customer": "Assegna Asset(i) al Cliente", "assign-asset-to-customer-text": "Seleziona gli asset da assegnare al cliente", "no-assets-text": "Nessun asset trovato", - "assign-to-customer-text": "Seleziona il cliente a cui assegnare l'asset", + "assign-to-customer-text": "Seleziona il cliente a cui assegnare gli asset", "public": "Pubblico", "assignedToCustomer": "Assegnato al cliente", - "make-public": "Rendi pubblico l'asset", - "make-private": "Rendi privato l'asset", + "make-public": "Rendi asset pubblico", + "make-private": "Rendi asset privato", "unassign-from-customer": "Rimuovi assegnazione dal cliente", "delete": "Elimina asset", "asset-public": "L'asset è pubblico", @@ -859,11 +866,11 @@ "alarm": "Allarme", "alarms-created": "Allarmi creati", "queue-stats": "Statistiche coda", - "processing-failures-and-timeouts": "Errori e timeout di elaborazione", + "processing-failures-and-timeouts": "Errori di elaborazione e timeout", "exceptions": "Eccezioni", - "alarms-created-daily-activity": "Attività giornaliera allarmi creati", - "alarms-created-hourly-activity": "Attività oraria allarmi creati", - "alarms-created-monthly-activity": "Attività mensile allarmi creati", + "alarms-created-daily-activity": "Attività giornaliera di allarmi creati", + "alarms-created-hourly-activity": "Attività oraria di allarmi creati", + "alarms-created-monthly-activity": "Attività mensile di allarmi creati", "data-points": "Punti dati", "data-points-storage-days": "Giorni di conservazione dei punti dati", "device-api": "API dispositivo", @@ -908,31 +915,36 @@ "telemetry-persistence-hourly-activity": "Attività oraria persistenza telemetria", "telemetry-persistence-monthly-activity": "Attività mensile persistenza telemetria", "transport": "Trasporto", - "transport-daily-activity": "Attività giornaliera trasporto", - "transport-data-points": "Punti dati trasporto", - "transport-hourly-activity": "Attività oraria trasporto", - "transport-messages": "Messaggi trasporto", - "transport-monthly-activity": "Attività mensile trasporto", + "transport-daily-activity": "Attività giornaliera del trasporto", + "transport-data-points": "Punti dati del trasporto", + "transport-hourly-activity": "Attività oraria del trasporto", + "transport-messages": "Messaggi del trasporto", + "transport-monthly-activity": "Attività mensile del trasporto", "view-details": "Visualizza dettagli", "view-statistics": "Visualizza statistiche" }, "api-limit": { - "cassandra-queries": "Query Cassandra", + "cassandra-write-queries-core": "Query di scrittura Cassandra tramite Rest API", + "cassandra-read-queries-core": "Query di lettura Cassandra tramite Rest API e WS telemetry", + "cassandra-write-queries-rule-engine": "Query di scrittura Cassandra della telemetria Rule Engine", + "cassandra-read-queries-rule-engine": "Query di lettura Cassandra della telemetria Rule Engine", + "cassandra-write-queries-monolith": "Query di scrittura Cassandra della telemetria Monolith", + "cassandra-read-queries-monolith": "Query di lettura Cassandra della telemetria Monolith", "entity-version-creation": "Creazione versione entità", "entity-version-load": "Caricamento versione entità", "notification-requests": "Richieste di notifica", "notification-requests-per-rule": "Richieste di notifica per regola", "rest-api-requests": "Richieste REST API", "rest-api-requests-per-customer": "Richieste REST API per cliente", - "transport-messages": "Messaggi trasporto", - "transport-messages-per-device": "Messaggi trasporto per dispositivo", - "transport-messages-per-gateway": "Messaggi trasporto per gateway", - "transport-messages-per-gateway-device": "Messaggi trasporto per dispositivo gateway", + "transport-messages": "Messaggi di trasporto", + "transport-messages-per-device": "Messaggi di trasporto per dispositivo", + "transport-messages-per-gateway": "Messaggi di trasporto per gateway", + "transport-messages-per-gateway-device": "Messaggi di trasporto per dispositivo gateway", "ws-updates-per-session": "Aggiornamenti WS per sessione", - "edge-events": "Eventi edge", - "edge-events-per-edge": "Eventi per edge", - "edge-uplink-messages": "Messaggi uplink edge", - "edge-uplink-messages-per-edge": "Messaggi uplink per edge" + "edge-events": "Eventi Edge", + "edge-events-per-edge": "Eventi Edge per nodo Edge", + "edge-uplink-messages": "Messaggi uplink Edge", + "edge-uplink-messages-per-edge": "Messaggi uplink Edge per nodo Edge" }, "audit-log": { "audit": "Audit", @@ -1025,7 +1037,7 @@ "argument-asset": "Asset", "argument-customer": "Cliente", "argument-tenant": "Tenant corrente", - "argument-type": "Tipo argomento", + "argument-type": "Tipo di argomento", "see-debug-events": "Vedi eventi di debug", "attribute": "Attributo", "copy-argument-name": "Copia nome argomento", @@ -1057,10 +1069,11 @@ "delete-multiple-title": "Sei sicuro di voler eliminare { count, plural, =1 {1 campo calcolato} other {# campi calcolati} }?", "delete-multiple-text": "Attenzione, dopo la conferma tutti i campi calcolati selezionati saranno eliminati e tutti i dati correlati saranno irrimediabilmente persi.", "test-with-this-message": "Testa con questo messaggio", + "use-latest-timestamp": "Usa il timestamp più recente", "hint": { - "arguments-simple-with-rolling": "Il campo calcolato di tipo semplice non deve contenere chiavi con tipo rolling su serie temporale.", + "arguments-simple-with-rolling": "Il campo calcolato di tipo semplice non deve contenere chiavi con tipo rolling delle serie temporali.", "arguments-empty": "Gli argomenti non devono essere vuoti.", - "expression-required": "L'espressione è obbligatoria.", + "expression-required": "Espressione obbligatoria.", "expression-invalid": "Espressione non valida", "expression-max-length": "La lunghezza dell'espressione deve essere inferiore a 255 caratteri.", "argument-name-required": "Il nome dell'argomento è obbligatorio.", @@ -1068,13 +1081,110 @@ "argument-name-duplicate": "Esiste già un argomento con questo nome.", "argument-name-max-length": "Il nome dell'argomento deve essere inferiore a 256 caratteri.", "argument-name-forbidden": "Il nome dell'argomento è riservato e non può essere utilizzato.", - "argument-type-required": "Il tipo dell'argomento è obbligatorio.", + "argument-type-required": "Il tipo di argomento è obbligatorio.", "max-args": "Numero massimo di argomenti raggiunto.", - "decimals-range": "I decimali di default devono essere un numero compreso tra 0 e 15.", - "expression": "L'espressione di default dimostra come trasformare una temperatura da Fahrenheit a Celsius.", - "arguments-entity-not-found": "Entità di destinazione dell'argomento non trovata." + "decimals-range": "Per impostazione predefinita, i decimali devono essere un numero compreso tra 0 e 15.", + "expression": "L'espressione predefinita dimostra come trasformare una temperatura da Fahrenheit a Celsius.", + "arguments-entity-not-found": "Entità di destinazione dell'argomento non trovata.", + "use-latest-timestamp": "Se abilitato, il valore calcolato verrà salvato utilizzando il timestamp più recente dalla telemetria degli argomenti, invece dell'orario del server." } }, + "ai-models": { + "ai-models": "Modelli AI", + "ai-model": "Modello AI", + "model": "Modello", + "name": "Nome", + "ai-provider": "Fornitore AI", + "no-found": "Nessun modello AI trovato", + "list": "{ count, plural, =1 {Un modello} other {Elenco di # modelli} }", + "selected-fields": "{ count, plural, =1 {1 modello} other {# modelli} } selezionati", + "add": "Aggiungi modello", + "delete-model-title": "Sei sicuro di voler eliminare il modello '{{modelName}}'?", + "delete-model-text": "Attenzione, dopo la conferma il modello e tutti i dati correlati diventeranno irrecuperabili.", + "delete-models-title": "Sei sicuro di voler eliminare { count, plural, =1 {1 modello} other {# modelli} }?", + "delete-models-text": "Attenzione, dopo la conferma tutti i modelli selezionati verranno rimossi e tutti i dati correlati diventeranno irrecuperabili.", + "ai-providers": { + "openai": "OpenAI", + "azure-openai": "Azure OpenAI", + "google-ai-gemini": "Google AI Gemini", + "google-vertex-ai-gemini": "Google Vertex AI Gemini", + "mistral-ai": "Mistral AI", + "anthropic": "Anthropic", + "amazon-bedrock": "Amazon Bedrock", + "github-models": "Modelli GitHub", + "ollama": "Ollama" + }, + "name-required": "Il nome è obbligatorio.", + "name-max-length": "Il nome deve contenere al massimo 255 caratteri.", + "provider": "Provider", + "api-key": "Chiave API", + "api-key-required": "La chiave API è obbligatoria.", + "api-key-open-ai-required": "La chiave API è obbligatoria quando si utilizza l'API ufficiale di OpenAI.", + "project-id": "ID progetto", + "project-id-required": "L'ID progetto è obbligatorio.", + "location": "Località", + "location-required": "La località è obbligatoria.", + "service-account-key-file": "File della chiave dell'account di servizio", + "service-account-key-file-required": "Il file della chiave dell'account di servizio è obbligatorio.", + "no-file": "Nessun file selezionato.", + "drop-file": "Trascina un file o clicca per selezionare un file da caricare.", + "personal-access-token": "Token di accesso personale", + "personal-access-token-required": "Il token di accesso personale è obbligatorio.", + "configuration": "Configurazione", + "model-id": "ID modello", + "model-id-required": "L'ID del modello è obbligatorio.", + "deployment-name": "Nome del deployment", + "deployment-name-required": "Il nome del deployment è obbligatorio.", + "set": "Imposta", + "region": "Regione", + "region-required": "La regione è obbligatoria.", + "access-key-id": "ID chiave di accesso", + "access-key-id-required": "L'ID della chiave di accesso è obbligatorio.", + "secret-access-key": "Chiave di accesso segreta", + "secret-access-key-required": "La chiave di accesso segreta è obbligatoria.", + "temperature": "Temperatura", + "temperature-hint": "Regola il livello di casualità nell'output del modello. Valori più alti aumentano la casualità, mentre valori più bassi la riducono.", + "temperature-min": "Deve essere maggiore o uguale a 0.", + "top-p": "Top P", + "top-p-hint": "Crea un insieme dei token più probabili tra cui il modello può scegliere. Valori più alti creano un insieme più ampio e variegato, mentre quelli più bassi lo restringono.", + "top-p-min-max": "Deve essere maggiore di 0 e al massimo 1.", + "top-k": "Top K", + "top-k-hint": "Limita le scelte del modello a un insieme fisso dei \"K\" token più probabili.", + "top-k-min": "Deve essere maggiore o uguale a 0.", + "presence-penalty": "Penalità di presenza", + "presence-penalty-hint": "Applica una penalità fissa alla probabilità di un token se è già apparso nel testo.", + "frequency-penalty": "Penalità di frequenza", + "frequency-penalty-hint": "Applica una penalità alla probabilità di un token in base alla sua frequenza nel testo.", + "max-output-tokens": "Numero massimo di token in output", + "max-output-tokens-hint": "Imposta il numero massimo di token che il\nmodello può generare in una singola risposta.", + "context-length": "Lunghezza del contesto", + "context-length-hint": "Definisce la dimensione della finestra di contesto in token. Questo valore imposta il limite totale di memoria per il modello, includendo sia l'input dell'utente che la risposta generata.", + "endpoint": "Endpoint", + "endpoint-required": "L'endpoint è obbligatorio.", + "baseurl": "URL base", + "baseurl-required": "L'URL base è obbligatorio.", + "service-version": "Versione del servizio", + "check-connectivity": "Verifica connettività", + "check-connectivity-success": "La richiesta di test è andata a buon fine", + "check-connectivity-failed": "La richiesta di test non è riuscita", + "no-model-matching": "Nessun modello corrispondente a '{{entity}}' trovato.", + "model-required": "Il modello è obbligatorio.", + "no-model-text": "Nessun modello trovato.", + "authentication": "Autenticazione", + "authentication-basic-hint": "Utilizza l'autenticazione HTTP Basic standard. Il nome utente e la password verranno combinati, codificati in Base64 e inviati in un'intestazione \"Authorization\" con ogni richiesta al server Ollama.", + "authentication-token-hint": "Utilizza l'autenticazione con token Bearer. Il token fornito verrà inviato direttamente in un'intestazione \"Authorization\" con ogni richiesta al server Ollama.", + "authentication-type": { + "none": "Nessuna", + "basic": "Basic", + "token": "Token" + }, + "username": "Nome utente", + "username-required": "Il nome utente è obbligatorio.", + "password": "Password", + "password-required": "La password è obbligatoria.", + "token": "Token", + "token-required": "Il token è obbligatorio." + }, "confirm-on-exit": { "message": "Hai modifiche non salvate. Sei sicuro di voler lasciare questa pagina?", "html-message": "Hai modifiche non salvate.
Sei sicuro di voler lasciare questa pagina?", @@ -1236,15 +1346,15 @@ "assign-dashboard-to-customer-text": "Seleziona le dashboard da assegnare al cliente", "assign-to-customer-text": "Seleziona il cliente a cui assegnare la dashboard", "assign-to-customer": "Assegna al cliente", - "unassign-from-customer": "Disassegna dal cliente", + "unassign-from-customer": "Rimuovi assegnazione dal cliente", "make-public": "Rendi dashboard pubblica", "make-private": "Rendi dashboard privata", "manage-assigned-customers": "Gestisci clienti assegnati", "assigned-customers": "Clienti assegnati", "assign-to-customers": "Assegna dashboard ai clienti", "assign-to-customers-text": "Seleziona i clienti a cui assegnare la dashboard", - "unassign-from-customers": "Disassegna dashboard dai clienti", - "unassign-from-customers-text": "Seleziona i clienti da cui disassegnare la dashboard", + "unassign-from-customers": "Rimuovi dashboard dai clienti", + "unassign-from-customers-text": "Seleziona i clienti da cui rimuovere la dashboard", "no-dashboards-text": "Nessuna dashboard trovata", "no-widgets": "Nessun widget configurato", "add-widget": "Aggiungi nuovo widget", @@ -1724,7 +1834,7 @@ "type-number": "Numero", "type-switch": "Interruttore", "type-select": "Selezione", - "type-radios": "Pulsanti radio", + "type-radios": "Pulsanti di scelta", "type-datetime": "Data/Ora", "type-image": "Immagine", "type-javascript": "JavaScript", @@ -1747,13 +1857,14 @@ "remove-property": "Rimuovi proprietà", "default-value": "Valore predefinito", "value-required": "Valore richiesto", - "number-settings": "Impostazioni numeriche", + "number-settings": "Impostazioni numero", "min": "Min", "max": "Max", "step": "Passo", "selected-options-limit": "Limite opzioni selezionate", "advanced-ui-settings": "Impostazioni UI avanzate", "disable-on-property": "Disabilita in base alla proprietà", + "disable-on-property-none": "Nessuna (campo sempre abilitato)", "display-condition-function": "Funzione di condizione di visualizzazione", "sub-label": "Sotto etichetta", "vertical-divider-after": "Divisore verticale dopo", @@ -1787,7 +1898,8 @@ "array-item": "Elemento dell'array", "item-type": "Tipo di elemento", "item-name": "Nome dell'elemento", - "no-items": "Nessun elemento" + "no-items": "Nessun elemento", + "support-unit-conversion": "Supporta la conversione delle unità" }, "clear-form": "Cancella modulo", "clear-form-prompt": "Sei sicuro di voler rimuovere tutte le proprietà del modulo?", @@ -1795,7 +1907,7 @@ "export-form": "Esporta modulo in JSON", "json-file": "File JSON", "json-content": "Contenuto JSON", - "invalid-form-json-file-error": "Impossibile importare il modulo da JSON: struttura dei dati JSON non valida." + "invalid-form-json-file-error": "Impossibile importare il modulo da JSON: struttura dei dati JSON del modulo non valida." }, "asset-profile": { "asset-profile": "Profilo asset", @@ -1896,21 +2008,22 @@ "set-default-device-profile-text": "Dopo la conferma, il profilo dispositivo sarà impostato come predefinito e verrà utilizzato per i nuovi dispositivi senza profilo specificato.", "no-device-profiles-found": "Nessun profilo dispositivo trovato.", "create-new-device-profile": "Creane uno nuovo!", - "mqtt-device-topic-filters": "Filtri topic dispositivo MQTT", - "mqtt-device-topic-filters-unique": "I filtri topic del dispositivo MQTT devono essere unici.", - "mqtt-device-topic-filters-spark-plug": "Nodo Edge of Network (EoN) MQTT Sparkplug B.", - "mqtt-device-topic-filters-spark-plug-hint": "Consente connessioni da nodi EoN con payload e formato topic Sparkplug B.", + "mqtt-device-topic-filters": "Filtri dei topic MQTT del dispositivo", + "mqtt-device-topic-filters-unique": "I filtri dei topic MQTT del dispositivo devono essere unici.", + "mqtt-device-topic-filters-spark-plug": "Nodo Sparkplug B Edge of Network (EoN) MQTT.", + "mqtt-device-topic-filters-spark-plug-hint": "Consente connessioni dai nodi EoN con payload e formato dei topic Sparkplug B.", "mqtt-device-topic-filters-spark-plug-attribute-metric-names": "Metriche SparkPlug da salvare come attributi.", - "mqtt-device-topic-filters-spark-plug-attribute-metric-names-hint": "Nomi delle metriche SparkPlug che verranno salvate come attributi del dispositivo. Tutte le altre metriche saranno archiviate come telemetria.", - "mqtt-device-payload-type": "Payload dispositivo MQTT", + "mqtt-device-topic-filters-spark-plug-attribute-metric-names-hint": "Nomi delle metriche SparkPlug che verranno salvate come attributi del dispositivo. Tutte le altre metriche verranno salvate come telemetria del dispositivo.", + "mqtt-device-payload-type": "Payload MQTT del dispositivo", "mqtt-device-payload-type-json": "JSON", "mqtt-device-payload-type-proto": "Protobuf", - "mqtt-enable-compatibility-with-json-payload-format": "Abilita compatibilità con altri formati payload.", - "mqtt-enable-compatibility-with-json-payload-format-hint": "Se abilitato, la piattaforma utilizzerà di default il formato payload Protobuf. In caso di errore di parsing, tenterà di utilizzare il formato JSON. Utile per la retrocompatibilità durante aggiornamenti firmware. Modalità soggetta a un leggero degrado delle prestazioni.", - "mqtt-use-json-format-for-default-downlink-topics": "Usa formato Json per topic di downlink predefiniti", - "mqtt-use-json-format-for-default-downlink-topics-hint": "Usato per inviare attributi e RPC via Json su v1/devices/me/.... Non influisce sui topic v2.", - "mqtt-send-ack-on-validation-exception": "Invia PUBACK in caso di errore di validazione PUBLISH", - "mqtt-send-ack-on-validation-exception-hint": "Se abilitato, invia l'acknowledgment invece di chiudere la sessione MQTT in caso di errore di validazione.", + "mqtt-enable-compatibility-with-json-payload-format": "Abilita la compatibilità con altri formati di payload.", + "mqtt-enable-compatibility-with-json-payload-format-hint": "Quando abilitato, la piattaforma utilizzerà il formato di payload Protobuf come predefinito. Se l'analisi fallisce, la piattaforma tenterà di utilizzare il formato di payload JSON. Utile per la compatibilità retroattiva durante gli aggiornamenti firmware. Ad esempio, la versione iniziale del firmware utilizza JSON, mentre la nuova versione utilizza Protobuf. Durante il processo di aggiornamento del firmware della flotta di dispositivi, è necessario supportare contemporaneamente sia Protobuf che JSON. La modalità di compatibilità introduce un leggero degrado delle prestazioni, perciò si consiglia di disabilitarla una volta aggiornati tutti i dispositivi.", + "mqtt-use-json-format-for-default-downlink-topics": "Utilizza il formato JSON per i topic downlink predefiniti", + "mqtt-use-json-format-for-default-downlink-topics-hint": "Quando abilitato, la piattaforma utilizzerà il formato JSON per inviare attributi e RPC tramite i seguenti topic: v1/devices/me/attributes/response/$request_id, v1/devices/me/attributes, v1/devices/me/rpc/request/$request_id, v1/devices/me/rpc/response/$request_id. Questa impostazione non influisce sulle sottoscrizioni di attributi e RPC inviate tramite i nuovi topic (v2): v2/a/res/$request_id, v2/a, v2/r/req/$request_id, v2/r/res/$request_id. Dove $request_id è un identificatore di richiesta intero.", + "mqtt-send-ack-on-validation-exception": "Invia PUBACK in caso di errore di validazione del messaggio PUBLISH", + "mqtt-send-ack-on-validation-exception-hint": "Per impostazione predefinita, la piattaforma chiuderà la sessione MQTT in caso di fallimento della validazione del messaggio. Quando abilitato, la piattaforma invierà un acknowledgment di pubblicazione anziché chiudere la sessione.", + "mqtt-protocol-version": "Versione del protocollo", "snmp-add-mapping": "Aggiungi mapping SNMP", "snmp-mapping-not-configured": "Nessun mapping OID configurato per time series/telemetria", "snmp-timseries-or-attribute-name": "Nome time series/attributo per mapping", @@ -2171,24 +2284,27 @@ "add-lwm2m-server-config": "Aggiungi server LwM2M", "no-config-servers": "Nessun server configurato", "others-tab": "Altre impostazioni", - "client-strategy": "Strategia client alla connessione", + "ota-update": "Aggiornamento OTA", + "use-object-19-for-ota-update": "Usa l'Oggetto 19 per i metadati dei file OTA (checksum, dimensione, versione, nome)", + "use-object-19-for-ota-update-hint": "Utilizza Resource ObjectId = 19 per gli aggiornamenti OTA: FirmWare → InstanceId = 65534, SoftWare → InstanceId = 65535. Il formato dei dati è JSON codificato in Base64. Questo JSON contiene i metadati del file OTA (informazioni del file): \"Checksum\" (SHA256). Campi aggiuntivi: \"Title\" (nome OTA), \"Version\" (versione OTA), \"File Name\" (nome file per archiviare l’OTA sul client), \"File Size\" (dimensione OTA in byte).", + "client-strategy": "Strategia del client durante la connessione", "client-strategy-label": "Strategia", - "client-strategy-only-observe": "Solo richiesta di osservazione dopo la connessione iniziale", - "client-strategy-read-all": "Leggi tutte le risorse e invia richiesta di osservazione dopo la registrazione", + "client-strategy-only-observe": "Solo richiesta Observe al client dopo la connessione iniziale", + "client-strategy-read-all": "Leggi tutte le risorse e invia una richiesta Observe al client dopo la registrazione", "fw-update": "Aggiornamento firmware", "fw-update-strategy": "Strategia di aggiornamento firmware", - "fw-update-strategy-data": "Invia aggiornamento come file binario usando Oggetto 19, Risorsa 0 (Data)", - "fw-update-strategy-package": "Invia aggiornamento come file binario usando Oggetto 5, Risorsa 0 (Package)", - "fw-update-strategy-package-uri": "Genera URL CoAP univoco e invia aggiornamento come Oggetto 5, Risorsa 1 (Package URI)", + "fw-update-strategy-data": "Invia l’aggiornamento firmware come file binario utilizzando l'Oggetto 19 e la Risorsa 0 (Data)", + "fw-update-strategy-package": "Invia l’aggiornamento firmware come file binario utilizzando l'Oggetto 5 e la Risorsa 0 (Package)", + "fw-update-strategy-package-uri": "Genera automaticamente un URL CoAP univoco per scaricare il pacchetto e invia l’aggiornamento firmware tramite Oggetto 5 e Risorsa 1 (Package URI)", "sw-update": "Aggiornamento software", "sw-update-strategy": "Strategia di aggiornamento software", - "sw-update-strategy-package": "Invia file binario usando Oggetto 9, Risorsa 2 (Package)", - "sw-update-strategy-package-uri": "Genera URL CoAP univoco per scaricare il pacchetto e invia aggiornamento usando Oggetto 9, Risorsa 3 (Package URI)", - "fw-update-resource": "Risorsa CoAP aggiornamento firmware", - "fw-update-resource-required": "Risorsa CoAP aggiornamento firmware obbligatoria.", - "sw-update-resource": "Risorsa CoAP aggiornamento software", - "sw-update-resource-required": "Risorsa CoAP aggiornamento software obbligatoria.", - "config-json-tab": "Configurazione JSON profilo dispositivo", + "sw-update-strategy-package": "Invia il file binario utilizzando l'Oggetto 9 e la Risorsa 2 (Package)", + "sw-update-strategy-package-uri": "Genera automaticamente un URL CoAP univoco per scaricare il pacchetto e invia l’aggiornamento software tramite Oggetto 9 e Risorsa 3 (Package URI)", + "fw-update-resource": "Risorsa CoAP per aggiornamento firmware", + "fw-update-resource-required": "La risorsa CoAP per l’aggiornamento firmware è obbligatoria.", + "sw-update-resource": "Risorsa CoAP per aggiornamento software", + "sw-update-resource-required": "La risorsa CoAP per l’aggiornamento software è obbligatoria.", + "config-json-tab": "Profilo dispositivo JSON", "attributes-name": { "min-period": "Periodo minimo", "max-period": "Periodo massimo", @@ -2198,10 +2314,20 @@ "min-evaluation-period": "Periodo minimo di valutazione", "max-evaluation-period": "Periodo massimo di valutazione" }, - "default-object-id": "Versione oggetto predefinita (Attributo)", + "default-object-id": "Versione predefinita dell'Oggetto (Attributo)", "default-object-id-ver": { "v1-0": "1.0", - "v1-1": "1.1" + "v1-1": "1.1", + "v1-2": "1.2" + }, + "observe-strategy": { + "observe-strategy": "Strategia Observe", + "single": "Singola", + "single-description": "Una richiesta Observe per risorsa (maggiore precisione, più traffico di rete)", + "composite-all": "Composita globale", + "composite-all-description": "Tutte le risorse sono osservate con un’unica richiesta Composite Observe (più efficiente, meno flessibile)", + "composite-by-object": "Composita per oggetti", + "composite-by-object-description": "Le risorse sono raggruppate per tipo di oggetto e osservate tramite richieste Composite Observe separate (approccio bilanciato)" } }, "snmp": { @@ -2514,16 +2640,18 @@ "type-rulechains": "Catene di regole", "list-of-rulechains": "{ count, plural, =1 {Una catena di regole} other {Elenco di # catene di regole} }", "rulechain-name-starts-with": "Catene di regole i cui nomi iniziano con '{{prefix}}'", - "type-rulenode": "Nodo regola", - "type-rulenodes": "Nodi regola", - "list-of-rulenodes": "{ count, plural, =1 {Un nodo regola} other {Elenco di # nodi regola} }", - "rulenode-name-starts-with": "Nodi regola i cui nomi iniziano con '{{prefix}}'", + "type-rulenode": "Nodo rule", + "type-rulenodes": "Nodi rule", + "list-of-rulenodes": "{ count, plural, =1 {Un nodo rule} other {Elenco di # nodi rule} }", + "rulenode-name-starts-with": "Nodi rule i cui nomi iniziano con '{{prefix}}'", "type-current-customer": "Cliente corrente", "type-current-tenant": "Tenant corrente", "type-current-user": "Utente corrente", - "type-current-user-owner": "Proprietario utente corrente", + "type-current-user-owner": "Proprietario dell’utente corrente", "type-calculated-field": "Campo calcolato", "type-calculated-fields": "Campi calcolati", + "type-ai-model": "Modello AI", + "type-ai-models": "Modelli AI", "type-widgets-bundle": "Pacchetto widget", "type-widgets-bundles": "Pacchetti widget", "list-of-widgets-bundles": "{ count, plural, =1 {Un pacchetto widget} other {Elenco di # pacchetti widget} }", @@ -2553,6 +2681,8 @@ "type-tb-resources": "Risorse", "list-of-tb-resources": "{ count, plural, =1 {Una risorsa} other {Elenco di # risorse} }", "type-ota-package": "Pacchetto OTA", + "type-ota-packages": "Pacchetti OTA", + "list-of-ota-packages": "{ count, plural, =1 {Un pacchetto OTA} other {Elenco di # pacchetti OTA} }", "type-rpc": "RPC", "type-queue": "Coda", "type-queue-stats": "Statistiche coda", @@ -2700,9 +2830,9 @@ "timeseries-placeholder": "Serie temporali", "target-entity": "Entità di destinazione", "attributes-propagation": "Propagazione degli attributi", - "attributes-propagation-hint": "La vista entità copierà automaticamente gli attributi specificati dall'entità di destinazione ogni volta che viene salvata o aggiornata. Per motivi di prestazioni, gli attributi dell'entità di destinazione non vengono propagati ad ogni modifica. È possibile abilitare la propagazione automatica configurando un nodo 'copy to view' nella catena di regole e collegando i messaggi 'Post attributes' e 'Attributes Updated' a tale nodo.", - "timeseries-data": "Dati serie temporali", - "timeseries-data-hint": "Configura le chiavi di dati delle serie temporali dell'entità di destinazione accessibili alla vista entità. Questi dati sono di sola lettura.", + "attributes-propagation-hint": "La Entity View copierà automaticamente gli attributi specificati dall’entità di destinazione ogni volta che salvi o aggiorni questa entity view. Per motivi di prestazioni, gli attributi dell’entità di destinazione non vengono propagati alla entity view a ogni modifica degli attributi. Puoi abilitare la propagazione automatica configurando il rule node \"copy to view\" nella tua rule chain e collegando i messaggi \"Post attributes\" e \"Attributes Updated\" al nuovo rule node.", + "timeseries-data": "Dati delle serie temporali", + "timeseries-data-hint": "Configura le chiavi delle serie temporali dell’entità di destinazione che saranno accessibili alla entity view. Questi dati delle serie temporali sono di sola lettura.", "search": "Cerca viste entità", "selected-entity-views": "{ count, plural, =1 {1 vista entità} other {# viste entità} } selezionate", "assign-entity-view-to-edge": "Assegna vista(e) entità all'Edge", @@ -2933,11 +3063,12 @@ "duplicate-filter": "Esiste già un filtro con lo stesso nome.", "filters": "Filtri", "unable-delete-filter-title": "Impossibile eliminare il filtro", - "unable-delete-filter-text": "Il filtro '{{filter}}' non può essere eliminato poiché è utilizzato dai seguenti widget:
{{widgetsList}}", - "duplicate-filter-error": "Filtro duplicato trovato '{{filter}}'.
I filtri devono essere univoci all'interno della dashboard.", - "missing-key-filters-error": "I filtri chiave sono mancanti per il filtro '{{filter}}'.", + "unable-delete-filter-text": "Il filtro '{{filter}}' non può essere eliminato perché è utilizzato dai seguenti widget:
{{widgetsList}}", + "duplicate-filter-error": "Trovato filtro duplicato '{{filter}}'.
I filtri devono essere unici all’interno della dashboard.", + "missing-key-filters-error": "Mancano i key filters per il filtro '{{filter}}'.", "filter": "Filtro", "editable": "Modificabile", + "editable-hint": "Consenti all’utente di modificare il valore del filtro nelle dashboard.", "no-filters-found": "Nessun filtro trovato.", "no-filter-text": "Nessun filtro specificato", "add-filter-prompt": "Aggiungi un filtro", @@ -2974,19 +3105,21 @@ "complex-filter": "Filtro complesso", "edit-complex-filter": "Modifica filtro complesso", "edit-filter-user-params": "Modifica parametri utente predicato filtro", - "filter-user-params": "Parametri utente predicato filtro", + "filter-user-params": "Parametri utente del predicato del filtro", "user-parameters": "Parametri utente", "display-label": "Etichetta da visualizzare", - "order-priority": "Priorità di ordinamento del campo", + "custom-label": "Etichetta personalizzata", + "custom-label-hint": "Abilita per impostare un’etichetta personalizzata per il filtro. Se disabilitato, l’etichetta verrà generata automaticamente.", + "order-priority": "Ordine di visualizzazione", "key-filter": "Filtro chiave", "key-filters": "Filtri chiave", "key-name": "Nome chiave", - "key-name-required": "Il nome chiave è obbligatorio.", + "key-name-required": "Il nome della chiave è obbligatorio.", "key-type": { "key-type": "Tipo di chiave", "attribute": "Attributo", - "timeseries": "Serie temporale", - "entity-field": "Campo entità", + "timeseries": "Serie temporali", + "entity-field": "Campo dell’entità", "constant": "Costante", "client-attribute": "Attributo client", "server-attribute": "Attributo server", @@ -3021,7 +3154,8 @@ "switch-to-dynamic-value": "Passa al valore dinamico", "switch-to-default-value": "Passa al valore predefinito", "inherit-owner": "Eredita dal proprietario", - "source-attribute-not-set": "Se l'attributo sorgente non è impostato" + "source-attribute-not-set": "Se l’attributo sorgente non è impostato", + "unit": "Unità" }, "fullscreen": { "expand": "Espandi a schermo intero", @@ -3404,12 +3538,13 @@ "temperature-step": "Incremento della temperatura", "heat-pump-color": "Colore della pompa di calore", "power-button-background": "Sfondo del pulsante di accensione", - "value-box-background": "Sfondo del riquadro del valore", - "value-units": "Unità di valore", + "value-box-background": "Sfondo della casella del valore", + "value-units": "Unità del valore", + "enable-units-scale": "Abilita le unità sulla scala", "filtration-mode": "Modalità di filtrazione", - "filtration-mode-hint": "Valore intero che indica la modalità di filtrazione attuale.", - "filtration-mode-update": "Stato aggiornamento modalità di filtrazione", - "filtration-mode-update-hint": "Azione eseguita quando l'utente clicca per cambiare la modalità di filtrazione attuale.", + "filtration-mode-hint": "Valore intero che indica la modalità di filtrazione corrente.", + "filtration-mode-update": "Aggiornamento della modalità di filtrazione", + "filtration-mode-update-hint": "Azione eseguita quando l’utente fa clic per modificare la modalità di filtrazione corrente.", "filter-mode": "Filtro", "waste-mode": "Scarico", "backwash-mode": "Controlavaggio", @@ -3719,18 +3854,20 @@ "invalid-version-pattern": "Formato versione non valido. Usa il formato: major.minor.patch (es. 1.0.0).", "mobile-center": "Centro mobile", "mobile-package": "Pacchetto applicazione", - "mobile-package-max-length": "Il pacchetto applicazione deve contenere meno di 256 caratteri", - "mobile-package-required": "Pacchetto applicazione richiesto.", - "mobile-package-pattern": "Formato pacchetto applicazione non valido", + "mobile-package-max-length": "Il pacchetto applicazione deve essere inferiore a 256 caratteri", + "mobile-package-required": "Il pacchetto applicazione è obbligatorio.", + "mobile-package-pattern": "Formato non valido per il pacchetto applicazione", + "mobile-package-title": "Titolo applicazione", + "mobile-package-title-max-length": "Il titolo dell’applicazione deve essere inferiore a 256 caratteri", "no-application": "Nessuna applicazione trovata", - "no-bundles": "Nessun pacchetto trovato", + "no-bundles": "Nessun bundle trovato", "platform-type": "Tipo di piattaforma", "search-application": "Cerca applicazioni", - "search-bundles": "Cerca pacchetti", + "search-bundles": "Cerca bundle", "set": "Imposta", - "sha256-certificate-fingerprints": "Impronta certificato SHA256", - "sha256-certificate-fingerprints-required": "Impronta certificato SHA256 richiesta", - "sha256-certificate-fingerprints-pattern": "Formato impronta SHA256 non valido", + "sha256-certificate-fingerprints": "Impronte del certificato SHA256", + "sha256-certificate-fingerprints-required": "Le impronte del certificato SHA256 sono obbligatorie", + "sha256-certificate-fingerprints-pattern": "Formato non valido per l’impronta del certificato SHA256", "show-hidden-pages": "Mostra pagine nascoste", "status": "Stato", "status-type": { @@ -3791,68 +3928,66 @@ "url": "URL", "invalid-url-format": "Formato URL non valido", "path": "Percorso", - "invalid-path-format": "Formato del percorso non valido", + "invalid-path-format": "Formato percorso non valido", "custom-page": "Pagina personalizzata", "edit-page": "Modifica pagina", "edit-custom-page": "Modifica pagina personalizzata", "delete-page": "Elimina pagina", "qr-code-widget": "Widget codice QR", "type-here": "Digita qui", - "configuration-dialog": "Finestra di configurazione", - "configuration-app": "App di configurazione", + "configuration-dialog": "Dialogo di configurazione", + "configuration-app": "Configurazione app", "configuration-step": { - "prepare-environment-title": "Prepara l'ambiente di sviluppo", - "prepare-environment-text": "L'app mobile Flutter ThingsBoard richiede Flutter SDK. Segui le istruzioni per configurare Flutter SDK.", - "get-source-code-title": "Ottieni il codice sorgente dell'app", - "get-source-code-text": "Puoi ottenere il codice sorgente dell'app mobile Flutter ThingsBoard clonandolo dal repository GitHub:", - "configure-api-title": "Configura endpoint API di ThingsBoard", - "configure-api-text": "Apri il progetto flutter_thingsboard_pe_app nel tuo editor/IDE. Modifica:", - "configure-api-hint": "Imposta il valore della costante thingsBoardApiEndpoint per corrispondere all'endpoint API della tua istanza ThingsBoard. Non utilizzare gli hostname 'localhost' o '127.0.0.1'.", - "run-app-title": "Esegui l'app", - "run-app-text": "Esegui l'app come descritto nel tuo IDE.\nSe usi il terminale, esegui il comando seguente:", - "more-information": "Informazioni dettagliate disponibili nella nostra documentazione introduttiva.", - "getting-started": "Guida introduttiva", - "configure-package-title": "Configura il pacchetto dell'applicazione", - "configure-package-text": "Puoi modificare manualmente il pacchetto dell'applicazione o usare uno strumento CLI di terze parti.", - "configure-package-text-install": "Per installare lo strumento CLI Rename, esegui il seguente comando:", - "configure-package-run-commands": "Esegui questi comandi nella directory root del tuo progetto:" + "prepare-environment-title": "Prepara l’ambiente di sviluppo", + "prepare-environment-text": "L’applicazione mobile Flutter ThingsBoard richiede il Flutter SDK. Segui le istruzioni per configurare il Flutter SDK.", + "get-source-code-title": "Ottieni il codice sorgente dell’app", + "get-source-code-text": "Puoi ottenere il codice sorgente dell’applicazione mobile Flutter ThingsBoard clonandolo dal repository GitHub:", + "configure-app-settings-title": "Configura le impostazioni dell’app", + "configure-app-settings-text": "Scarica il file di configurazione e posizionalo nella directory principale del progetto che hai clonato nel passaggio precedente.", + "download-file": "Scarica file", + "run-app-title": "Esegui l’app", + "run-app-text": "Esegui l’app come indicato nel tuo IDE.\nSe utilizzi il terminale, esegui l’app con il seguente comando:", + "more-information": "Puoi trovare informazioni dettagliate nella nostra documentazione Getting Started.", + "getting-started": "Getting Started" } }, "notification": { "action-button": "Pulsante di azione", "action-type": "Tipo di azione", "active": "Attivo", - "add-notification-recipients-group": "Aggiungi gruppo destinatari notifica", - "add-notification-template": "Aggiungi modello di notifica", + "add-notification-recipients-group": "Aggiungi gruppo di destinatari notifiche", + "add-notification-template": "Aggiungi template di notifica", "add-recipient": "Aggiungi destinatario", "add-recipients": "Aggiungi destinatari", "add-rule": "Aggiungi regola", "add-stage": "Aggiungi fase", - "add-template": "Aggiungi modello", + "add-template": "Aggiungi template", "after": "Dopo", "alarm-assignment-trigger-settings": "Impostazioni trigger assegnazione allarme", "alarm-comment-trigger-settings": "Impostazioni trigger commento allarme", "alarm-trigger-settings": "Impostazioni trigger allarme", "all": "Tutti", - "api-feature-hint": "Se il campo è vuoto, il trigger sarà applicato a tutte le funzionalità API", + "api-feature-hint": "Se il campo è vuoto, il trigger verrà applicato a tutte le funzionalità API", "api-usage-trigger-settings": "Impostazioni trigger utilizzo API", "new-platform-version-trigger-settings": "Impostazioni trigger nuova versione piattaforma", - "rate-limits-trigger-settings": "Impostazioni trigger superamento limiti", + "rate-limits-trigger-settings": "Impostazioni trigger superamento limiti di velocità", "task-processing-failure-trigger-settings": "Impostazioni trigger errore elaborazione attività", - "at-least-one-should-be-selected": "Almeno uno deve essere selezionato", - "basic-settings": "Impostazioni di base", - "button-text": "Testo pulsante", + "resources-shortage-trigger-settings": "Impostazioni trigger carenza di risorse", + "at-least-one-should-be-selected": "Deve essere selezionato almeno uno", + "basic-settings": "Impostazioni base", + "button-text": "Testo del pulsante", "button-text-required": "Il testo del pulsante è obbligatorio", - "button-text-max-length": "Il testo del pulsante deve essere lungo al massimo {{ length }} caratteri", + "button-text-max-length": "Il testo del pulsante deve essere minore o uguale a {{ length }} caratteri", "compose": "Componi", "conversation": "Conversazione", "conversation-required": "La conversazione è obbligatoria", - "copy-notification-template": "Copia modello di notifica", + "copy-notification-template": "Copia template di notifica", "copy-rule": "Copia regola", - "copy-template": "Copia modello", + "copy-template": "Copia template", "create-new": "Crea nuovo", "created": "Creato", "customize-messages": "Personalizza messaggi", + "cpu-threshold": "Soglia CPU", "delete-notification-text": "Attenzione, dopo la conferma la notifica non sarà più recuperabile.", "delete-notification-title": "Sei sicuro di voler eliminare la notifica?", "delete-notifications-text": "Attenzione, dopo la conferma le notifiche non saranno più recuperabili.", @@ -3889,36 +4024,37 @@ "mobile-app": "App mobile", "mobile-app-preview": "Anteprima notifica app mobile" }, - "delivery-method-not-configure-click": "Metodo di consegna non configurato. Clicca per configurarlo.", - "delivery-method-not-configure-contact": "Metodo di consegna non configurato. Contatta l'amministratore di sistema.", + "delivery-method-not-configure-click": "Il metodo di consegna non è configurato. Clicca per configurarlo.", + "delivery-method-not-configure-contact": "Il metodo di consegna non è configurato. Contatta l’amministratore di sistema.", "delivery-methods": "Metodi di consegna", "description": "Descrizione", "device-activity-trigger-settings": "Impostazioni trigger attività dispositivo", - "device-list-rule-hint": "Se il campo è vuoto, il trigger sarà applicato a tutti i dispositivi", - "device-profiles-list-rule-hint": "Se il campo è vuoto, il trigger sarà applicato a tutti i profili dispositivo", + "device-list-rule-hint": "Se il campo è vuoto, il trigger verrà applicato a tutti i dispositivi", + "device-profiles-list-rule-hint": "Se il campo è vuoto, il trigger verrà applicato a tutti i profili dispositivo", "disabled": "Disabilitato", - "edge-trigger-settings": "Impostazioni trigger edge", - "edge-list-rule-hint": "Se il campo è vuoto, il trigger sarà applicato a tutte le istanze edge", - "edit-notification-recipients-group": "Modifica gruppo destinatari notifica", - "edit-notification-template": "Modifica modello di notifica", + "edge-trigger-settings": "Impostazioni trigger Edge", + "edge-list-rule-hint": "Se il campo è vuoto, il trigger verrà applicato a tutte le istanze Edge", + "edit-notification-recipients-group": "Modifica gruppo destinatari notifiche", + "edit-notification-template": "Modifica template notifica", "edit-rule": "Modifica regola", - "edit-template": "Modifica modello", + "edit-template": "Modifica template", "enabled": "Abilitato", "entities-limit-trigger-settings": "Impostazioni trigger limite entità", - "entity-action-trigger-settings": "Impostazioni trigger azione entità", - "entity-type": "Tipo entità", + "entity-action-trigger-settings": "Impostazioni trigger azioni entità", + "entity-type": "Tipo di entità", "escalation-chain": "Catena di escalation", - "failed-send": "Errori di invio", + "failed-send": "Invii non riusciti", "fails": "{ count, plural, =1 {1 errore} other {# errori} }", "filter": "Filtro", "first-recipient": "Primo destinatario", "inactive": "Inattivo", "inbox": "Posta in arrivo", "notification-inbox": "Notifiche / Posta in arrivo", - "input-field-support-templatization": "Il campo di input supporta la templatizzazione.", - "input-fields-support-templatization": "I campi di input supportano la templatizzazione.", + "input-field-support-templatization": "Il campo di input supporta la templificazione.", + "input-fields-support-templatization": "I campi di input supportano la templificazione.", "link": "Link", "link-required": "Il link è obbligatorio", + "link-max-length": "Il link deve essere inferiore o uguale a {{ length }} caratteri", "link-type": { "dashboard": "Apri dashboard", "link": "Apri URL" @@ -3929,22 +4065,23 @@ "mark-as-read": "Segna come letta", "message": "Messaggio", "message-required": "Il messaggio è obbligatorio", - "message-max-length": "Il messaggio deve contenere al massimo {{ length }} caratteri", + "message-max-length": "Il messaggio deve essere inferiore o uguale a {{ length }} caratteri", "name": "Nome", "name-required": "Il nome è obbligatorio", "new-notification": "Nuova notifica", "no-inbox-notification": "Nessuna notifica trovata", "no-notification-request": "Nessuna richiesta di notifica", - "no-notification-templates": "Nessun modello di notifica trovato", - "no-notifications-yet": "Nessuna notifica al momento", - "no-recipients-notification": "Nessuna notifica di destinatari", + "no-notification-templates": "Nessun template di notifica trovato", + "no-notifications-yet": "Ancora nessuna notifica", + "no-recipients-notification": "Nessun destinatario della notifica", "no-recipients-matching": "Nessun destinatario corrispondente a '{{entity}}' trovato.", "no-recipients-text": "Nessun destinatario trovato", "no-rule": "Nessuna regola configurata", "no-rules-notification": "Nessuna regola di notifica", - "no-severity-found": "Nessuna gravità trovata", - "no-severity-matching": "'{{severity}}' non trovata.", + "no-severity-found": "Nessuna severità trovata", + "no-severity-matching": "'{{severity}}' non trovato.", "no-template-matching": "Nessuna risorsa corrispondente a '{{template}}' trovata.", + "create-new-template": "Creane uno nuovo!", "not-found-slack-recipient": "Destinatario Slack non trovato", "notification": "Notifica", "notification-center": "Centro notifiche", @@ -3961,15 +4098,16 @@ "unassigned": "Allarme non assegnato" }, "notify-on": "Notifica su", - "notify-on-comment-update": "Notifica su aggiornamento commento", - "notify-on-required": "Campo 'Notifica su' obbligatorio", - "notify-on-unassign": "Notifica su disassegnazione", - "notify-only-user-comments": "Notifica solo commenti utente", - "only-rule-chain-lifecycle-failures": "Solo fallimenti del ciclo di vita della rule chain", - "only-rule-node-lifecycle-failures": "Solo fallimenti del ciclo di vita del nodo", - "platform-users": "Utenti piattaforma", + "notify-on-comment-update": "Notifica sull’aggiornamento dei commenti", + "notify-on-required": "Il campo 'Notifica su' è obbligatorio", + "notify-on-unassign": "Notifica sulla rimozione dell’assegnazione", + "notify-only-user-comments": "Notifica solo i commenti degli utenti", + "only-rule-chain-lifecycle-failures": "Solo i fallimenti del ciclo di vita della rule chain", + "only-rule-node-lifecycle-failures": "Solo i fallimenti del ciclo di vita del rule node", + "platform-users": "Utenti della piattaforma", + "ram-threshold": "Soglia RAM", "rate-limits": "Limiti di velocità", - "rate-limits-hint": "Se il campo è vuoto, il trigger sarà applicato a tutti i limiti", + "rate-limits-hint": "Se il campo è vuoto, il trigger verrà applicato a tutti i limiti di velocità", "recipient": "Destinatario", "recipient-group": "Gruppo destinatari", "recipient-type": { @@ -4032,13 +4170,14 @@ }, "start-from-scratch": "Inizia da zero", "status": "Stato", - "stop-escalation-alarm-status-become": "Ferma l'escalation quando lo stato dell'allarme diventa:", + "stop-escalation-alarm-status-become": "Interrompi l’escalation quando lo stato dell’allarme diventa:", + "storage-threshold": "Soglia di archiviazione", "subject": "Oggetto", - "subject-required": "L'oggetto è obbligatorio", - "subject-max-length": "L'oggetto deve contenere al massimo {{ length }} caratteri", - "template": "Modello", - "template-name": "Nome modello", - "template-required": "Il modello è obbligatorio", + "subject-required": "L’oggetto è obbligatorio", + "subject-max-length": "L’oggetto deve essere inferiore o uguale a {{ length }} caratteri", + "template": "Template", + "template-name": "Nome template", + "template-required": "Il template è obbligatorio", "template-type": { "alarm": "Allarme", "alarm-assignment": "Assegnazione allarme", @@ -4048,13 +4187,14 @@ "entities-limit": "Limite entità", "entity-action": "Azione entità", "general": "Generale", - "rule-engine-lifecycle-event": "Evento ciclo di vita rule engine", - "rule-node": "Nodo regola", - "new-platform-version": "Nuova versione piattaforma", - "rate-limits": "Limiti superati", - "edge-communication-failure": "Errore comunicazione edge", - "edge-connection": "Connessione edge", - "task-processing-failure": "Errore elaborazione attività" + "rule-engine-lifecycle-event": "Evento ciclo di vita Rule Engine", + "rule-node": "Rule node", + "new-platform-version": "Nuova versione della piattaforma", + "rate-limits": "Superamento limiti di velocità", + "edge-communication-failure": "Errore di comunicazione Edge", + "edge-connection": "Connessione Edge", + "task-processing-failure": "Errore elaborazione attività", + "resources-shortage": "Carenza risorse" }, "templates": "Modelli", "notification-templates": "Notifiche / Modelli", @@ -4072,12 +4212,13 @@ "device-activity": "Attività dispositivo", "entities-limit": "Limite entità", "entity-action": "Azione entità", - "rule-engine-lifecycle-event": "Evento ciclo di vita rule engine", + "rule-engine-lifecycle-event": "Evento ciclo di vita Rule Engine", "new-platform-version": "Nuova versione della piattaforma", - "rate-limits": "Limiti superati", - "edge-connection": "Connessione edge", - "edge-communication-failure": "Errore comunicazione edge", + "rate-limits": "Superamento limiti di velocità", + "edge-connection": "Connessione Edge", + "edge-communication-failure": "Errore di comunicazione Edge", "task-processing-failure": "Errore elaborazione attività", + "resources-shortage": "Carenza risorse", "trigger": "Trigger", "trigger-required": "Il trigger è obbligatorio" }, @@ -4112,14 +4253,15 @@ "assign-firmware-required": "Il firmware assegnato è obbligatorio", "assign-software": "Software assegnato", "assign-software-required": "Il software assegnato è obbligatorio", - "auto-generate-checksum": "Genera automaticamente checksum", + "auto-generate-checksum": "Genera automaticamente il checksum", "checksum": "Checksum", "checksum-hint": "Se il checksum è vuoto, verrà generato automaticamente", "checksum-algorithm": "Algoritmo di checksum", - "checksum-copied-message": "Checksum del pacchetto copiato negli appunti", - "change-firmware": "La modifica del firmware può causare l'aggiornamento di { count, plural, =1 {1 dispositivo} other {# dispositivi} }.", - "change-software": "La modifica del software può causare l'aggiornamento di { count, plural, =1 {1 dispositivo} other {# dispositivi} }.", - "chose-compatible-device-profile": "Il pacchetto caricato sarà disponibile solo per dispositivi con il profilo selezionato.", + "checksum-copied-message": "Il checksum del pacchetto è stato copiato negli appunti", + "change-firmware": "La modifica del firmware può causare l’aggiornamento di { count, plural, =1 {1 dispositivo} other {# dispositivi} }.", + "change-software": "La modifica del software può causare l’aggiornamento di { count, plural, =1 {1 dispositivo} other {# dispositivi} }.", + "change-ota-setting-title": "Sei sicuro di voler modificare le impostazioni OTA?", + "chose-compatible-device-profile": "Il pacchetto caricato sarà disponibile solo per i dispositivi con il profilo selezionato.", "chose-firmware-distributed-device": "Scegli il firmware da distribuire ai dispositivi", "chose-software-distributed-device": "Scegli il software da distribuire ai dispositivi", "content-type": "Tipo di contenuto", @@ -4185,9 +4327,9 @@ "current-password": "Password attuale", "copy-jwt-token": "Copia token JWT", "jwt-token": "Token JWT", - "token-valid-till": "Token valido fino a", - "tokenCopiedSuccessMessage": "Token JWT copiato negli appunti", - "tokenCopiedWarnMessage": "Il token JWT è scaduto! Per favore, ricarica la pagina." + "token-valid-till": "Il token è valido fino a", + "tokenCopiedSuccessMessage": "Il token JWT è stato copiato negli appunti", + "tokenCopiedWarnMessage": "Il token JWT è scaduto! Aggiorna la pagina." }, "profiles": { "profiles": "Profili" @@ -4313,7 +4455,8 @@ "remove-filter": "Rimuovi filtro", "add-relation-filter": "Aggiungi filtro di relazione", "any-relation": "Qualsiasi relazione", - "relation-filters": "Filtri di relazione", + "relation-filters": "Filtri relazione", + "relation-filter": "Filtro relazione", "additional-info": "Informazioni aggiuntive (JSON)", "invalid-additional-info": "Impossibile analizzare il JSON delle informazioni aggiuntive.", "no-relations-text": "Nessuna relazione trovata", @@ -4354,15 +4497,21 @@ "jks": "JKS", "js-module": "Modulo JS", "lwm2m-model": "Modello LWM2M", - "pkcs-12": "PKCS #12" + "pkcs-12": "PKCS #12", + "general": "Generale" }, - "resource-sub-type": "Sottotipo", + "resource-sub-type": "Sotto-tipo", "sub-type": { - "image": "immagine", + "image": "Immagine", "scada-symbol": "Simbolo SCADA", "extension": "Estensione", "module": "Modulo" - } + }, + "resource-is-in-use": "La risorsa è utilizzata da altre entità", + "resources-are-in-use": "Le risorse sono utilizzate da altre entità", + "resource-is-in-use-text": "La risorsa '{{title}}' non è stata eliminata perché utilizzata dalle seguenti entità:", + "resources-are-in-use-text": "Non tutte le risorse sono state eliminate perché utilizzate da altre entità.
È possibile visualizzare le entità referenziate facendo clic sul pulsante Riferimenti nella riga corrispondente della risorsa.
Se desideri comunque eliminare queste risorse, selezionale nella tabella sottostante e fai clic sul pulsante Elimina selezionate.", + "delete-resource-in-use-text": "Se desideri comunque eliminare la risorsa, fai clic sul pulsante Elimina comunque." }, "javascript": { "add": "Aggiungi risorsa JavaScript", @@ -4620,9 +4769,9 @@ "update-attributes-only-on-value-change": "Salva attributi solo se il valore cambia", "update-attributes-only-on-value-change-hint": "Aggiorna gli attributi ad ogni messaggio, indipendentemente dal fatto che il valore sia cambiato. Aumenta l'uso delle API e riduce le prestazioni.", "update-attributes-only-on-value-change-hint-enabled": "Aggiorna gli attributi solo se il valore è cambiato. Se il valore non cambia, non verrà inviato alcun aggiornamento né notifica.", - "fetch-credentials-to-metadata": "Recupera credenziali nei metadati", - "notify-device-on-update-hint": "Se abilitato, forza la notifica al dispositivo dell’aggiornamento di attributi condivisi. Se disabilitato, il comportamento dipende dal parametro 'notifyDevice' nei metadati del messaggio.", - "notify-device-on-delete-hint": "Se abilitato, forza la notifica al dispositivo della rimozione di attributi condivisi. Se disabilitato, il comportamento dipende dal parametro 'notifyDevice' nei metadati.", + "fetch-credentials-to-metadata": "Recupera le credenziali nei metadata", + "notify-device-on-update-hint": "Se abilitato, forza la notifica al dispositivo riguardo l’aggiornamento degli attributi condivisi. Se disabilitato, il comportamento della notifica è controllato dal parametro 'notifyDevice' nei metadata del messaggio in ingresso. Per disattivare la notifica, i metadata del messaggio devono contenere il parametro 'notifyDevice' impostato su 'false'. Qualsiasi altro caso attiverà la notifica al dispositivo.", + "notify-device-on-delete-hint": "Se abilitato, forza la notifica al dispositivo riguardo la rimozione degli attributi condivisi. Se disabilitato, il comportamento della notifica è controllato dal parametro 'notifyDevice' nei metadata del messaggio in ingresso. Per attivare la notifica, i metadata del messaggio devono contenere il parametro 'notifyDevice' impostato su 'true'. In qualsiasi altro caso, la notifica non verrà inviata al dispositivo.", "latest-timeseries": "Chiavi serie temporali più recenti", "timeseries-keys": "Chiavi serie temporali", "timeseries-keys-required": "Deve essere selezionata almeno una chiave della serie temporale.", @@ -4702,13 +4851,13 @@ "fields-mapping-hint": "Se il campo messaggio è impostato su $entityId, l'id dell’origine sarà salvato nella colonna specificata.", "relations-query-config-direction-suffix": "originatore", "profile-name": "Nome profilo", - "fetch-circle-parameter-info-from-metadata-hint": "Il campo metadati '{{perimeterKeyName}}' deve essere definito con il formato: {\"latitude\":48.196, \"longitude\":24.6532, \"radius\":100.0, \"radiusUnit\":\"METER\"}", - "fetch-poligon-parameter-info-from-metadata-hint": "Il campo metadati '{{perimeterKeyName}}' deve essere definito con il formato: [[48.19736,24.65235],[48.19800,24.65060],...,[48.19849,24.65420]]", - "short-templatization-tooltip": "Usa $[messageKey] per estrarre valore dal messaggio e ${metadataKey} dai metadati.", - "fields-mapping-required": "Deve essere specificata almeno una mappatura di campo.", - "at-least-one-field-required": "Deve essere fornito almeno un valore per un campo di input.", - "originator-fields-sv-map-hint": "I campi chiave di destinazione supportano la templatizzazione. Usa $[messageKey] o ${metadataKey}.", - "sv-map-hint": "Solo i campi chiave di destinazione supportano la templatizzazione. Usa $[messageKey] o ${metadataKey}.", + "fetch-circle-parameter-info-from-metadata-hint": "Il campo metadata '{{perimeterKeyName}}' deve essere definito nel seguente formato: {\"latitude\":48.196, \"longitude\":24.6532, \"radius\":100.0, \"radiusUnit\":\"METER\"}", + "fetch-poligon-parameter-info-from-metadata-hint": "Il campo metadata '{{perimeterKeyName}}' deve essere definito nel seguente formato: [[48.19736,24.65235],[48.19800,24.65060],...,[48.19849,24.65420]]", + "short-templatization-tooltip": "Usa $[messageKey] per estrarre il valore dal messaggio e ${metadataKey} per estrarre il valore dai metadata.", + "fields-mapping-required": "È necessario specificare almeno una mappatura dei campi.", + "at-least-one-field-required": "Almeno un campo di input deve avere un valore.", + "originator-fields-sv-map-hint": "I campi della chiave di destinazione supportano la templificazione. Usa $[messageKey] per estrarre il valore dal messaggio e ${metadataKey} per estrarre il valore dai metadata.", + "sv-map-hint": "Solo i campi della chiave di destinazione supportano la templificazione. Usa $[messageKey] per estrarre il valore dal messaggio e ${metadataKey} per estrarre il valore dai metadata.", "source-field": "Campo sorgente", "source-field-required": "Campo sorgente richiesto.", "originator-source": "Origine dell’origine", @@ -4902,10 +5051,10 @@ "credentials-anonymous": "Anonimo", "credentials-basic": "Base", "credentials-pem": "PEM", - "credentials-pem-hint": "È richiesto almeno il file del certificato CA del server o una coppia di file certificato e chiave privata del client", - "credentials-sas": "Firma di accesso condivisa", - "sas-key": "Chiave SAS", - "sas-key-required": "Chiave SAS richiesta.", + "credentials-pem-hint": "È richiesto almeno il file del certificato Server CA oppure una coppia formata da certificato client e chiave privata client", + "credentials-sas": "Shared Access Signature", + "sas-key": "SAS Key", + "sas-key-required": "La SAS Key è obbligatoria.", "hostname": "Nome host", "hostname-required": "Nome host richiesto.", "azure-ca-cert": "File certificato CA", @@ -5012,8 +5161,8 @@ "longitude-field-name": "Nome campo longitudine", "latitude-field-name-required": "Nome campo latitudine richiesto.", "longitude-field-name-required": "Nome campo longitudine richiesto.", - "fetch-perimeter-info-from-metadata": "Recupera informazioni perimetro dai metadati", - "fetch-perimeter-info-from-metadata-tooltip": "Se il tipo di perimetro è 'Poligono', il valore del campo metadati '{{perimeterKeyName}}' sarà usato come definizione del perimetro senza ulteriori analisi. Se è 'Cerchio', il valore verrà analizzato per estrarre i campi 'latitude', 'longitude', 'radius', 'radiusUnit' per la definizione del cerchio.", + "fetch-perimeter-info-from-metadata": "Recupera le informazioni del perimetro dai metadata", + "fetch-perimeter-info-from-metadata-tooltip": "Se il tipo di perimetro è impostato su 'Polygon', il valore del campo metadata '{{perimeterKeyName}}' verrà utilizzato come definizione del perimetro senza ulteriori elaborazioni. Altrimenti, se il tipo di perimetro è impostato su 'Circle', il valore del campo metadata '{{perimeterKeyName}}' verrà analizzato per estrarre i campi 'latitude', 'longitude', 'radius', 'radiusUnit' utilizzati per definire il perimetro circolare.", "perimeter-key-name": "Nome chiave perimetro", "perimeter-key-name-hint": "Nome campo metadati contenente le informazioni sul perimetro.", "perimeter-key-name-required": "Nome chiave perimetro richiesto.", @@ -5063,7 +5212,7 @@ "persist-alarm-rules": "Memorizza stato delle regole allarme", "persist-alarm-rules-hint": "Se abilitato, il nodo regola salverà lo stato dell'elaborazione nel database.", "fetch-alarm-rules": "Recupera stato delle regole allarme", - "fetch-alarm-rules-hint": "Se abilitato, il nodo regola ripristinerà lo stato dell'elaborazione all'inizializzazione e garantirà che gli allarmi vengano generati anche dopo riavvii del server.", + "fetch-alarm-rules-hint": "Se abilitato, il rule node ripristinerà lo stato di elaborazione all’inizializzazione e garantirà che gli allarmi vengano generati anche dopo i riavvii del server. Altrimenti, lo stato verrà ripristinato quando arriverà il primo messaggio dal dispositivo.", "input-value-key": "Chiave valore di input", "input-value-key-required": "Chiave del valore di input richiesta.", "output-value-key": "Chiave del valore di output", @@ -5208,19 +5357,19 @@ "add-key": "Aggiungi chiave", "recipients": "Destinatari", "message-subject-and-content": "Oggetto e contenuto del messaggio", - "template-rules-hint": "Entrambi i campi supportano la templatizzazione. Usa $[messageKey] per estrarre dal messaggio e ${metadataKey} dai metadati.", - "originator-customer-desc": "Usa il cliente dell'origine come nuovo originatore.", - "originator-tenant-desc": "Usa il tenant attuale come nuovo originatore.", - "originator-related-entity-desc": "Usa un'entità correlata come nuovo originatore. Ricerca basata su tipo e direzione della relazione.", - "originator-alarm-originator-desc": "Usa l'origine dell'allarme come nuovo originatore. Solo se l'origine del messaggio è un'entità di allarme.", - "originator-entity-by-name-pattern-desc": "Usa l'entità recuperata dal DB come nuovo originatore. Ricerca basata su tipo e modello di nome.", - "email-from-template-hint": "Usa $[messageKey] per estrarre dal messaggio e ${metadataKey} dai metadati.", - "recipients-block-main-hint": "Lista di indirizzi separati da virgole. Tutti i campi supportano la templatizzazione.", - "forward-msg-default-rule-chain": "Inoltra messaggio alla regola predefinita dell'origine", - "forward-msg-default-rule-chain-tooltip": "Se abilitato, il messaggio sarà inoltrato alla regola predefinita dell'origine o a quella configurata.", - "exclude-zero-deltas": "Escludi delta zero dal messaggio in uscita", - "exclude-zero-deltas-hint": "Se abilitato, la chiave \"{{outputValueKey}}\" sarà aggiunta solo se il valore non è zero.", - "exclude-zero-deltas-time-difference-hint": "Se abilitato, le chiavi \"{{outputValueKey}}\" e \"{{periodValueKey}}\" saranno aggiunte solo se \"{{outputValueKey}}\" non è zero.", + "template-rules-hint": "Entrambi i campi di input supportano la templificazione. Usa $[messageKey] per estrarre il valore dal messaggio e ${metadataKey} per estrarre il valore dai metadata del messaggio.", + "originator-customer-desc": "Utilizza il customer dell’originatore del messaggio in ingresso come nuovo originatore.", + "originator-tenant-desc": "Utilizza il tenant corrente come nuovo originatore.", + "originator-related-entity-desc": "Utilizza l’entità correlata come nuovo originatore. La ricerca si basa sul tipo di relazione configurato e sulla direzione.", + "originator-alarm-originator-desc": "Utilizza l’originatore dell’allarme come nuovo originatore. Solo se l’originatore del messaggio in ingresso è un’entità allarme.", + "originator-entity-by-name-pattern-desc": "Utilizza l’entità recuperata dal DB come nuovo originatore. La ricerca si basa sul tipo di entità e sul pattern del nome specificato.", + "email-from-template-hint": "Usa $[messageKey] per estrarre il valore dal messaggio e ${metadataKey} per estrarre il valore dai metadata.", + "recipients-block-main-hint": "Elenco di indirizzi separati da virgola. Tutti i campi di input supportano la templificazione. Usa $[messageKey] per estrarre il valore dal messaggio e ${metadataKey} per estrarre il valore dai metadata.", + "forward-msg-default-rule-chain": "Inoltra il messaggio alla default rule chain dell’originatore", + "forward-msg-default-rule-chain-tooltip": "Se abilitato, il messaggio verrà inoltrato alla default rule chain dell’originatore o alla rule chain dalla configurazione, se l’originatore non ha una default rule chain definita nel profilo dell’entità.", + "exclude-zero-deltas": "Escludi delta pari a zero dal messaggio in uscita", + "exclude-zero-deltas-hint": "Se abilitato, la chiave di output \"{{outputValueKey}}\" verrà aggiunta al messaggio in uscita solo se il suo valore non è zero.", + "exclude-zero-deltas-time-difference-hint": "Se abilitato, le chiavi di output \"{{outputValueKey}}\" e \"{{periodValueKey}}\" verranno aggiunte al messaggio in uscita solo se il valore di \"{{outputValueKey}}\" non è zero.", "search-direction-from": "Dall'origine all'entità di destinazione", "search-direction-to": "Dall'entità di destinazione all'origine", "del-relation-direction-from": "Dall'origine", @@ -5230,29 +5379,29 @@ "function-name": "Nome funzione", "function-name-required": "Nome funzione richiesto.", "qualifier": "Qualificatore", - "qualifier-hint": "Se non specificato, verrà usato \"$LATEST\".", + "qualifier-hint": "Se il qualificatore non è specificato, verrà utilizzato il qualificatore predefinito \"$LATEST\".", "aws-credentials": "Credenziali AWS", - "connection-timeout": "Timeout connessione", - "connection-timeout-required": "Timeout connessione richiesto.", - "connection-timeout-min": "Timeout minimo connessione è 0.", - "connection-timeout-hint": "Tempo massimo in secondi per stabilire connessione. 0 significa infinito (sconsigliato).", - "request-timeout": "Timeout richiesta", - "request-timeout-required": "Timeout richiesta richiesto.", - "request-timeout-min": "Timeout minimo richiesta è 0", - "request-timeout-hint": "Tempo massimo in secondi per completare la richiesta. 0 significa infinito (sconsigliato).", + "connection-timeout": "Timeout di connessione", + "connection-timeout-required": "Il timeout di connessione è obbligatorio.", + "connection-timeout-min": "Il timeout di connessione minimo è 0.", + "connection-timeout-hint": "Tempo di attesa in secondi durante la fase iniziale di stabilimento della connessione prima di interrompere per timeout. Un valore pari a 0 indica infinito e non è raccomandato.", + "request-timeout": "Timeout della richiesta", + "request-timeout-required": "Il timeout della richiesta è obbligatorio.", + "request-timeout-min": "Il timeout minimo della richiesta è 0.", + "request-timeout-hint": "Tempo di attesa in secondi affinché la richiesta venga completata prima di interrompere per timeout. Un valore pari a 0 indica infinito e non è raccomandato.", "units": "Unità", - "tell-failure-aws-lambda": "Segnala errore se AWS Lambda solleva eccezione", - "tell-failure-aws-lambda-hint": "Il nodo forza un errore se l'esecuzione della funzione Lambda solleva un'eccezione.", + "tell-failure-aws-lambda": "Segnala errore se l’esecuzione della funzione AWS Lambda genera un’eccezione", + "tell-failure-aws-lambda-hint": "Il rule node forza un failure dell’elaborazione del messaggio se l’esecuzione della funzione AWS Lambda genera un’eccezione.", "basic-mode": "Base", "advanced-mode": "Avanzato", "save-time-series": { "processing-settings": "Impostazioni di elaborazione", - "processing-settings-hint": "Definisci come vengono elaborati i messaggi in arrivo. Le impostazioni di base consentono di selezionare strategie preconfigurate, mentre le impostazioni avanzate permettono di selezionare strategie individuali per ciascuna azione.", - "advanced-settings-hint": "Fai attenzione quando configuri le strategie di elaborazione. Alcune combinazioni possono portare a comportamenti imprevisti.", + "processing-settings-hint": "Definisci come vengono elaborati i messaggi in ingresso. Le impostazioni di elaborazione di base consentono di selezionare strategie preconfigurate, mentre le impostazioni avanzate permettono di selezionare strategie di elaborazione individuali per ciascuna azione.", + "advanced-settings-hint": "Prestare attenzione quando si configurano le strategie di elaborazione. Alcune combinazioni possono portare a comportamenti imprevisti.", "strategy": "Strategia", "deduplication-interval": "Intervallo di deduplicazione", - "deduplication-interval-required": "L'intervallo di deduplicazione è richiesto", - "deduplication-interval-min-max-range": "L'intervallo di deduplicazione deve essere almeno di 1 secondo e massimo di 1 giorno", + "deduplication-interval-required": "L’intervallo di deduplicazione è obbligatorio", + "deduplication-interval-min-max-range": "L’intervallo di deduplicazione deve essere almeno 1 secondo e al massimo 1 giorno", "strategy-type": { "every-message": "Su ogni messaggio", "skip": "Salta", @@ -5304,6 +5453,37 @@ "html-text-description": "Permette di usare tag HTML per formattazione, link e immagini nel corpo dell'email.", "dynamic-text-description": "Permette di usare testo semplice o HTML dinamicamente in base alla templatizzazione.", "after-template-evaluation-hint": "Dopo la valutazione del template il valore deve essere true per HTML e false per testo semplice." + }, + "ai": { + "ai-model": "Modello AI", + "model": "Modello", + "ai-model-hint": "Seleziona il modello AI preconfigurato per elaborare le richieste inviate da questo rule node, oppure utilizza \"Create new\" per configurarene uno nuovo.", + "prompt-settings": "Impostazioni prompt", + "prompt-settings-hint": "Il system prompt opzionale definisce il ruolo generale e i vincoli dell’AI, mentre lo user prompt definisce il compito specifico da eseguire. Entrambi i campi supportano la templificazione.", + "system-prompt": "System prompt", + "system-prompt-max-length": "Il system prompt deve contenere 500000 caratteri o meno.", + "system-prompt-blank": "Il system prompt non può essere vuoto.", + "user-prompt": "User prompt", + "user-prompt-required": "Lo user prompt è obbligatorio.", + "user-prompt-max-length": "Lo user prompt deve contenere 500000 caratteri o meno.", + "user-prompt-blank": "Lo user prompt non può essere vuoto.", + "response-format": "Formato risposta", + "response-text": "Testo", + "response-json": "JSON", + "response-json-schema": "JSON Schema", + "response-format-hint-TEXT": "Consente al modello di generare testo arbitrario, che può o meno essere un oggetto JSON valido. Se l’output non è un oggetto JSON valido, verrà automaticamente racchiuso all’interno di un oggetto JSON sotto la chiave \"response\".", + "response-format-hint-JSON": "Il modello deve generare una risposta che sia un JSON valido. Se l’output non è un oggetto JSON valido, verrà automaticamente racchiuso all’interno di un oggetto JSON sotto la chiave \"response\".", + "response-format-hint-JSON_SCHEMA": "Il modello deve generare un JSON che corrisponda alla struttura e ai tipi di dati definiti nello schema fornito. Se l’output non è un oggetto JSON valido, verrà automaticamente racchiuso all’interno di un oggetto JSON sotto la chiave \"response\".", + "response-json-schema-hint": "È possibile inserire qualsiasi JSON Schema valido, ma questo rule node supporta solo un sottoinsieme limitato delle sue caratteristiche. Consulta la documentazione del nodo per i dettagli.", + "response-json-schema-required": "JSON Schema è obbligatorio", + "advanced-settings": "Impostazioni avanzate", + "timeout": "Timeout", + "timeout-hint": "Tempo massimo di attesa per una risposta \ndal modello AI prima che la richiesta venga interrotta.", + "timeout-required": "Il timeout è obbligatorio", + "timeout-validation": "Deve essere compreso tra 1 secondo e 10 minuti.", + "force-acknowledgement": "Forza acknowledgement", + "force-acknowledgement-hint": "Se abilitato, il messaggio in ingresso viene confermato immediatamente. La risposta del modello viene quindi aggiunta in coda come nuovo messaggio separato.", + "ai-resources": "Risorse AI" } }, "timezone": { @@ -5528,17 +5708,17 @@ "maximum-rule-chains": "Numero massimo di rule chain", "maximum-rule-chains-required": "È richiesto il numero massimo di rule chain.", "maximum-rule-chains-range": "Il numero massimo di rule chain non può essere negativo", - "maximum-resources-sum-data-size": "Dimensione totale massima dei file risorsa (byte)", - "maximum-resources-sum-data-size-required": "La dimensione totale massima dei file risorsa è richiesta.", - "maximum-resources-sum-data-size-range": "La dimensione totale massima dei file risorsa non può essere negativa", - "maximum-resource-size": "Dimensione massima del singolo file risorsa (byte)", - "maximum-resource-size-required": "La dimensione massima del file risorsa è richiesta", + "maximum-resources-sum-data-size": "Dimensione totale massima dei file delle risorse (byte)", + "maximum-resources-sum-data-size-required": "La dimensione totale massima dei file delle risorse è obbligatoria.", + "maximum-resources-sum-data-size-range": "La dimensione totale massima dei file delle risorse non può essere negativa", + "maximum-resource-size": "Dimensione massima del file risorsa (byte)", + "maximum-resource-size-required": "La dimensione massima del file risorsa è obbligatoria", "maximum-resource-size-range": "La dimensione massima del file risorsa non può essere negativa", - "maximum-ota-packages-sum-data-size": "Dimensione totale massima dei file OTA (byte)", - "maximum-ota-package-sum-data-size-required": "La dimensione totale massima dei file OTA è richiesta.", - "maximum-ota-package-sum-data-size-range": "La dimensione totale massima dei file OTA non può essere negativa", - "maximum-debug-duration-min": "Durata massima di debug (min)", - "maximum-debug-duration-min-range": "La durata massima di debug non può essere negativa", + "maximum-ota-packages-sum-data-size": "Dimensione totale massima dei file dei pacchetti OTA (byte)", + "maximum-ota-package-sum-data-size-required": "La dimensione totale massima dei file dei pacchetti OTA è obbligatoria.", + "maximum-ota-package-sum-data-size-range": "La dimensione totale massima dei file dei pacchetti OTA non può essere negativa", + "maximum-debug-duration-min": "Durata massima del debug (min)", + "maximum-debug-duration-min-range": "La durata massima del debug non può essere negativa", "rest-requests-for-tenant": "Richieste REST per tenant", "transport-tenant-telemetry-msg-rate-limit": "Messaggi di telemetria del tenant (trasporto)", "transport-tenant-telemetry-data-points-rate-limit": "Punti dati di telemetria del tenant (trasporto)", @@ -5603,9 +5783,9 @@ "rule-engine-exceptions-ttl-days": "TTL delle eccezioni del Rule Engine (giorni)", "rule-engine-exceptions-ttl-days-required": "TTL delle eccezioni del Rule Engine richiesto", "rule-engine-exceptions-ttl-days-range": "Il TTL delle eccezioni del Rule Engine non può essere negativo", - "max-rule-node-executions-per-message": "Numero massimo di esecuzioni per nodo per messaggio", - "max-rule-node-executions-per-message-required": "È richiesto il numero massimo di esecuzioni per nodo per messaggio.", - "max-rule-node-executions-per-message-range": "Il numero massimo di esecuzioni per nodo per messaggio non può essere negativo", + "max-rule-node-executions-per-message": "Numero massimo di esecuzioni del Rule node per messaggio", + "max-rule-node-executions-per-message-required": "Il numero massimo di esecuzioni del Rule node per messaggio è obbligatorio.", + "max-rule-node-executions-per-message-range": "Il numero massimo di esecuzioni del Rule node per messaggio non può essere negativo", "max-emails": "Numero massimo di email inviate", "max-emails-required": "È richiesto il numero massimo di email inviate.", "max-emails-range": "Il numero massimo di email inviate non può essere negativo", @@ -5624,8 +5804,11 @@ "incorrect-pattern-for-rate-limits": "Il formato è coppie separate da virgole di capacità e periodo (in secondi) con i due punti, ad es. 100:1,2000:60", "too-small-value-zero": "Il valore deve essere maggiore di 0", "too-small-value-one": "Il valore deve essere maggiore di 1", - "queue-size-is-limited-by-system-configuration": "La dimensione della coda è anche limitata dalla configurazione di sistema.", - "cassandra-tenant-limits-configuration": "Query Cassandra per tenant", + "queue-size-is-limited-by-system-configuration": "La dimensione della coda è inoltre limitata dalla configurazione del sistema.", + "cassandra-write-tenant-core-limits-configuration": "Query di scrittura Cassandra per le API Rest", + "cassandra-read-tenant-core-limits-configuration": "Query di lettura Cassandra per API Rest e telemetria WS", + "cassandra-write-tenant-rule-engine-limits-configuration": "Query di scrittura Cassandra per la telemetria del Rule Engine", + "cassandra-read-tenant-rule-engine-limits-configuration": "Query di lettura Cassandra per la telemetria del Rule Engine", "ws-limit-max-sessions-per-tenant": "Numero massimo di sessioni per tenant", "ws-limit-max-sessions-per-customer": "Numero massimo di sessioni per cliente", "ws-limit-max-sessions-per-regular-user": "Numero massimo di sessioni per utente regolare", @@ -5638,6 +5821,7 @@ "ws-limit-updates-per-session": "Aggiornamenti WS per sessione", "rate-limits": { "add-limit": "Aggiungi limite", + "and-also-less-than": "e anche inferiore a", "advanced-settings": "Impostazioni avanzate", "edit-limit": "Modifica limite", "calculated-field-debug-event-rate-limit": "Eventi di debug del campo calcolato", @@ -5656,12 +5840,15 @@ "edit-transport-gateway-device-telemetry-data-points-title": "Modifica i limiti dei punti dati di telemetria dei dispositivi gateway", "edit-tenant-rest-limits-title": "Modifica i limiti delle richieste REST per il tenant", "edit-customer-rest-limits-title": "Modifica i limiti delle richieste REST per il cliente", - "edit-ws-limit-updates-per-session-title": "Modifica i limiti degli aggiornamenti WS per sessione", - "edit-cassandra-tenant-limits-configuration-title": "Modifica i limiti delle query Cassandra per tenant", - "edit-tenant-entity-export-rate-limit-title": "Modifica i limiti di creazione delle versioni delle entità", - "edit-tenant-entity-import-rate-limit-title": "Modifica i limiti di caricamento delle versioni delle entità", - "edit-tenant-notification-request-rate-limit-title": "Modifica i limiti delle richieste di notifica", - "edit-tenant-notification-requests-per-rule-rate-limit-title": "Modifica i limiti delle richieste di notifica per regola", + "edit-ws-limit-updates-per-session-title": "Modifica limiti di aggiornamenti WS per sessione", + "edit-cassandra-write-tenant-core-limits-configuration": "Modifica query di scrittura Cassandra per le API Rest", + "edit-cassandra-read-tenant-core-limits-configuration": "Modifica query di lettura Cassandra per API Rest e telemetria WS", + "edit-cassandra-write-tenant-rule-engine-limits-configuration": "Modifica query di scrittura Cassandra per la telemetria del Rule Engine", + "edit-cassandra-read-tenant-rule-engine-limits-configuration": "Modifica query di lettura Cassandra per la telemetria del Rule Engine", + "edit-tenant-entity-export-rate-limit-title": "Modifica limiti di creazione delle versioni entità", + "edit-tenant-entity-import-rate-limit-title": "Modifica limiti di caricamento delle versioni entità", + "edit-tenant-notification-request-rate-limit-title": "Modifica limiti delle richieste di notifica", + "edit-tenant-notification-requests-per-rule-rate-limit-title": "Modifica limiti delle richieste di notifica per regola di notifica", "edit-edge-events-rate-limit": "Modifica i limiti degli eventi edge", "edit-edge-events-per-edge-rate-limit": "Modifica i limiti degli eventi edge per edge", "edge-events-rate-limit": "Eventi edge", @@ -5673,13 +5860,14 @@ "messages-per": "messaggi per", "not-set": "Non impostato", "number-of-messages": "Numero di messaggi", - "number-of-messages-required": "È richiesto il numero di messaggi.", + "number-of-messages-required": "Il numero di messaggi è obbligatorio.", "number-of-messages-min": "Il valore minimo è 1.", "preview": "Anteprima", - "per-seconds": "Ogni secondi", - "per-seconds-required": "È richiesta la frequenza temporale.", + "per-seconds": "Per secondi", + "per-seconds-required": "Il tempo di rate è obbligatorio.", "per-seconds-min": "Il valore minimo è 1.", - "rate-limits": "Limiti di frequenza", + "per-seconds-duplicate": "Intervallo di tempo duplicato. Ogni intervallo deve essere unico.", + "rate-limits": "Limiti di velocità", "remove-limit": "Rimuovi limite", "transport-tenant-msg": "Messaggi di trasporto del tenant", "transport-tenant-telemetry-msg": "Messaggi di telemetria del tenant", @@ -5825,21 +6013,135 @@ "label": "Etichetta", "value": "Valore", "date": "Data", - "show-date-time-interval": "Mostra intervallo data e ora", - "show-date-time-interval-hint": "Mostra intervallo data e ora in base all'aggregazione dei dati.", + "show-date-time-interval": "Mostra intervallo data/ora", + "show-date-time-interval-hint": "Mostra l’intervallo data/ora in base all’aggregazione dei dati.", + "hide-zero-tooltip-values": "Nascondi i valori pari a zero", + "show-stack-total": "Mostra il valore totale in modalità stack", "background-color": "Colore di sfondo", "background-blur": "Sfocatura sfondo" }, "unit": { + "set-unit-conversion": "Imposta conversione unità", + "unit-settings": { + "unit-settings": "Impostazioni unità", + "source-unit": "Unità di origine", + "source-unit-hint": "Questa è l’unità del valore memorizzato. L’unità da cui stai convertendo. Inserisci il simbolo usato dai dati di origine (es. m, km, ft, in).", + "target-metric-unit": "Unità metrica di destinazione", + "target-metric-unit-hint": "Scegli in quale unità metrica (SI) convertire il valore di origine (es. cm, mm, km).", + "target-imperial-unit": "Unità imperiale di destinazione", + "target-imperial-unit-hint": "Scegli in quale unità imperiale convertire il valore di origine (es. in, ft, yd).", + "target-hybrid-unit": "Unità ibrida di destinazione", + "target-hybrid-unit-hint": "Scegli in quale unità ibrida convertire il valore di origine (es. cm, in, km). Le unità ibride combinano unità metriche o imperiali.", + "enable-unit-conversion": "Abilita conversione unità", + "enable-unit-conversion-hint": "Attiva per abilitare la conversione. Se disattivato, il valore di origine passerà invariato. Disabilitato se esiste una sola unità nel gruppo di misurazione corrispondente (es. Flusso luminoso, AQI)." + }, + "unit-system": "Sistema di unità", + "unit-system-type": { + "AUTO": "Auto", + "METRIC": "Metrico", + "IMPERIAL": "Imperiale", + "HYBRID": "Ibrido" + }, + "measures": { + "absorbed-dose-rate": "Tasso di dose assorbita", + "acceleration": "Accelerazione", + "acidity": "Acidità", + "air-quality-index": "Indice qualità dell’aria", + "amount-of-substance": "Quantità di sostanza", + "angle": "Angolo", + "angular-acceleration": "Accelerazione angolare", + "area": "Area", + "area-density": "Densità di area", + "capacitance": "Capacità", + "catalytic-activity": "Attività catalitica", + "catalytic-concentration": "Concentrazione catalitica", + "charge": "Carica", + "current-density": "Densità di corrente", + "data-transfer-rate": "Velocità di trasferimento dati", + "density": "Densità", + "digital": "Digitale", + "dimension-ratio": "Rapporto dimensionale", + "dynamic-viscosity": "Viscosità dinamica", + "earthquake-magnitude": "Magnitudo sismica", + "electric-charge-density": "Densità di carica elettrica", + "electric-current": "Corrente elettrica", + "electric-dipole-moment": "Momento di dipolo elettrico", + "electric-field-strength": "Intensità del campo elettrico", + "electric-flux": "Flusso elettrico", + "electric-permittivity": "Permittività elettrica", + "electric-polarizability": "Polarizzabilità elettrica", + "electrical-conductance": "Conduttanza elettrica", + "electrical-conductivity": "Conducibilità elettrica", + "energy": "Energia", + "energy-density": "Densità di energia", + "force": "Forza", + "frequency": "Frequenza", + "fuel-efficiency": "Efficienza del carburante", + "heat-capacity": "Capacità termica", + "illuminance": "Illuminamento", + "inductance": "Induttanza", + "kinematic-viscosity": "Viscosità cinematica", + "length": "Lunghezza", + "light-exposure": "Esposizione luminosa", + "linear-charge-density": "Densità di carica lineare", + "logarithmic-ratio": "Rapporto logaritmico", + "luminous-efficacy": "Efficacia luminosa", + "luminous-flux": "Flusso luminoso", + "luminous-intensity": "Intensità luminosa", + "magnetic-field-gradient": "Gradiente del campo magnetico", + "magnetic-flux": "Flusso magnetico", + "magnetic-flux-density": "Densità di flusso magnetico", + "magnetic-moment": "Momento magnetico", + "magnetic-permeability": "Permeabilità magnetica", + "mass": "Massa", + "mass-fraction": "Frazione massica", + "molar-concentration": "Concentrazione molare", + "molar-energy": "Energia molare", + "molar-heat-capacity": "Capacità termica molare", + "molar-mass": "Massa molare", + "number-concentration": "Concentrazione numerica", + "parts-per-million": "Parti per milione", + "power": "Potenza", + "power-density": "Densità di potenza", + "pressure": "Pressione", + "radiance": "Radianza", + "radiant-intensity": "Intensità radiante", + "radiation-dose": "Dose di radiazione", + "radioactive-decay": "Decadimento radioattivo", + "radioactivity": "Radioattività", + "radioactivity-concentration": "Concentrazione di radioattività", + "reciprocal-length": "Lunghezza reciproca", + "resistance": "Resistenza", + "reynolds-number": "Numero di Reynolds", + "signal-level": "Livello del segnale", + "solid-angle": "Angolo solido", + "specific-energy": "Energia specifica", + "specific-heat-capacity": "Capacità termica specifica", + "specific-humidity": "Umidità specifica", + "specific-volume": "Volume specifico", + "speed": "Velocità", + "surface-charge-density": "Densità di carica superficiale", + "surface-tension": "Tensione superficiale", + "temperature": "Temperatura", + "thermal-conductivity": "Conducibilità termica", + "time": "Tempo", + "torque": "Coppia", + "turbidity": "Torbidità", + "voltage": "Tensione", + "volume": "Volume", + "volume-flow": "Flusso volumetrico" + }, "millimeter": "Millimetro", "centimeter": "Centimetro", - "angstrom": "Ångström", + "decimeter": "Decimetro", + "angstrom": "Angstrom", "nanometer": "Nanometro", "micrometer": "Micrometro", "meter": "Metro", "kilometer": "Chilometro", "inch": "Pollice", "foot": "Piede", + "foot-us": "Piede (US survey)", "yard": "Iarda", "mile": "Miglio", "nautical-mile": "Miglio nautico", @@ -5885,7 +6187,8 @@ "cubic-inch": "Pollice cubo", "cubic-foot": "Piede cubo", "cubic-yard": "Iarda cubica", - "fluid-ounce": "Oncia liquida", + "fluid-ounce": "Oncia fluida", + "fluid-ounce-per-second": "Once fluide al secondo", "pint": "Pinta", "quart": "Quarto", "gallon": "Gallone", @@ -5903,10 +6206,14 @@ "percent": "Percentuale", "meter-per-second": "Metro al secondo", "kilometer-per-hour": "Chilometro all'ora", - "foot-per-second": "Piede al secondo", + "foot-per-second": "Piedi al secondo", + "foot-per-minute": "Piedi al minuto", "mile-per-hour": "Miglio all'ora", "knot": "Nodo", + "inch-per-second": "Pollici al secondo", + "inch-per-hour": "Pollici all’ora", "millimeters-per-minute": "Millimetri al minuto", + "meter-per-minute": "Metri al minuto", "kilometer-per-hour-squared": "Chilometro all'ora quadrato", "foot-per-second-squared": "Piede al secondo quadrato", "pascal": "Pascal", @@ -5923,6 +6230,7 @@ "newton-per-meter": "Newton per metro", "atmospheres": "Atmosfere", "pounds-per-square-inch": "Libbre per pollice quadrato", + "kilopound-per-square-inch": "Kilopound per pollice quadrato", "torr": "Torr", "inches-of-mercury": "Pollici di mercurio", "pascal-per-square-meter": "Pascal per metro quadrato", @@ -5940,18 +6248,24 @@ "megajoule": "Megajoule", "gigajoule": "Gigajoule", "watt-hour": "Wattora", + "watt-minute": "Wattminuto", "kilowatt-hour": "Kilowattora", + "milliwatt-hour": "Milliwattora", + "megawatt-hour": "Megawattora", + "gigawatt-hour": "Gigawattora", "electron-volts": "Elettronvolt", - "joules-per-coulomb": "Joule per Coulomb", - "british-thermal-unit": "Unità termica britannica", + "joules-per-coulomb": "Joule per coulomb", + "british-thermal-unit": "Unità termiche britanniche", + "thousand-british-thermal-unit": "Mille unità termiche britanniche", + "million-british-thermal-unit": "Milioni di unità termiche britanniche", "foot-pound": "Piede-libbra", "calorie": "Caloria", "small-calorie": "Piccola caloria", - "kilocalorie": "Chilocaloria", - "joule-per-kelvin": "Joule per Kelvin", - "joule-per-kilogram-kelvin": "Joule per chilogrammo-Kelvin", + "kilocalorie": "Kilocaloria", + "joule-per-kelvin": "Joule per kelvin", + "joule-per-kilogram-kelvin": "Joule per chilogrammo-kelvin", "joule-per-kilogram": "Joule per chilogrammo", - "watt-per-meter-kelvin": "Watt per metro-Kelvin", + "watt-per-meter-kelvin": "Watt per metro-kelvin", "joule-per-cubic-meter": "Joule per metro cubo", "therm": "Therm", "electric-dipole-moment": "Momento di dipolo elettrico", @@ -5974,10 +6288,20 @@ "watt-per-square-inch": "Watt per pollice quadrato", "kilowatt-per-square-inch": "Kilowatt per pollice quadrato", "horsepower": "Cavallo vapore", - "btu-per-hour": "Unità termiche britanniche/ora", + "btu-per-hour": "Unità termiche britanniche per ora", + "btu-per-second": "Unità termiche britanniche per secondo", + "btu-per-day": "Unità termiche britanniche per giorno", + "mbtu-per-hour": "Mille unità termiche britanniche per ora", + "mbtu-per-second": "Mille unità termiche britanniche per secondo", + "mbtu-per-day": "Mille unità termiche britanniche per giorno", + "mmbtu-per-hour": "Milioni di unità termiche britanniche per ora", + "mmbtu-per-second": "Milioni di unità termiche britanniche per secondo", + "mmbtu-per-day": "Milioni di unità termiche britanniche per giorno", + "foot-pound-per-second": "Piede-libbra per secondo", "coulomb": "Coulomb", "millicoulomb": "Millicoulomb", "microcoulomb": "Microcoulomb", + "nanocoulomb": "Nanocoulomb", "picocoulomb": "Picocoulomb", "coulomb-per-meter": "Coulomb per metro", "coulomb-per-cubic-meter": "Coulomb per metro cubo", @@ -5995,14 +6319,17 @@ "are": "Ara", "barn": "Barn", "circular-inch": "Pollice circolare", - "milliampere-hour": "Milliampere-ora", - "ampere-hours": "Ampere-ora", - "kiloampere-hours": "Chiloampere-ora", + "milliampere-hour": "Milliampereora", + "ampere-hours": "Ampereora", + "kiloampere-hours": "Kiloampereora", "nanoampere": "Nanoampere", "picoampere": "Picoampere", "microampere": "Microampere", "milliampere": "Milliampere", "ampere": "Ampere", + "kiloampere": "Kiloampere", + "megaampere": "Megaampere", + "gigaampere": "Gigaampere", "microampere-per-square-centimeter": "Microampere per centimetro quadrato", "ampere-per-square-meter": "Ampere per metro quadrato", "ampere-per-meter": "Ampere per metro", @@ -6011,25 +6338,31 @@ "ampere-meter-squared": "Ampere metro quadrato", "nanovolt": "Nanovolt", "picovolt": "Picovolt", + "millivolt": "Millivolt", + "microvolt": "Microvolt", "volt": "Volt", - "dbmV": "dBmV", - "dbm": "dBm", - "volt-meter": "Volt-metro", - "kilovolt-meter": "Kilovolt-metro", - "megavolt-meter": "Megavolt-metro", - "microvolt-meter": "Microvolt-metro", - "millivolt-meter": "Millivolt-metro", - "nanovolt-meter": "Nanovolt-metro", + "kilovolt": "Kilovolt", + "megavolt": "Megavolt", + "dbmV": "Decibel volt", + "dbm": "Decibel milliwatt", + "volt-meter": "Volt metro", + "kilovolt-meter": "Kilovolt metro", + "megavolt-meter": "Megavolt metro", + "microvolt-meter": "Microvolt metro", + "millivolt-meter": "Millivolt metro", + "nanovolt-meter": "Nanovolt metro", "ohm": "Ohm", "microohm": "Microohm", "milliohm": "Milliohm", "kilohm": "Kilohm", "megohm": "Megohm", "gigohm": "Gigohm", + "millihertz": "Millihertz", "hertz": "Hertz", "kilohertz": "Kilohertz", "megahertz": "Megahertz", "gigahertz": "Gigahertz", + "terahertz": "Terahertz", "rpm": "Giri al minuto", "candela-per-square-meter": "Candela per metro quadrato", "candela": "Candela", @@ -6037,21 +6370,21 @@ "lux": "Lux", "foot-candle": "Foot-candle", "lumen-per-square-meter": "Lumen per metro quadrato", - "lux-second": "Secondo lux", - "lumen-second": "Secondo lumen", + "lux-second": "Lux secondo", + "lumen-second": "Lumen secondo", "lumens-per-watt": "Lumen per watt", "mole": "Mole", "nanomole": "Nanomole", "micromole": "Micromole", "millimole": "Millimole", - "kilomole": "Chilomole", + "kilomole": "Kilomole", "mole-per-cubic-meter": "Mole per metro cubo", - "rssi": "RSSI", + "rssi": "Indicatore di intensità del segnale ricevuto", "ppm": "Parti per milione", "ppb": "Parti per miliardo", "micrograms-per-cubic-meter": "Microgrammi per metro cubo", - "aqi": "Indice di qualità dell'aria (AQI)", - "gram-per-cubic-meter": "Grammo per metro cubo", + "aqi": "AQI", + "gram-per-cubic-meter": "Grammi per metro cubo", "gram-per-kilogram": "Umidità specifica", "millimeters-per-second": "Millimetri al secondo", "neper": "Neper", @@ -6071,50 +6404,53 @@ "coulombs-per-kilogram": "Coulomb per chilogrammo", "becquerels-per-cubic-meter": "Becquerel per metro cubo", "curies-per-liter": "Curie per litro", - "becquerels-per-second": "Becquerel al secondo", - "curies-per-second": "Curie al secondo", - "gy-per-second": "Gray al secondo", + "becquerels-per-second": "Becquerel per secondo", + "curies-per-second": "Curie per secondo", + "gy-per-second": "Gray per secondo", "watt-per-steradian": "Watt per steradiante", "watt-per-square-metre-steradian": "Watt per metro quadrato-steradiante", - "ph-level": "Livello di pH", + "ph-level": "Livello pH", "turbidity": "Torbidità", "mg-per-liter": "Milligrammi per litro", "microsiemens-per-centimeter": "Microsiemens per centimetro", "millisiemens-per-meter": "Millisiemens per metro", "siemens-per-meter": "Siemens per metro", - "kilogram-per-cubic-meter": "Chilogrammo per metro cubo", - "gram-per-cubic-centimeter": "Grammo per centimetro cubo", - "kilogram-per-square-meter": "Chilogrammo per metro quadrato", - "milligram-per-milliliter": "Milligrammo per millilitro", - "milligram-per-cubic-meter": "Milligrammo per metro cubo", + "kilogram-per-cubic-meter": "Chilogrammi per metro cubo", + "gram-per-cubic-centimeter": "Grammi per centimetro cubo", + "kilogram-per-square-meter": "Chilogrammi per metro quadrato", + "milligram-per-milliliter": "Milligrammi per millilitro", + "milligram-per-cubic-meter": "Milligrammi per metro cubo", "pound-per-cubic-foot": "Libbra per piede cubo", "ounces-per-cubic-inch": "Once per pollice cubo", "tons-per-cubic-yard": "Tonnellate per iarda cubica", - "particle-density": "Densità di particelle", + "particle-density": "Densità delle particelle", "kilometers-per-liter": "Chilometri per litro", "miles-per-gallon": "Miglia per gallone", "liters-per-100-km": "Litri per 100 km", "gallons-per-mile": "Galloni per miglio", - "liters-per-hour": "Litri all'ora", - "gallons-per-hour": "Galloni all'ora", - "beats-per-minute": "Battiti per minuto", + "liters-per-hour": "Litri per ora", + "gallons-per-hour": "Galloni per ora", + "beats-per-minute": "Battiti al minuto", "millimeters-of-mercury": "Millimetri di mercurio", "milligrams-per-deciliter": "Milligrammi per decilitro", "g-force": "Forza G", - "kilonewton": "Chilonewton", + "kilonewton": "Kilonewton", "kilogram-force": "Chilogrammo-forza", "pound-force": "Libbra-forza", - "kilopound-force": "Chilolibbra-forza", + "kilopound-force": "Kilopound-forza", "dyne": "Dina", "poundal": "Poundal", "kip": "Kip", "gal": "Gal", "gravity": "Gravità", - "hectopascal": "Ettopascal", + "hectopascal": "Ectopascal", "atmosphere": "Atmosfera", "millibars": "Millibar", "inch-of-mercury": "Pollice di mercurio", "richter-scale": "Scala Richter", + "nanosecond": "Nanosecondo", + "microsecond": "Microsecondo", + "millisecond": "Millisecondo", "second": "Secondo", "minute": "Minuto", "hour": "Ora", @@ -6123,13 +6459,14 @@ "month": "Mese", "year": "Anno", "cubic-foot-per-minute": "Piede cubo al minuto", - "cubic-meters-per-hour": "Metri cubi all'ora", + "cubic-meters-per-hour": "Metri cubi all’ora", "cubic-meters-per-second": "Metri cubi al secondo", "liter-per-second": "Litri al secondo", "liter-per-minute": "Litri al minuto", "gallons-per-minute": "Galloni al minuto", "cubic-foot-per-second": "Piede cubo al secondo", "milliliters-per-minute": "Millilitri al minuto", + "cubic-decimeter-per-second": "Decimetri cubi al secondo", "bit": "Bit", "byte": "Byte", "kilobyte": "Kilobyte", @@ -6150,8 +6487,11 @@ "megabyte-per-second": "Megabyte al secondo", "gigabyte-per-second": "Gigabyte al secondo", "degree": "Grado", - "radian": "Radianti", - "gradian": "Gradi centesimali", + "radian": "Radiante", + "gradian": "Grado centesimale", + "arcminute": "Primo d’arco", + "arcsecond": "Secondo d’arco", + "milliradian": "Milliradiante", "revolution": "Rivoluzione", "siemens": "Siemens", "millisiemens": "Millisiemens", @@ -6177,16 +6517,16 @@ "nanotesla": "Nanotesla", "kilotesla": "Kilotesla", "megatesla": "Megatesla", - "millitesla-square-meters": "Millitesla per metro quadrato", + "millitesla-square-meters": "Millitesla metri quadrati", "gamma": "Gamma", "lambda": "Lambda", - "square-meter-per-second": "Metro quadrato al secondo", - "square-centimeter-per-second": "Centimetro quadrato al secondo", + "square-meter-per-second": "Metri quadrati al secondo", + "square-centimeter-per-second": "Centimetri quadrati al secondo", "stoke": "Stoke", - "centistokes": "Centistoke", - "square-foot-per-second": "Piede quadrato al secondo", - "square-inch-per-second": "Pollice quadrato al secondo", - "pascal-second": "Pascal per secondo", + "centistokes": "Centistokes", + "square-foot-per-second": "Piedi quadrati al secondo", + "square-inch-per-second": "Pollici quadrati al secondo", + "pascal-second": "Pascal secondo", "centipoise": "Centipoise", "poise": "Poise", "reynolds": "Reynolds", @@ -6194,37 +6534,39 @@ "newton-second-per-square-meter": "Newton secondo per metro quadrato", "dyne-second-per-square-centimeter": "Dina secondo per centimetro quadrato", "kilogram-per-meter-second": "Chilogrammo per metro-secondo", - "tesla-square-meters": "Tesla per metro quadrato", + "tesla-square-meters": "Tesla metri quadrati", "maxwell": "Maxwell", "tesla-per-meter": "Tesla per metro", "gauss-per-centimeter": "Gauss per centimetro", "weber": "Weber", "microweber": "Microweber", "milliweber": "Milliweber", - "gauss-square-centimeter": "Gauss per centimetro quadrato", - "kilogauss-square-centimeter": "Kilogauss per centimetro quadrato", + "gauss-square-centimeter": "Gauss centimetri quadrati", + "kilogauss-square-centimeter": "Kilogauss centimetri quadrati", "henry": "Henry", "millihenry": "Millihenry", "microhenry": "Microhenry", "nanohenry": "Nanohenry", "henry-per-meter": "Henry per metro", "tesla-meter-per-ampere": "Tesla metro per ampere", - "gauss-per-oersted": "Gauss per Oersted", + "gauss-per-oersted": "Gauss per oersted", "kilogram-per-mole": "Chilogrammo per mole", - "gram-per-mole": "Gramma per mole", + "gram-per-mole": "Grammo per mole", "milligram-per-mole": "Milligrammo per mole", "joule-per-mole": "Joule per mole", - "joule-per-mole-kelvin": "Joule per mole-Kelvin", + "joule-per-mole-kelvin": "Joule per mole-kelvin", "millivolts-per-meter": "Millivolt per metro", "volts-per-meter": "Volt per metro", "kilovolts-per-meter": "Kilovolt per metro", "radian-per-second": "Radianti al secondo", "radian-per-second-squared": "Radianti al secondo quadrato", "revolutions-per-minute-per-second": "Accelerazione angolare", - "deg-per-second": "gradi al secondo (°/s)", + "deg-per-second": "Gradi al secondo", + "rotation-per-minute": "Rotazioni al minuto", "degrees-brix": "Gradi Brix", "katal": "Katal", - "katal-per-cubic-metre": "Katal per metro cubo" + "katal-per-cubic-metre": "Katal per metro cubo", + "paris-inch": "Pollice di Parigi" }, "user": { "user": "Utente", @@ -6374,7 +6716,7 @@ "rollback-on-error-hint": "Se devi ripristinare un numero elevato di entità, valuta la possibilità di disabilitare questa opzione per migliorare le prestazioni.\nNota: in caso di errore durante il caricamento della versione, le entità già salvate (con relazioni, attributi, ecc.) rimarranno invariate." }, "widget": { - "widget-library": "Libreria widget", + "widget-library": "Libreria di widget", "widget-bundle": "Bundle di widget", "all-bundles": "Tutti i bundle", "select-widgets-bundle": "Seleziona bundle di widget", @@ -6383,19 +6725,19 @@ "widget": "Widget", "select-widget": "Seleziona widget", "no-widgets-matching": "Nessun widget corrispondente a '{{entity}}' trovato.", - "no-widgets": "Nessun widget", + "no-widgets": "Non ci sono ancora widget", "no-widgets-text": "Nessun widget trovato", "management": "Gestione widget", "editor": "Editor widget", - "confirm-to-exit-editor-html": "Hai modifiche non salvate al widget.
Sei sicuro di voler lasciare questa pagina?", - "widget-type-not-found": "Problema nel caricamento della configurazione del widget.
Probabilmente il tipo di widget associato è stato rimosso.", + "confirm-to-exit-editor-html": "Hai impostazioni del widget non salvate.
Sei sicuro di voler lasciare questa pagina?", + "widget-type-not-found": "Problema nel caricamento della configurazione del widget.
Probabilmente il tipo di\n widget associato è stato rimosso.", "widget-type-load-error": "Il widget non è stato caricato a causa dei seguenti errori:", "remove": "Rimuovi widget", "delete": "Elimina widget", "edit": "Modifica widget", "remove-widget-title": "Sei sicuro di voler rimuovere il widget '{{widgetTitle}}'?", - "remove-widget-text": "Dopo la conferma, il widget e tutti i dati correlati non saranno più recuperabili.", - "replace-reference-with-widget-copy": "Sostituisci riferimento con copia del widget", + "remove-widget-text": "Dopo la conferma, il widget e tutti i dati correlati diventeranno irrecuperabili.", + "replace-reference-with-widget-copy": "Sostituisci riferimento con una copia del widget", "timeseries": "Serie temporali", "search-data": "Cerca dati", "no-data-found": "Nessun dato trovato", @@ -7774,6 +8116,18 @@ "fill-area-opacity": "Opacità area riempita", "range-chart-style": "Stile grafico intervallo" }, + "knob": { + "behavior": "Comportamento", + "initial-value": "Valore iniziale", + "initial-value-hint": "Azione per ottenere il valore iniziale della manopola.", + "on-value-change": "Al cambio del valore", + "on-value-change-hint": "Azione attivata quando il valore della manopola viene modificato.", + "range": "Intervallo", + "min": "min", + "max": "max", + "value": "Valore", + "fallback-initial-value": "Valore iniziale di fallback" + }, "rpc": { "value-settings": "Impostazioni valore", "initial-value": "Valore iniziale", @@ -7830,9 +8184,7 @@ "led-status-value-timeseries": "Serie temporale dispositivo con valore stato LED", "check-status-method": "Metodo RPC per controllo stato dispositivo", "parse-led-status-value-function": "Funzione per analisi valore stato LED", - "knob-title": "Titolo manopola", - "min-value": "Valore minimo", - "max-value": "Valore massimo" + "knob-title": "Titolo manopola" }, "maps": { "map-type": { @@ -8327,14 +8679,14 @@ "markers-clustering-settings": "Impostazioni clustering marker", "use-map-markers-clustering": "Usa clustering marker mappa", "zoom-on-cluster-click": "Zoom al clic su un cluster", - "max-cluster-zoom": "Livello di zoom massimo per includere marker in un cluster (0 - 18)", + "max-cluster-zoom": "Il livello massimo di zoom in cui un marker può far parte di un cluster (0 - 18)", "max-cluster-radius-pixels": "Raggio massimo coperto da un cluster in pixel", - "cluster-zoom-animation": "Mostra animazione su marker durante zoom", - "show-markers-bounds-on-cluster-mouse-over": "Mostra limiti marker al passaggio su cluster", - "spiderfy-max-zoom-level": "Espandi cluster al massimo livello di zoom", - "load-optimization": "Ottimizzazione caricamento", - "cluster-chunked-loading": "Usa caricamento a blocchi per evitare blocchi della pagina", - "cluster-markers-lazy-load": "Usa caricamento ritardato per i marker", + "cluster-zoom-animation": "Mostra animazione sui marker durante lo zoom", + "show-markers-bounds-on-cluster-mouse-over": "Mostra i confini dei marker al passaggio del mouse su un cluster", + "spiderfy-max-zoom-level": "Attiva lo spiderfy al livello massimo di zoom (per vedere tutti i marker del cluster)", + "load-optimization": "Ottimizzazione del caricamento", + "cluster-chunked-loading": "Usa caricamento a blocchi per aggiungere i marker così da evitare blocchi della pagina", + "cluster-markers-lazy-load": "Usa il caricamento lazy per aggiungere i marker", "editor-settings": "Impostazioni editor", "enable-snapping": "Abilita allineamento ai vertici per disegno preciso", "init-draggable-mode": "Inizializza mappa in modalità trascinamento", @@ -8676,7 +9028,7 @@ "pie-chart-card-style": "Stile scheda grafico a torta" }, "radar-chart": { - "radar-appearance": "Aspetto radar", + "radar-appearance": "Aspetto del radar", "shape": "Forma", "shape-polygon": "Poligono", "shape-circle": "Cerchio", @@ -8687,7 +9039,11 @@ "radar-axis": "Asse radar", "axis-label": "Etichetta asse", "ticks-label": "Etichetta tacche", - "radar-chart-style": "Stile grafico radar" + "radar-chart-style": "Stile del grafico radar", + "max-axes-scaling": "Scala massima degli assi", + "max-axes-scaling-hint": "Scegli se ogni asse radar deve avere il proprio valore massimo (Separato) o condividere il valore massimo più alto tra tutti gli assi sulla base del dataset del widget (Comune).", + "separate": "Separato", + "common": "Comune" }, "time-series-chart": { "chart": "Grafico", @@ -8964,12 +9320,12 @@ "cpu": "CPU", "ram": "RAM", "disk": "Disco", - "cpu-warning-text": "Utilizzo elevato della CPU. Per evitare guasti, ottimizza le prestazioni del sistema.", - "cpu-critical-text": "Utilizzo critico della CPU. Per evitare guasti, ottimizza le prestazioni del sistema.", - "ram-warning-text": "Scarsa riserva di RAM. Per evitare guasti, ottimizza le prestazioni del sistema o aumenta la RAM.", - "ram-critical-text": "Riserva di RAM criticamente bassa. Per evitare guasti, ottimizza le prestazioni del sistema o aumenta la RAM.", - "disk-warning-text": "Spazio su disco insufficiente. Per evitare perdite di dati, libera o espandi lo spazio su disco.", - "disk-critical-text": "Spazio su disco criticamente insufficiente. Per evitare perdite di dati, libera o espandi lo spazio su disco." + "cpu-warning-text": "Utilizzo della CPU elevato. Per evitare malfunzionamenti del sistema, ottimizza le prestazioni.", + "cpu-critical-text": "Utilizzo della CPU criticamente elevato. Per evitare malfunzionamenti del sistema, ottimizza le prestazioni.", + "ram-warning-text": "Riserva di RAM in diminuzione. Per evitare malfunzionamenti del sistema, ottimizza le prestazioni o aumenta la quantità di RAM.", + "ram-critical-text": "Riserva di RAM criticamente bassa. Per evitare malfunzionamenti del sistema, ottimizza le prestazioni o aumenta la quantità di RAM.", + "disk-warning-text": "Spazio su disco in esaurimento. Per evitare la perdita di dati, libera o amplia lo spazio su disco.", + "disk-critical-text": "Spazio su disco criticamente basso. Per evitare la perdita di dati, libera o amplia lo spazio su disco." }, "cluster-info": { "service-id": "ID servizio", @@ -9193,4 +9549,4 @@ "language": { "language": "Lingua" } -} +} \ No newline at end of file diff --git a/ui-ngx/src/assets/locale/locale.constant-lt_LT.json b/ui-ngx/src/assets/locale/locale.constant-lt_LT.json index 935ae65eb4..c3ddb5af74 100644 --- a/ui-ngx/src/assets/locale/locale.constant-lt_LT.json +++ b/ui-ngx/src/assets/locale/locale.constant-lt_LT.json @@ -1,7708 +1,9524 @@ -{ - "access": { - "unauthorized": "Neautorizuotas", - "unauthorized-access": "Neautorizuota prieiga", - "unauthorized-access-text": "Prieiga prie šio funkcionalumo leidžiama tik prisijungusiam vartotojui!", - "access-forbidden": "Prieiga uždrausta", - "access-forbidden-text": "Neturite teisių prieigai!
Bandykite prisijungti kitu vartotoju.", - "refresh-token-expired": "Sesijos galiojimas baigėsi", - "refresh-token-failed": "Sesijos atnaujinti nepavyksta", - "permission-denied": "Leidimas nesuteiktas", - "permission-denied-text": "Šio veiksmo atlikti negalite!" - }, - "account": { - "account": "Account", - "notification-settings": "Notification settings" - }, - "action": { - "activate": "Aktyvuoti", - "suspend": "Sustabdyti", - "save": "Išsaugoti", - "saveAs": "Išsaugoti kaip", - "move": "Perkelti", - "cancel": "Atmesti", - "ok": "OK", - "delete": "Panaikinti", - "add": "Pridėti", - "yes": "Taip", - "no": "Ne", - "update": "Atnaujinti", - "remove": "Panaikinti", - "search": "Paieška", - "clear-search": "Išvalyti", - "assign": "Priskirti", - "unassign": "Atsieti", - "share": "Pasidalinti", - "make-private": "Riboti matomumą", - "make-public": "Neriboti matomumo", - "apply": "Taikyti", - "apply-changes": "Pritaikyti pakeitimus", - "edit-mode": "Redagavimo režimas", - "enter-edit-mode": "Redagavimo režimas", - "decline-changes": "Atšaukti pakeitimus", - "open": "Atverti", - "decline": "Atšaukti", - "close": "Uždaryti", - "back": "Atgal", - "run": "Paleisti", - "sign-in": "Prisijunkite!", - "edit": "Redaguoti", - "view": "Peržiūrėti", - "create": "Kurti", - "drag": "Vilkti", - "refresh": "Atnaujinti", - "undo": "Atšaukti", - "copy": "Kopijuoti", - "paste": "Įklijuoti", - "copy-reference": "Kopijuoti nuorodą", - "paste-reference": "Įklijuoti nuorodą", - "import": "Importuoti", - "export": "Eksportuoti", - "share-via": "Pasidalinti per {{provider}}", - "select": "Pasirinkti", - "continue": "Tęsti", - "discard-changes": "Atsisakyti pakeitimų", - "download": "Parsisiųsti", - "next": "Sekantis", - "next-with-label": "Sekantis: {{label}}", - "read-more": "Skaityti daugiau", - "hide": "Paslėpti", - "done": "Atlikta", - "print": "Spausdinti", - "restore": "Atkurti", - "confirm": "Patvirtinti", - "more": "Daugiau", - "less": "Mažiau", - "skip": "Praleisti", - "send": "Siųsti", - "reset": "Nustatyti iš naujo", - "show-more": "Rodyti daugiau", - "dont-show-again": "Daugiau neberodyti", - "see-documentation": "Žiūrėti dokumentacijoje", - "clear": "Išvalyti" - }, - "aggregation": { - "aggregation": "Agregavimas", - "function": "Duomenų aggregavimo funkcija", - "limit": "Maksimali reikšmė", - "group-interval": "Grupavimo intervalas", - "min": "Min", - "max": "Max", - "avg": "Vidurkis", - "sum": "Sum", - "count": "Kiekis", - "none": "Nėra" - }, - "admin": { - "settings": "Settings", - "general": "General", - "general-settings": "General Settings", - "home-settings": "Home Settings", - "home": "Home", - "outgoing-mail": "Mail Server", - "outgoing-mail-settings": "Outgoing Mail Server Settings", - "system-settings": "System Settings", - "test-mail-sent": "Test mail was successfully sent!", - "base-url": "Base URL", - "base-url-required": "Base URL is required.", - "prohibit-different-url": "Prohibit to use hostname from the client request headers", - "prohibit-different-url-hint": "This setting should be enabled for production environments. May cause security issues when disabled", - "mail-from": "Mail From", - "mail-from-required": "Mail From is required.", - "smtp-protocol": "SMTP protocol", - "smtp-host": "SMTP host", - "smtp-host-required": "SMTP host is required.", - "smtp-port": "SMTP port", - "smtp-port-required": "You must supply a smtp port.", - "smtp-port-invalid": "That doesn't look like a valid smtp port.", - "timeout-msec": "Timeout (msec)", - "timeout-required": "Timeout is required.", - "timeout-invalid": "That doesn't look like a valid timeout.", - "enable-tls": "Enable TLS", - "tls-version": "TLS version", - "enable-proxy": "Enable proxy", - "proxy-host": "Proxy host", - "proxy-host-required": "Proxy host is required.", - "proxy-port": "Proxy port", - "proxy-port-required": "Proxy port is required.", - "proxy-port-range": "Proxy port should be in a range from 1 to 65535.", - "proxy-user": "Proxy user", - "proxy-password": "Proxy password", - "change-password": "Change password", - "send-test-mail": "Send test mail", - "use-system-mail-settings": "Use System Mail Server Settings", - "mail-templates": "Mail Templates", - "mail-template-settings": "Mail Templates Settings", - "use-system-mail-template-settings": "Use System Mail Templates", - "mail-template": { - "mail-template": "Mail template", - "test": "Test email message", - "activation": "Account activation message", - "account-activated": "Account activated message", - "account-lockout": "Account lockout message", - "reset-password": "Reset password message", - "password-was-reset": "Password was reset message", - "user-activated": "User activated message", - "user-registered": "User registered message", - "api-usage-state-enabled": "Api usage state enabled", - "api-usage-state-warning": "Api usage state warning", - "api-usage-state-disabled": "Api usage state disabled", - "two-fa-verification": "2FA verification message" - }, - "mail-subject": "Mail Subject", - "mail-body": "Mail body", - "sms-provider": "SMS provider", - "sms-provider-settings": "SMS provider settings", - "use-system-sms-settings": "Use System SMS provider settings", - "sms-provider-type": "SMS provider type", - "sms-provider-type-required": "SMS provider type is required.", - "sms-provider-type-aws-sns": "Amazon SNS", - "sms-provider-type-twilio": "Twilio", - "sms-provider-type-smpp": "SMPP", - "aws-access-key-id": "AWS Access Key ID", - "aws-access-key-id-required": "AWS Access Key ID is required", - "aws-secret-access-key": "AWS Secret Access Key", - "aws-secret-access-key-required": "AWS Secret Access Key is required", - "aws-region": "AWS Region", - "aws-region-required": "AWS Region is required", - "number-from": "Phone Number From", - "number-from-required": "Phone Number From is required.", - "number-to": "Phone Number To", - "number-to-required": "Phone Number To is required.", - "phone-number-hint": "Phone Number in E.164 format, ex. +19995550123", - "phone-number-hint-twilio": "Phone Number in E.164 format/Phone Number's SID/Messaging Service SID, ex. +19995550123/PNXXX/MGXXX", - "phone-number-pattern": "Invalid phone number. Should be in E.164 format, ex. +19995550123.", - "phone-number-pattern-twilio": "Invalid phone number. Should be in E.164 format/Phone Number's SID/Messaging Service SID, ex. +19995550123/PNXXX/MGXXX.", - "sms-message": "SMS message", - "sms-message-required": "SMS message is required.", - "sms-message-max-length": "SMS message can't be longer 1600 characters", - "twilio-account-sid": "Twilio Account SID", - "twilio-account-sid-required": "Twilio Account SID is required", - "twilio-account-token": "Twilio Account Token", - "twilio-account-token-required": "Twilio Account Token is required", - "send-test-sms": "Send test SMS", - "test-sms-sent": "Test SMS was successfully sent!", - "security-settings": "Security settings", - "password-policy": "Password policy", - "minimum-password-length": "Minimum password length", - "minimum-password-length-required": "Minimum password length is required", - "minimum-password-length-range": "Minimum password length should be in a range from 5 to 50", - "minimum-uppercase-letters": "Minimum number of uppercase letters", - "minimum-uppercase-letters-range": "Minimum number of uppercase letters can't be negative", - "minimum-lowercase-letters": "Minimum number of lowercase letters", - "minimum-lowercase-letters-range": "Minimum number of lowercase letters can't be negative", - "minimum-digits": "Minimum number of digits", - "minimum-digits-range": "Minimum number of digits can't be negative", - "minimum-special-characters": "Minimum number of special characters", - "minimum-special-characters-range": "Minimum number of special characters can't be negative", - "password-expiration-period-days": "Password expiration period in days", - "password-expiration-period-days-range": "Password expiration period in days can't be negative", - "password-reuse-frequency-days": "Password reuse frequency in days", - "password-reuse-frequency-days-range": "Password reuse frequency in days can't be negative", - "allow-whitespace": "Allow whitespace", - "general-policy": "General policy", - "max-failed-login-attempts": "Maximum number of failed login attempts, before account is locked", - "minimum-max-failed-login-attempts-range": "Maximum number of failed login attempts can't be negative", - "user-lockout-notification-email": "In case user account lockout, send notification to email", - "domain-name": "Domain name", - "domain-name-unique": "Domain name and protocol need to unique.", - "domain-name-max-length": "Domain name should be less than 256", - "error-verification-url": "A domain name shouldn't contain symbols '/' and ':'. Example: thingsboard.io", - "connection-settings": "Connection settings", - "oauth2": { - "access-token-uri": "Access token URI", - "access-token-uri-required": "Access token URI is required.", - "activate-user": "Activate user", - "add-domain": "Add domain", - "delete-domain": "Delete domain", - "add-provider": "Add provider", - "delete-provider": "Delete provider", - "allow-user-creation": "Allow user creation", - "always-fullscreen": "Always fullscreen", - "authorization-uri": "Authorization URI", - "authorization-uri-required": "Authorization URI is required.", - "client-authentication-method": "Client authentication method", - "client-id": "Client ID", - "client-id-required": "Client ID is required.", - "client-id-max-length": "Client ID should be less than 256", - "client-secret": "Client secret", - "client-secret-required": "Client secret is required.", - "client-secret-max-length": "Client secret should be less than 2049", - "custom-setting": "Custom settings", - "customer-name-pattern": "Customer name pattern", - "customer-name-pattern-max-length": "Customer name pattern should be less than 256", - "parent-customer-name-pattern": "Parent customer name pattern", - "user-groups-name-pattern": "User groups name pattern", - "default-dashboard-name": "Default dashboard name", - "default-dashboard-name-max-length": "Default dashboard name should be less than 256", - "delete-domain-text": "Be careful, after the confirmation a domain and all provider data will be unavailable.", - "delete-domain-title": "Are you sure you want to delete settings the domain '{{domainName}}'?", - "delete-registration-text": "Be careful, after the confirmation a provider data will be unavailable.", - "delete-registration-title": "Are you sure you want to delete the provider '{{name}}'?", - "email-attribute-key": "Email attribute key", - "email-attribute-key-required": "Email attribute key is required.", - "email-attribute-key-max-length": "Email attribute key should be less than 32", - "first-name-attribute-key": "First name attribute key", - "first-name-attribute-key-max-length": "First name attribute key should be less than 32", - "general": "General", - "jwk-set-uri": "JSON Web Key URI", - "last-name-attribute-key": "Last name attribute key", - "last-name-attribute-key-max-length": "Last name attribute key should be less than 32", - "login-button-icon": "Login button icon", - "login-button-label": "Provider label", - "login-button-label-placeholder": "Login with $(Provider label)", - "login-button-label-required": "Label is required.", - "login-provider": "Login provider", - "mapper": "Mapper", - "new-domain": "New domain", - "oauth2": "OAuth2", - "password-max-length": "Password should be less than 256", - "redirect-uri-template": "Redirect URI template", - "copy-redirect-uri": "Copy redirect URI", - "registration-id": "Registration ID", - "registration-id-required": "Registration ID is required.", - "registration-id-unique": "Registration ID need to unique for the system.", - "scope": "Scope", - "scope-required": "Scope is required.", - "tenant-name-pattern": "Tenant name pattern", - "tenant-name-pattern-required": "Tenant name pattern is required.", - "tenant-name-pattern-max-length": "Tenant name pattern ishould be less than 256", - "tenant-name-strategy": "Tenant name strategy", - "type": "Mapper type", - "uri-pattern-error": "Invalid URI format.", - "url": "URL", - "url-pattern": "Invalid URL format.", - "url-required": "URL is required.", - "url-max-length": "URL should be less than 256", - "user-info-uri": "User info URI", - "user-info-uri-required": "User info URI is required.", - "username-max-length": "User name should be less than 256", - "user-name-attribute-name": "User name attribute key", - "user-name-attribute-name-required": "User name attribute key is required", - "protocol": "Protocol", - "domain-schema-http": "HTTP", - "domain-schema-https": "HTTPS", - "domain-schema-mixed": "HTTP+HTTPS", - "enable": "Enable OAuth2 settings", - "domains": "Domains", - "mobile-apps": "Mobile applications", - "no-mobile-apps": "No applications configured", - "mobile-package": "Application package", - "mobile-package-placeholder": "Ex.: my.example.app", - "mobile-package-hint": "For Android: your own unique Application ID. For iOS: Product bundle identifier.", - "mobile-package-unique": "Application package must be unique.", - "mobile-app-secret": "Application secret", - "invalid-mobile-app-secret": "Application secret must contain only alphanumeric characters and must be between 16 and 2048 characters long.", - "copy-mobile-app-secret": "Copy application secret", - "add-mobile-app": "Add application", - "delete-mobile-app": "Delete application info", - "providers": "Providers", - "platform-web": "Web", - "platform-android": "Android", - "platform-ios": "iOS", - "all-platforms": "All platforms", - "smtp-provider": "SMTP provider", - "allowed-platforms": "Allowed platforms", - "authentication": "Authentication", - "basic": "Basic", - "provider": "Provider", - "redirect-url": "Redirect URI", - "domain-name": "Domain name", - "redirect-url-template": "Redirect URI template", - "microsoft-tenant-id": "Directory (tenant) Id", - "microsoft-tenant-id-required": "Directory (tenant) Id is required", - "token-uri": "Token URI", - "token-uri-required": "Token URI is required", - "redirect-uri": "Redirect URI", - "google-provider": "Google", - "microsoft-provider": "Office 365", - "sendgrid-provider": "Sendgrid", - "custom-provider": "Custom", - "generate-access-token": "Generate access token", - "update-access-token": "Update access token", - "access-token-status": "Access token status:", - "token-status-generated": "generated", - "token-status-not-generated": "not generated" - }, - "smpp-provider": { - "smpp-version": "SMPP version", - "smpp-host": "SMPP host", - "smpp-host-required": "SMPP host is required", - "smpp-port": "SMPP port", - "smpp-port-required": "SMPP port is required", - "system-id": "System ID", - "system-id-required": "System ID is required", - "password": "Password", - "password-required": "Password is required", - "type-settings": "Type settings", - "source-settings": "Source settings", - "destination-settings": "Destination settings", - "additional-settings": "Additional settings", - "system-type": "System type", - "bind-type": "Bind type", - "service-type": "Service type", - "source-address": "Source address", - "source-ton": "Source TON", - "source-npi": "Source NPI", - "destination-ton": "Destination TON (Type of Number)", - "destination-npi": "Destination NPI (Numbering Plan Identification)", - "address-range": "Address range", - "coding-scheme": "Coding scheme", - "bind-type-tx": "Transmitter", - "bind-type-rx": "Receiver", - "bind-type-trx": "Transciever", - "ton-unknown": "Unknown", - "ton-international": "International", - "ton-national": "National", - "ton-network-specific": "Network Specific", - "ton-subscriber-number": "Subscriber Number", - "ton-alphanumeric": "Alphanumeric", - "ton-abbreviated": "Abbreviated", - "npi-unknown": "0 - Unknown", - "npi-isdn": "1 - ISDN/telephone numbering plan (E163/E164)", - "npi-data-numbering-plan": "3 - Data numbering plan (X.121)", - "npi-telex-numbering-plan": "4 - Telex numbering plan (F.69)", - "npi-land-mobile": "6 - Land Mobile (E.212)", - "npi-national-numbering-plan": "8 - National numbering plan", - "npi-private-numbering-plan": "9 - Private numbering plan", - "npi-ermes-numbering-plan": "10 - ERMES numbering plan (ETSI DE/PS 3 01-3)", - "npi-internet": "13 - Internet (IP)", - "npi-wap-client-id": "18 - WAP Client Id (to be defined by WAP Forum)", - "scheme-smsc": "0 - SMSC Default Alphabet (ASCII for short and long code and to GSM for toll-free)", - "scheme-ia5": "1 - IA5 (ASCII for short and long code, Latin 9 for toll-free (ISO-8859-9))", - "scheme-octet-unspecified-2": "2 - Octet Unspecified (8-bit binary)", - "scheme-latin-1": "3 - Latin 1 (ISO-8859-1)", - "scheme-octet-unspecified-4": "4 - Octet Unspecified (8-bit binary)", - "scheme-jis": "5 - JIS (X 0208-1990)", - "scheme-cyrillic": "6 - Cyrillic (ISO-8859-5)", - "scheme-latin-hebrew": "7 - Latin/Hebrew (ISO-8859-8)", - "scheme-ucs-utf": "8 - UCS2/UTF-16 (ISO/IEC-10646)", - "scheme-pictogram-encoding": "9 - Pictogram Encoding", - "scheme-music-codes": "10 - Music Codes (ISO-2022-JP)", - "scheme-extended-kanji-jis": "13 - Extended Kanji JIS (X 0212-1990)", - "scheme-korean-graphic-character-set": "14 - Korean Graphic Character Set (KS C 5601/KS X 1001)" - }, - "queue-select-name": "Select queue name", - "queue-name": "Name", - "queue-name-required": "Queue name is required!", - "queues": "Queues", - "queue-partitions": "Partitions", - "queue-submit-strategy": "Submit strategy", - "queue-processing-strategy": "Processing strategy", - "queue-configuration": "Queue configuration", - "repository-settings": "Repository settings", - "repository": "Repository", - "repository-url": "Repository URL", - "repository-url-required": "Repository URL is required.", - "default-branch": "Default branch name", - "repository-read-only": "Read-only", - "show-merge-commits": "Show merge commits", - "authentication-settings": "Authentication settings", - "auth-method": "Authentication method", - "auth-method-username-password": "Password / access token", - "auth-method-username-password-hint": "GitHub users must use access tokens with write permissions to the repository.", - "auth-method-private-key": "Private key", - "password-access-token": "Password / access token", - "change-password-access-token": "Change password / access token", - "private-key": "Private key", - "drop-private-key-file-or": "Drag and drop a private key file or", - "passphrase": "Passphrase", - "enter-passphrase": "Enter passphrase", - "change-passphrase": "Change passphrase", - "check-access": "Check access", - "check-repository-access-success": "Repository access successfully verified!", - "delete-repository-settings-title": "Are you sure you want to delete repository settings?", - "delete-repository-settings-text": "Be careful, after the confirmation the repository settings will be removed and version control feature will be unavailable.", - "auto-commit-settings": "Auto-commit settings", - "auto-commit": "Auto-commit", - "auto-commit-entities": "Auto-commit entities", - "no-auto-commit-entities-prompt": "No entities configured for auto-commit", - "delete-auto-commit-settings-title": "Are you sure you want to delete auto-commit settings?", - "delete-auto-commit-settings-text": "Be careful, after the confirmation the auto-commit settings will be removed and auto-commit will be disabled for all entities.", - "2fa": { - "2fa": "Two-factor authentication", - "available-providers": "Available providers", - "issuer-name": "Issuer name", - "issuer-name-required": "Issuer name is required.", - "max-verification-failures-before-user-lockout": "Max verification failures before user lockout", - "max-verification-failures-before-user-lockout-pattern": "Max verification failures must be a positive integer.", - "number-of-checking-attempts": "Number of checking attempts", - "number-of-checking-attempts-pattern": "Number of checking attempts must be a positive integer.", - "number-of-checking-attempts-required": "Number of checking attempts is required.", - "number-of-codes": "Number of codes", - "number-of-codes-pattern": "Number of codes must be a positive integer.", - "number-of-codes-required": "Number of codes is required.", - "provider": "Provider", - "retry-verification-code-period": "Retry verification code period (sec)", - "retry-verification-code-period-pattern": "Minimal period time is 5 sec", - "retry-verification-code-period-required": "Retry verification code period is required.", - "total-allowed-time-for-verification": "Total allowed time for verification (sec)", - "total-allowed-time-for-verification-pattern": "Minimal total allowed time is 60 sec", - "total-allowed-time-for-verification-required": "Total allowed time is required.", - "use-system-two-factor-auth-settings": "Use system two factor auth settings", - "verification-code-check-rate-limit": "Verification code check rate limit", - "verification-code-lifetime": "Verification code lifetime (sec)", - "verification-code-lifetime-pattern": "Verification code lifetime must be a positive integer.", - "verification-code-lifetime-required": "Verification code lifetime is required.", - "verification-message-template": "Verification message template", - "verification-limitations": "Verification limitations", - "verification-message-template-pattern": "Verification message need to contains pattern: ${code}", - "verification-message-template-required": "Verification message template is required.", - "within-time": "Within time (sec)", - "within-time-pattern": "Time must be a positive integer.", - "within-time-required": "Time is required." - }, - "jwt": { - "security-settings": "JWT security settings", - "issuer-name": "Issuer name", - "issuer-name-required": "Issuer name is required.", - "signings-key": "Signing key", - "signings-key-hint": "Base64 encoded string representing at least 256 bits of data.", - "signings-key-required": "Signing key is required.", - "signings-key-min-length": "Signing key must be at least 256 bits of data.", - "signings-key-base64": "Signing key must be base64 format.", - "expiration-time": "Token expiration time (sec)", - "expiration-time-required": "Token expiration time is required.", - "expiration-time-min": "Minimum time is 60 seconds (1 minute).", - "refresh-expiration-time": "Refresh token expiration time (sec)", - "refresh-expiration-time-required": "Refresh token expiration time is required.", - "refresh-expiration-time-min": "Minimum time is 900 seconds (15 minute).", - "refresh-expiration-time-less-token": "Refresh token time must be greater token time.", - "generate-key": "Generate key", - "info-header": "All users will be to re-logined", - "info-message": "Change of the JWT Signing Key will cause all issued tokens to be invalid. All users will need to re-login. This will also affect scripts that use Rest API/Websockets." - }, - "resources": "Resources", - "notifications": "Notifications", - "notifications-settings": "Notifications settings", - "slack-api-token": "Slack API token", - "slack": "Slack", - "slack-settings": "Slack settings" - }, - "alarm": { - "alarm": "Įspėjimas", - "alarms": "Įspėjimai", - "all-alarms": "Visi Įspėjimai", - "select-alarm": "Pasirinkti įspėjimą", - "no-alarms-matching": "Su '{{entity}}' susijusių įspėjimų nėra.", - "alarm-required": "Įspėjimas yra privalomas", - "alarm-filter": "Įspėjimų filtras", - "filter": "Filtras", - "alarm-status": "Įspėjimo statusas", - "alarm-status-list": "Įspėjimo statusų sąrašas", - "any-status": "Visi statusai", - "search-status": { - "ANY": "Visi", - "ACTIVE": "Aktyvūs", - "CLEARED": "Atmesti", - "ACK": "Pripažinti", - "UNACK": "Nepatvirtinti" - }, - "display-status": { - "ACTIVE_UNACK": "Aktyvūs nepatvirtinti", - "ACTIVE_ACK": "Aktyvūs pripažinti", - "CLEARED_UNACK": "Atmesti nepatvirtinti", - "CLEARED_ACK": "Atmesti pripažinti" - }, - "no-alarms-prompt": "Įspėjimų nėra", - "created-time": "Sukūrimo laikas", - "type": "Tipas", - "severity": "Lygis", - "originator": "Iniciatorius", - "originator-type": "Iniciatoriaus tipas", - "details": "Pastabos", - "originator-label": "Iniciatoriaus pavadinimas", - "assign": "Priskirti", - "assignments": "Priskyrimai", - "assignee": "Atsakingas", - "assignee-id": "Atsakingo asmens ID", - "assignee-first-name": "Atsakingo asmens vardas", - "assignee-last-name": "Atsakingo asmens pavardė", - "assignee-email": "Atsakingo asmens e-paštas", - "unassigned": "Panaikinti priskyrimą", - "assignee-not-set": "Visi", - "status": "Statusas", - "alarm-details": "Įspėjimo pastabos", - "start-time": "Pradžia", - "assign-time": "Priskyrimo laikas", - "end-time": "Pabaiga", - "ack-time": "Pripažinimo laikas", - "clear-time": "Atmetimo laikas", - "duration": "Trukmė", - "alarm-severity-list": "Įspėjimų lygiai", - "any-severity": "Visi lygiai", - "severity-critical": "Kritinis", - "severity-major": "Svarbus", - "severity-minor": "Antraeilis", - "severity-warning": "Įspėjimas", - "severity-indeterminate": "Nenustatytas", - "acknowledge": "Patvirtinti", - "clear": "Atmesti", - "delete": "Panaikinti", - "search": "Įspėjimo paieška", - "selected-alarms": "Pasirinkta { count, plural, =1 {1 įspėjimas} other {# įspėjimai} }", - "no-data": "Nėra duomenų", - "polling-interval": "Įspėjimų tikrinimo intervalas (sek)", - "polling-interval-required": "Reikalingas įspėjimų tikrinimo intervalas", - "min-polling-interval-message": "Mažiausias įspėjimų tikrinimo intervalas yra 1 sekundė.", - "aknowledge-alarms-title": "Pripažinti { count, plural, =1 {1 įspėjimą} other {# įspėjimus} }", - "aknowledge-alarms-text": "Pripažinti { count, plural, =1 {1 įspėjimą} other {# įspėjimus} }?", - "aknowledge-alarm-title": "Pripažinti įspėjimą", - "aknowledge-alarm-text": "Pripažinti įspėjimą?", - "selected-alarms-are-acknowledged": "Pasirinkti įspėjimai pripažinti", - "clear-alarms-title": "Atmesti { count, plural, =1 {1 įspėjimą} other {# įspėjimus} }", - "clear-alarms-text": "Atmesti { count, plural, =1 {1 įspėjimą} other {# įspėjimus} }?", - "clear-alarm-title": "Atmesti įspėjimą", - "clear-alarm-text": "Atmesti įspėjimą?", - "delete-alarms-title": "Panaikinti { count, plural, =1 {1 įspėjimą} other {# įspėjimus} }", - "delete-alarms-text": "Panaikinti { count, plural, =1 {1 įspėjimą} other {# įspėjimus} }?", - "selected-alarms-are-cleared": "Pasirinkti įspėjimai atmesti", - "alarm-status-filter": "Įspėjimų statusai", - "alarm-filter-title": "Įspėjimų filtras", - "assigned": "Priskirta", - "filter-title": "Filtras", - "max-count-load": "Didžiausias rodomų įspėjimų skaičius (0 – neribotas)", - "max-count-load-required": "Reikalingas didžiausias rodomų įspėjimų skaičius (0 – neribotas).", - "max-count-load-error-min": "Mažiausia reikšmė yra 0.", - "fetch-size": "Fetch size", - "fetch-size-required": "Fetch size is required.", - "fetch-size-error-min": "Mažiausia rekšmė yra 10.", - "alarm-type-list": "Įspėjimų tipai", - "any-type": "Visi tipai", - "assigned-to-current-user": "Priskirta prisijungusiam vartotojui", - "assigned-to-me": "Priskirta man", - "search-propagated-alarms": "Ieškoti išplatintų įspėjimų", - "comments": "Įspėjimo pastabos", - "show-more": "Rodyti daugiau", - "additional-info": "Papildoma informacija", - "alarm-type": "Įspėjimo tipas", - "enter-alarm-type": "Įveskite įspėjimo tipą", - "no-alarm-types-matching": "Nėra įspėjimų tipų, kurie atitiktų '{{entitySubtype}}'.", - "alarm-type-list-empty": "Nepasirinktas įspėjimų tipas" - }, - "alarm-activity": { - "add": "Pridėti komentarą...", - "alarm-comment": "Įspėjimo komentaras", - "comments": "Komentarai", - "delete-alarm-comment": "Ištrinti komentarą?", - "refresh": "Atnaujinti", - "oldest-first": "Seniausi viršuje", - "newest-first": "Naujausi viršuje", - "activity": "Veikla", - "export": "Eksportuoti į CSV", - "author": "Sukūrė", - "created-date": "Sukūrimo dara", - "edited-date": "Redagavimo data", - "text": "Tekstas", - "system": "Sistema" - }, - "alias": { - "add": "Pridėti pseudonimą", - "edit": "Redaguoti pseudonimą", - "name": "Pseudonimas", - "name-required": "Reikalingas pseudonimas", - "duplicate-alias": "Toks pseudonimas sistemoje jau yra.", - "filter-type-single-entity": "Vienas subjektas", - "filter-type-entity-group": "Subjektų grupė", - "filter-type-entity-list": "Subjektų sąrašas", - "filter-type-entity-name": "Subjekto pavadinimas", - "filter-type-entity-type": "Subjekto tipas", - "filter-type-entity-group-list": "Subjektų grupių sąrašas", - "filter-type-entity-group-name": "Subjektų grupės pavadinimas", - "filter-type-entities-by-group-name": "Subjektai pagal grupės pavadinimą", - "filter-type-state-entity": "Subjektas iš skydelio būsenos", - "filter-type-state-entity-description": "Subjektas iš skydelio būsenos parametrų", - "filter-type-state-entity-owner": "Skydelio būsenos subjekto savininkas", - "filter-type-state-entity-owner-description": "Subjekto, iš skydelio būsenos parametrų, savininkas", - "filter-type-asset-type": "Turto tipas", - "filter-type-asset-type-description": "Turtas, kurio tipas '{{assetTypes}}'", - "filter-type-asset-type-and-name-description": "Turtas, kurio tipas '{{assetTypes}}' ir kurio pavadinimas prasideda '{{prefix}}'", - "filter-type-device-type": "Įrenginio tipas", - "filter-type-device-type-description": "Įrenginiai, kurių tipas '{{deviceTypes}}'", - "filter-type-device-type-and-name-description": "Įrenginiai, kurių tipas '{{deviceTypes}}' ir kurių pavadinimai '{{prefix}}'", - "filter-type-entity-view-type": "Subjekto rodinio tipas", - "filter-type-entity-view-type-description": "Subjektų rodiniai, kurių tipas '{{entityViewTypes}}'", - "filter-type-entity-view-type-and-name-description": "Subjektų rodiniai, kurių tipas '{{entityViewTypes}}' ir kurių pavadinimai prasideda '{{prefix}}'", - "filter-type-edge-type": "Edge type", - "filter-type-edge-type-description": "Edges of type '{{edgeTypes}}'", - "filter-type-edge-type-and-name-description": "Edges of type '{{edgeTypes}}' and with name starting with '{{prefix}}'", - "filter-type-relations-query": "Ryšių užklausa", - "filter-type-relations-query-description": "{{entities}} kurie turi {{relationType}} ryšį {{direction}} {{rootEntity}}", - "filter-type-edge-search-query": "Edge search query", - "filter-type-edge-search-query-description": "Edges with types {{edgeTypes}} that have {{relationType}} relation {{direction}} {{rootEntity}}", - "filter-type-scheduler-event": "Scheduler events", - "filter-type-scheduler-event-type-description": "Scheduler events with type '{{eventType}}'", - "filter-type-scheduler-event-originator-description": "Scheduler events of specific originator", - "filter-type-scheduler-event-type-originator-description": "Scheduler events of specific originator with '{{eventType}}'", - "filter-type-asset-search-query": "Turto paieškos užklausa", - "filter-type-asset-search-query-description": "{{assetTypes}} tipo turtas, turintis {{relationType}} tipo ryšį {{direction}} {{rootEntity}}", - "filter-type-device-search-query": "Įrenginio paieškos užklausa", - "filter-type-device-search-query-description": "{{deviceTypes}} tipo įrenginiai, turintys {{relationType}} tipo ryšį {{direction}} {{rootEntity}}", - "filter-type-entity-view-search-query": "Subjektų rodinio paieškos užklausa", - "filter-type-entity-view-search-query-description": "{{entityViewTypes}} tipo subjektai, turintys {{relationType}} tipo ryšį {{direction}} {{rootEntity}}", - "filter-type-apiUsageState": "Api Usage State", - "entity-filter": "Subjektų filtras", - "resolve-multiple": "Traktuoti kaip kelis subjektus", - "filter-type": "Filtro tipas", - "filter-type-required": "Filtro tipas būtinas.", - "entity-filter-no-entity-matched": "Subjektų, atitinkančių filtro kriterijus, nerasta.", - "no-entity-filter-specified": "Subjektų filtras nenustatytas", - "root-state-entity": "Subjektą, iš skydelio būsenos, naudoti kaip pagrindinį", - "group-state-entity": "Skydelio būsenos subjektą naudoti kaip subjektų grupę", - "group-state-entity-owner": "Skydelio būsenos subjektą naudoti kaip subjektų grupės sąvininką", - "last-level-relation": "Gauti tik paskutinio lygio ryšį", - "root-entity": "Pagridinis subjektas", - "state-entity-parameter-name": "Būsenos subjekto parametro pavadinimas", - "default-state-entity": "Numatytasis būsenos subjektas", - "default-state-entity-group": "Numatytoji būsenos subjektų grupė", - "default-entity-parameter-name": "Pagal nutylėjimą", - "max-relation-level": "Maksimalus ryšių lygis", - "unlimited-level": "Neribojamas lygis", - "state-entity": "Skydelio būsenos subjektas", - "entities-of-group-state-entity": "Subjektai iš skydelio būsenos subjektų grupės", - "all-entities": "Visi subjektai", - "any-relation": "visi", - "originator": "Iniciatorius", - "originator-state-entity": "Skydelio būsenos subjektą naudoti kaip iniciatorių", - "scheduler-event-type": "Scheduler event type" - }, - "asset": { - "all": "Visas", - "all-assets": "Visas turtas", - "groups": "Grupės", - "shared": "Bendrinamas", - "asset": "Turtas", - "assets": "Turtas", - "management": "Turto valdymas", - "view-assets": "Peržiūrėti turtą", - "add": "Pridėti turtą", - "asset-type-max-length": "Turto tipas turi būti trumpesnis nei 256 simboliai", - "assign-to-customer": "Priskirti klientui", - "assign-asset-to-customer": "Turtą priskirti klientui", - "assign-asset-to-customer-text": "Pasirinkite turtą, kurį norite priskiri klientui", - "no-assets-text": "Turto nerasta", - "assign-to-customer-text": "Pasirinkite klientą, kuriam priskiriamas turtas", - "public": "Viešas", - "assignedToCustomer": "Priskirti klientui", - "make-public": "Neriboti turto matomumo", - "make-private": "Riboti turto matomumą", - "unassign-from-customer": "Atsieti nuo kliento", - "delete": "Panaikinti turtą", - "asset-public": "Turtas yra viešas", - "asset-type": "Turto tipas", - "asset-type-required": "Turto tipas būtinas.", - "select-asset-type": "Pasirinkite turto tipą", - "enter-asset-type": "Įveskite turto tipą", - "any-asset": "Visas turtas", - "no-asset-types-matching": "Turto tipas, atitinkantis '{{entitySubtype}}', nerastas.", - "asset-type-list-empty": "Nepasirinkti turto tipai.", - "asset-types": "Turto tipai", - "name": "Pavadinimas", - "name-required": "Pavadinimas yra privalomas.", - "name-max-length": "Pavadinimas turi būti trumpesnis nei 256 simboliai", - "label-max-length": "Vardas turi būti trumpesnis nei 256 simboliai", - "description": "Aprašymas", - "type": "Tipas", - "type-required": "Tipas yra prvalomas.", - "details": "Pastabos", - "events": "Įvykiai", - "add-asset-text": "Pridėti turtą", - "asset-details": "Pastabos apie turtą", - "assign-assets": "Priskirti turtą", - "assign-assets-text": "Priskirti { count, plural, =1 {1 turtą} other {# turtus} } to customer", - "assign-asset-to-edge-title": "Assign Asset(s) To Edge", - "assign-asset-to-edge-text": "Please select the assets to assign to the edge", - "delete-assets": "Pašalinti turtą", - "unassign-assets": "Atsieti turtą", - "unassign-assets-action-title": "Atsieti { count, plural, =1 {1 turtą} other {# turtus} } nuo kliento?", - "assign-new-asset": "Prisirti naują turtą", - "delete-asset-title": "Pašalinti '{{assetName}}' turtą?", - "delete-asset-text": "Būkite dėmesingi, po patvirtinimo, turtas ir su juo susijusi informacija, bus pašalinta.", - "delete-assets-title": "Pašalinti { count, plural, =1 {1 turtą} other {# turtus} }?", - "delete-assets-action-title": "Pašalinti { count, plural, =1 {1 turtą} other {# turtus} }", - "delete-assets-text": "Būkite dėmesingi, po patvirtinimo, visi turto įrašai ir su jais susijusi informacija, bus pašalinta.", - "make-public-asset-title": "Ar tikrai norite neriboti turto '{{assetName}}' matomumo?", - "make-public-asset-text": "Po patvirtinimo turtas ir visa su juo susijusi informacija bus prieinama visiems.", - "make-private-asset-title": "Ar tikrai norite riboti turto '{{assetName}}' matomumą?", - "make-private-asset-text": "Po patvirtinimo, turtas ir visa su juo susijusi informacija nebus prieinama kitiems.", - "unassign-asset-title": "Ar tikrai norite atsieti turtą '{{assetName}}'?", - "unassign-asset-text": "Po patvirtinimo turtas bus atsietas ir klientas neteks prieigos prie jo.", - "unassign-asset": "Atsieti turtą", - "unassign-assets-title": "Ar tikrai norite atsieti { count, plural, =1 {1 turtą} other {# turtus} }?", - "unassign-assets-text": "Po patvirtinimo visas turtas bus atsietas ir klientas neteks prieigos prie jo.", - "copyId": "Kopijuoti turto Id", - "idCopiedMessage": "Turto Id nukopijuotas į iškarpinę", - "select-asset": "Pasirinkti turtą", - "no-assets-matching": "Turtas atitinkantis '{{entity}}' nerastas.", - "asset-required": "Turtas būtinas", - "name-starts-with": "Turto pavadinimas prasideda", - "help-text": "naudokite simbolį '%' pagal tai, kaip norite ieškoti: '%turto_pavadinimo_fragmentas%', '%turto_pavadinimo_pabaiga', 'turto_pavadinimo_pradžia%'.", - "search": "Turto paieška", - "select-group-to-add": "Pasirinkti grupę, į kurią turtą pridėti", - "select-group-to-move": "Pasirinkite grupę, į kurią turtą perkelti", - "remove-assets-from-group": "Ar tikrai norite { count, plural, =1 {1 turtą} other {# turtus} } pašalinti iš grupės '{{entityGroup}}'?", - "group": "Turto grupė", - "list-of-groups": "{ count, plural, =1 {Viena turto grupė} other { # Turto grupių sąrašas} }", - "group-name-starts-with": "Turto grupės, kurių pavadinimai prasideda '{{prefix}}'", - "import": "Importuoti turtą", - "asset-file": "Turto failas", - "label": "Etiketė", - "assign-asset-to-edge": "Assign Asset(s) To Edge", - "unassign-asset-from-edge": "Unassign asset", - "unassign-asset-from-edge-title": "Are you sure you want to unassign the asset '{{assetName}}'?", - "unassign-asset-from-edge-text": "After the confirmation the asset will be unassigned and won't be accessible by the edge.", - "unassign-assets-from-edge-title": "Are you sure you want to unassign { count, plural, =1 {1 asset} other {# assets} }?", - "unassign-assets-from-edge-text": "After the confirmation all selected assets will be unassigned and won't be accessible by the edge.", - "selected-assets": "Pasirinkta { count, plural, =1 {1 turtas} other {# turtai} }" - }, - "attribute": { - "attributes": "Atributai", - "latest-telemetry": "Paskutinė telemetrija", - "no-latest-telemetry": "Telemetrijos nėra", - "attributes-scope": "Subjekto atributų kontekstas", - "scope-telemetry": "Telemetrija", - "scope-latest-telemetry": "Paskutinė telemetrija", - "scope-client": "Kliento atributai", - "scope-server": "Serverio atributai", - "scope-shared": "Bendrinami atributai", - "add": "Pridėti atributą", - "add-attribute-prompt": "Pridėkite atributą", - "key": "Raktas", - "key-max-length": "Raktas negali viršyti 256 simbolių", - "last-update-time": "Atnaujinimo laikas", - "key-required": "Atributo raktas būtinas.", - "value": "Reikšmė", - "value-required": "Atributo reikšmė būtina.", - "telemetry-key-required": "Telemetrijos raktas būtinas", - "telemetry-value-required": "Telemetrijos reikšmė būtina", - "delete-attributes-title": "Ar tikrai norite pašalinti { count, plural, =1 {1 atributą} other {# atributus} }?", - "delete-attributes-text": "Būkite dėmesingi, po patvirtinimo pasirinkti atributai bus pašalinti.", - "delete-attributes": "Pašalinti atributus", - "enter-attribute-value": "Įveskite atributo reikšmę", - "show-on-widget": "Rodyti valdiklyje", - "widget-mode": "Valdiklio režimas", - "next-widget": "Sekantis valdiklis", - "prev-widget": "Ankstesnis valdiklis", - "add-to-dashboard": "Pridėti į skydelį", - "add-widget-to-dashboard": "Pridėti valdiklį į skydelį", - "selected-attributes": "Pasirinkta { count, plural, =1 {1 atributas} other {# atributai} }", - "selected-telemetry": "Pasirinkta { count, plural, =1 {1 telemetrijos blokas} other {# telemetrijos blokai} }", - "no-attributes-text": "Atributų nėra", - "no-telemetry-text": "Telemetrijos nėra", - "copy-key": "Kopijuoti raktą", - "add-telemetry": "Pridėti telemetriją", - "copy-value": "Kopijuoti reikšmę", - "delete-timeseries": { - "start-time": "Pradžia", - "ends-on": "Pabaiga", - "strategy": "Strategija", - "delete-strategy": "Šalinimo startegija", - "all-data": "Pašalinti visus duomenis", - "all-data-except-latest-value": "Pašalinti visus duomenis išskyrus naujausią reikšmę", - "latest-value": "Pašalinti naujausią reikšmę", - "all-data-for-time-period": "Pašalinti visus duomenis periodui", - "rewrite-latest-value": "Perrašyti naujausią reikšmę" - } +{ + "access": { + "unauthorized": "Neautorizuotas", + "unauthorized-access": "Neautorizuota prieiga", + "unauthorized-access-text": "Prieiga prie šio funkcionalumo leidžiama tik prisijungusiam vartotojui!", + "access-forbidden": "Prieiga uždrausta", + "access-forbidden-text": "Neturite teisių prieigai!
Bandykite prisijungti kitu vartotoju.", + "refresh-token-expired": "Sesijos galiojimas baigėsi", + "refresh-token-failed": "Sesijos atnaujinti nepavyksta", + "permission-denied": "Leidimas nesuteiktas", + "permission-denied-text": "Šio veiksmo atlikti negalite!" + }, + "account": { + "account": "Paskyra", + "notification-settings": "Pranešimų nustatymai" + }, + "action": { + "activate": "Aktyvuoti", + "suspend": "Sustabdyti", + "save": "Išsaugoti", + "saveAs": "Išsaugoti kaip", + "move": "Perkelti", + "cancel": "Atmesti", + "ok": "OK", + "delete": "Panaikinti", + "add": "Pridėti", + "yes": "Taip", + "no": "Ne", + "update": "Atnaujinti", + "remove": "Panaikinti", + "search": "Paieška", + "clear-search": "Išvalyti", + "assign": "Priskirti", + "unassign": "Atsieti", + "share": "Pasidalinti", + "make-private": "Riboti matomumą", + "apply": "Taikyti", + "apply-changes": "Pritaikyti pakeitimus", + "edit-mode": "Redagavimo režimas", + "enter-edit-mode": "Redagavimo režimas", + "decline-changes": "Atšaukti pakeitimus", + "decline": "Atšaukti", + "close": "Uždaryti", + "back": "Atgal", + "run": "Paleisti", + "sign-in": "Prisijunkite!", + "edit": "Redaguoti", + "view": "Peržiūrėti", + "create": "Kurti", + "drag": "Vilkti", + "refresh": "Atnaujinti", + "undo": "Atšaukti", + "copy": "Kopijuoti", + "paste": "Įklijuoti", + "copy-reference": "Kopijuoti nuorodą", + "paste-reference": "Įklijuoti nuorodą", + "import": "Importuoti", + "export": "Eksportuoti", + "share-via": "Pasidalinti per {{provider}}", + "select": "Pasirinkti", + "continue": "Tęsti", + "discard-changes": "Atsisakyti pakeitimų", + "download": "Parsisiųsti", + "next": "Sekantis", + "next-with-label": "Sekantis: {{label}}", + "read-more": "Skaityti daugiau", + "hide": "Paslėpti", + "test": "Test", + "done": "Atlikta", + "print": "Spausdinti", + "restore": "Atkurti", + "confirm": "Patvirtinti", + "more": "Daugiau", + "less": "Mažiau", + "skip": "Praleisti", + "send": "Siųsti", + "reset": "Nustatyti iš naujo", + "show-more": "Rodyti daugiau", + "dont-show-again": "Daugiau neberodyti", + "see-documentation": "Žiūrėti dokumentacijoje", + "clear": "Išvalyti", + "upload": "Įkelti", + "delete-anyway": "Trinti vistike", + "delete-selected": "Trinti pasirinktą", + "set": "Nustatyti" + }, + "aggregation": { + "aggregation": "Agregavimas", + "function": "Duomenų aggregavimo funkcija", + "limit": "Maksimali reikšmė", + "group-interval": "Grupavimo intervalas", + "min": "Min", + "max": "Max", + "avg": "Vidurkis", + "sum": "Sum", + "count": "Kiekis", + "none": "Nėra" + }, + "admin": { + "settings": "Nustatymai", + "general": "Bendrieji", + "general-settings": "Bendrieji nustatymai", + "home-settings": "Pagrindinio puslapio nustatymai", + "home": "Pagrindinis puslapis", + "outgoing-mail": "Pašto serveris", + "outgoing-mail-settings": "Išeinančio pašto serverio nustatymai", + "system-settings": "Sistemos nustatymai", + "test-mail-sent": "Bandomasis laiškas sėkmingai išsiųstas!", + "base-url": "Pagrindinis URL", + "base-url-required": "Pagrindinis URL yra privalomas.", + "prohibit-different-url": "Drausti naudoti kliento užklausų antraštėse nurodytą pagrindinio kompiuterio pavadinimą", + "prohibit-different-url-hint": "Šis nustatymas turėtų būti įjungtas gamybinėje aplinkoje. Jo išjungimas gali sukelti saugumo problemų", + "device-connectivity": { + "device-connectivity": "Įrenginių jungiamumas", + "http-s": "HTTP(s)", + "mqtt-s": "MQTT(s)", + "coap-s": "COAP(s)", + "http": "HTTP", + "https": "HTTPs", + "mqtt": "MQTT", + "mqtts": "MQTTs", + "coap": "COAP", + "coaps": "COAPs", + "hint": "Jei laukeliai 'host' arba 'port' yra tušti, bus naudojamos numatytosios protokolo reikšmės.", + "host": "Host", + "port": "Port", + "port-pattern": "Port turi būti teigiamas sveikasis skaičius.", + "port-range": "Port turi būti nuo 1 iki 65535." }, - "api-usage": { - "api-features": "API features", - "api-usage": "Api Usage", - "alarm": "Alarm", - "alarms-created": "Alarms created", - "alarms-created-daily-activity": "Alarms created daily activity", - "alarms-created-hourly-activity": "Alarms created hourly activity", - "alarms-created-monthly-activity": "Alarms created monthly activity", - "data-points": "Data points", - "data-points-storage-days": "Data points storage days", - "device-api": "Device API", - "email": "Email", - "email-messages": "Email messages", - "email-messages-daily-activity": "Email messages daily activity", - "email-messages-monthly-activity": "Email messages monthly activity", - "exceptions": "Exceptions", - "executions": "Executions", - "javascript": "JavaScript", - "javascript-executions": "JavaScript executions", - "javascript-functions": "JavaScript functions", - "javascript-functions-daily-activity": "JavaScript functions daily activity", - "javascript-functions-hourly-activity": "JavaScript functions hourly activity", - "javascript-functions-monthly-activity": "JavaScript functions monthly activity", - "latest-error": "Latest Error", - "messages": "Messages", - "notifications": "Notifications", - "notifications-email-sms": "Notifications (Email/SMS)", - "notifications-hourly-activity": "Notifications hourly activity", - "permanent-failures": "${entityName} Permanent Failures", - "permanent-timeouts": "${entityName} Permanent Timeouts", - "processing-failures": "${entityName} Processing Failures", - "processing-failures-and-timeouts": "Processing Failures and Timeouts", - "processing-timeouts": "${entityName} Processing Timeouts", - "queue-stats": "Queue Stats", - "rule-chain": "Rule Chain", - "rule-engine": "Rule Engine", - "rule-engine-daily-activity": "Rule Engine daily activity", - "rule-engine-executions": "Rule Engine executions", - "rule-engine-hourly-activity": "Rule Engine hourly activity", - "rule-engine-monthly-activity": "Rule Engine monthly activity", - "rule-engine-statistics": "Rule Engine Statistics", - "rule-node": "Rule Node", - "sms": "SMS", - "sms-messages": "SMS messages", - "sms-messages-daily-activity": "SMS messages daily activity", - "sms-messages-monthly-activity": "SMS messages monthly activity", - "successful": "${entityName} Successful", - "telemetry": "Telemetry", - "telemetry-persistence": "Telemetry persistence", - "telemetry-persistence-daily-activity": "Telemetry persistence daily activity", - "telemetry-persistence-hourly-activity": "Telemetry persistence hourly activity", - "telemetry-persistence-monthly-activity": "Telemetry persistence monthly activity", - "transport": "Transport", - "transport-daily-activity": "Transport daily activity", - "transport-data-points": "Transport data points", - "transport-hourly-activity": "Transport hourly activity", - "transport-messages": "Transport messages", - "transport-monthly-activity": "Transport monthly activity", - "view-details": "View details", - "view-statistics": "View statistics" - }, - "api-limit": { - "cassandra-queries": "Cassandra queries", - "entity-version-creation": "Entity version creation", - "entity-version-load": "Entity version load", - "integration-messages": "Integration messages", - "integration-messages-per-device": "Integration messages per device", - "notification-requests": "Notification requests", - "notification-requests-per-rule": "Notification requests per rule", - "reports-generation": "Reports generation", - "rest-api-requests": "REST API requests", - "rest-api-requests-per-customer": "REST API requests per customer", - "transport-messages": "Transport messages", - "transport-messages-per-device": "Transport messages per device", - "ws-updates-per-session": "WS updates per session" - }, - "audit-log": { - "audit": "Auditas", - "audit-logs": "Audito žurnalas", - "timestamp": "Laiko žyma", - "entity-type": "Subjektas", - "entity-name": "Pavadinimas", - "user": "Vartotojas", - "type": "Veiksmas", - "status": "Statusas", - "details": "Informacija", - "type-added": "Pridėta", - "type-deleted": "Pašalinta", - "type-updated": "Atnaujinta", - "type-attributes-updated": "Attributai atnaujinti", - "type-attributes-deleted": "Atributai pašalinti", - "type-rpc-call": "RPC iškvietimas", - "type-credentials-updated": "Įgaliojimai atnaujinti", - "type-assigned-to-customer": "Priskirta klientui", - "type-unassigned-from-customer": "Atsieta nuo kliento", - "type-assigned-to-edge": "Assigned to Edge", - "type-unassigned-from-edge": "Unassigned from Edge", - "type-activated": "Aktyvuota", - "type-suspended": "Sustabdyta", - "type-credentials-read": "Įgaliojimų skaitymas", - "type-attributes-read": "Atributų skaitymas", - "type-added-to-entity-group": "Įtraukta į grupę", - "type-removed-from-entity-group": "Pašalinta iš grupės", - "type-relation-add-or-update": "ryšys atnaujintas", - "type-relation-delete": "Ryšys panaikintas", - "type-relations-delete": "Visi ryšiai panaikinti", - "type-alarm-ack": "Pripažinta", - "type-alarm-clear": "Išvalyta", - "type-alarm-assign": "Priskitas", - "type-alarm-unassign": "Atsietas", - "type-added-comment": "Pridėtas komentaras", - "type-updated-comment": "Atnaujintas komentaras", - "type-deleted-comment": "Pašalintas komentaras", - "type-rest-api-rule-engine-call": "Rule engine REST API call", - "type-made-public": "Padaryti viešu", - "type-made-private": "Padaryti privačiu", - "type-login": "Prisijungti", - "type-logout": "Atsijungti", - "type-lockout": "Užblokuoti", - "status-success": "Sėkmė", - "status-failure": "Nesėkmė", - "audit-log-details": "Informacija apie autido žurnalą", - "no-audit-logs-prompt": "Žurnalo įrašų nėra", - "action-data": "Informacija apie veiksmus", - "failure-details": "Informacija apie nesėkmę", - "search": "Žurnalo įrašų paieška", - "clear-search": "Išvalyti paiešką", - "type-assigned-from-tenant": "Priskirta valdytojo", - "type-assigned-to-tenant": "Priskirta valdytojui", - "type-provision-success": "Device provisioned", - "type-provision-failure": "Device provisioning was failed", - "type-timeseries-updated": "Telemetrija atnaujinta", - "type-timeseries-deleted": "Telemetrija pašalinta", - "type-owner-changed": "Savininkas pakeistas", - "type-sms-sent": "SMS sent" - }, - "confirm-on-exit": { - "message": "Turite neišsaugotų pakeitimų. Ar tikrai norite palikti šį puslapį?", - "html-message": "Turite neišsaugotų pakeitimų.
Ar tikrai norite palikti šį puslapį?", - "title": "Neišsaugoti pakeitimai" - }, - "contact": { - "country": "Šalis", - "city": "Miestas", - "state": "Rajonas", - "postal-code": "Pašto kodas", - "postal-code-invalid": "Neteisingas pašto kodo formatas.", - "address": "Adresas", - "address2": "Adresas 2", - "phone": "Telefonas", + "mail-from": "Laiškas nuo", + "mail-from-required": "Laukas „Laiškas nuo“ yra privalomas.", + "smtp-protocol": "SMTP protokolas", + "smtp-host": "SMTP serveris", + "smtp-host-required": "SMTP serveris yra privalomas.", + "smtp-port": "SMTP prievadas", + "smtp-port-required": "Turite nurodyti SMTP prievadą.", + "smtp-port-invalid": "Tai neatrodo kaip tinkamas SMTP prievadas.", + "timeout-msec": "Laiko limitas (msek)", + "timeout-required": "Laiko limitas yra privalomas.", + "timeout-invalid": "Tai neatrodo kaip tinkamas laiko limitas.", + "enable-tls": "Įjungti TLS", + "tls-version": "TLS versija", + "enable-proxy": "Įjungti proxy", + "proxy-host": "Proxy serveris", + "proxy-host-required": "Proxy serveris yra privalomas.", + "proxy-port": "Proxy prievadas", + "proxy-port-required": "Proxy prievadas yra privalomas.", + "proxy-port-range": "Proxy prievadas turi būti nuo 1 iki 65535.", + "proxy-user": "Proxy naudotojas", + "proxy-password": "Proxy slaptažodis", + "change-password": "Pakeisti slaptažodį", + "send-test-mail": "Siųsti bandomąjį laišką", + "sms-provider": "SMS tiekėjas", + "sms-provider-settings": "SMS tiekėjo nustatymai", + "sms-provider-type": "SMS tiekėjo tipas", + "sms-provider-type-required": "SMS tiekėjo tipas yra privalomas.", + "sms-provider-type-aws-sns": "Amazon SNS", + "sms-provider-type-twilio": "Twilio", + "sms-provider-type-smpp": "SMPP", + "aws-access-key-id": "AWS prieigos raktas (Access Key ID)", + "aws-access-key-id-required": "AWS prieigos raktas (Access Key ID) yra privalomas", + "aws-secret-access-key": "AWS slaptas prieigos raktas (Secret Access Key)", + "aws-secret-access-key-required": "AWS slaptas prieigos raktas (Secret Access Key) yra privalomas", + "aws-region": "AWS regionas", + "aws-region-required": "AWS regionas yra privalomas", + "number-from": "Telefono numeris nuo", + "number-from-required": "Telefono numeris nuo yra privalomas.", + "number-to": "Telefono numeris kam", + "number-to-required": "Telefono numeris kam yra privalomas.", + "phone-number-hint": "Telefono numeris E.164 formatu, pvz. +19995550123", + "phone-number-hint-twilio": "Telefono numeris E.164 formatu / Telefono numerio SID / Žinučių paslaugos SID, pvz. +19995550123/PNXXX/MGXXX", + "phone-number-pattern": "Neteisingas telefono numeris. Turi būti E.164 formatu, pvz. +19995550123.", + "phone-number-pattern-twilio": "Neteisingas telefono numeris. Turi būti E.164 formatu / Telefono numerio SID / Žinučių paslaugos SID, pvz. +19995550123/PNXXX/MGXXX.", + "sms-message": "SMS žinutė", + "sms-message-required": "SMS žinutė yra privaloma.", + "sms-message-max-length": "SMS žinutė negali būti ilgesnė nei 1600 simbolių", + "twilio-account-sid": "Twilio paskyros SID", + "twilio-account-sid-required": "Twilio paskyros SID yra privalomas", + "twilio-account-token": "Twilio paskyros prieigos raktas (Token)", + "twilio-account-token-required": "Twilio paskyros prieigos raktas (Token) yra privalomas", + "send-test-sms": "Siųsti bandomąją SMS", + "test-sms-sent": "Bandomoji SMS sėkmingai išsiųsta!", + "security-settings": "Saugumo nustatymai", + "password-policy": "Slaptažodžių politika", + "minimum-password-length": "Minimalus slaptažodžio ilgis", + "minimum-password-length-required": "Minimalus slaptažodžio ilgis yra privalomas", + "minimum-password-length-range": "Minimalus slaptažodžio ilgis turi būti nuo 5 iki 50 simbolių", + "maximum-password-length": "Maksimalus slaptažodžio ilgis", + "maximum-password-length-min": "Maksimalus slaptažodžio ilgis turi būti bent 6 simboliai", + "maximum-password-length-less-min": "Maksimalus slaptažodžio ilgis turi būti didesnis nei minimalus", + "minimum-uppercase-letters": "Minimalus didžiųjų raidžių kiekis", + "minimum-uppercase-letters-range": "Minimalus didžiųjų raidžių kiekis negali būti neigiamas", + "minimum-lowercase-letters": "Minimalus mažųjų raidžių kiekis", + "minimum-lowercase-letters-range": "Minimalus mažųjų raidžių kiekis negali būti neigiamas", + "minimum-digits": "Minimalus skaitmenų kiekis", + "minimum-digits-range": "Minimalus skaitmenų kiekis negali būti neigiamas", + "minimum-special-characters": "Minimalus specialiųjų simbolių kiekis", + "minimum-special-characters-range": "Minimalus specialiųjų simbolių kiekis negali būti neigiamas", + "password-expiration-period-days": "Slaptažodžio galiojimo laikotarpis dienomis", + "password-expiration-period-days-range": "Slaptažodžio galiojimo laikotarpis dienomis negali būti neigiamas", + "password-reuse-frequency-days": "Slaptažodžio pakartotinio naudojimo dažnis dienomis", + "password-reuse-frequency-days-range": "Slaptažodžio pakartotinio naudojimo dažnis dienomis negali būti neigiamas", + "allow-whitespace": "Leisti tarpus", + "force-reset-password-if-no-valid": "Priverstinai atstatyti slaptažodį, jei jis negalioja", + "force-reset-password-if-no-valid-hint": "Būkite atsargūs įjungdami šią funkciją: naudotojai, kurių slaptažodžiai netinkami, turės juos atstatyti per el. paštą.", + "general-policy": "Bendroji politika", + "max-failed-login-attempts": "Maksimalus neteisingų prisijungimų skaičius prieš paskyros užrakinimą", + "minimum-max-failed-login-attempts-range": "Maksimalus neteisingų prisijungimų skaičius negali būti neigiamas", + "user-lockout-notification-email": "Naudotojo paskyros užrakinimo atveju siųsti pranešimą el. paštu", + "user-activation-token-ttl": "Naudotojo aktyvavimo nuorodos TTL valandomis", + "user-activation-token-ttl-range": "Naudotojo aktyvavimo nuorodos TTL turi būti nuo 1 iki 24 valandų", + "password-reset-token-ttl": "Slaptažodžio atstatymo nuorodos TTL valandomis", + "password-reset-token-ttl-range": "Slaptažodžio atstatymo nuorodos TTL turi būti nuo 1 iki 24 valandų", + "mobile-secret-key-length": "Mobiliojo slaptosios rakto ilgis", + "mobile-secret-key-length-range": "Mobiliojo slaptosios rakto ilgis turi būti teigiamas", + "domain-name": "Domeno pavadinimas", + "domain-name-unique": "Domeno pavadinimas ir protokolas turi būti unikalūs.", + "domain-name-max-length": "Domeno pavadinimas turi būti trumpesnis nei 256 simboliai", + "error-verification-url": "Domeno pavadinime neturi būti simbolių '/' ir ':'. Pavyzdys: thingsboard.io", + "connection-settings": "Ryšio nustatymai", + "oauth2": { + "access-token-uri": "Prieigos rakto URI", + "access-token-uri-required": "Prieigos rakto URI yra privalomas.", + "activate-user": "Aktyvuoti naudotoją", + "add-domain": "Pridėti domeną", + "delete-domain": "Ištrinti domeną", + "add-provider": "Pridėti tiekėją", + "delete-provider": "Ištrinti tiekėją", + "allow-user-creation": "Leisti naudotojų kūrimą", + "always-fullscreen": "Visada viso ekrano režimu", + "authorization-uri": "Autorizacijos URI", + "authorization-uri-required": "Autorizacijos URI yra privalomas.", + "add-client": "Pridėti OAuth 2.0 klientą", + "client-details": "OAuth 2.0 kliento informacija", + "client": "OAuth 2.0 klientas", + "clients": "OAuth 2.0 klientai", + "no-oauth2-clients": "OAuth 2.0 klientų nerasta", + "search-oauth2-clients": "Ieškoti OAuth 2.0 klientų", + "delete-client-title": "Ar tikrai norite ištrinti OAuth 2.0 klientą '{{clientName}}'?", + "delete-client-text": "Būkite atsargūs, po patvirtinimo klientas ir visi susiję duomenys bus negrįžtamai pašalinti.", + "delete-mobile-app-title": "Ar tikrai norite ištrinti mobiliojoje programėlėje '{{applicationName}}'?", + "delete-mobile-app-text": "Būkite atsargūs, po patvirtinimo mobilioji programėlė ir visi susiję duomenys bus negrįžtamai pašalinti.", + "title": "Pavadinimas.", + "client-title-required": "Pavadinimas yra privalomas.", + "client-title-max-length": "Pavadinimas turi būti mažiau nei 100", + "advanced-settings": "Išplėstiniai nustatymai", + "domain-details": "Domeno informacija", + "no-domains": "Domenų nerasta.", + "search-domains": "Ieškoti domenų.", + "mobile-app-details": "Mobiliosios programėlės informacija", + "add-mobile-app": "Pridėti mobiliąją programėlę", + "no-mobile-apps": "No applications configured", + "search-mobile-apps": "Ieškoti mobiliųjų programėlių.", + "send-token": "Siųsti prieigos raktą.", + "create-new": "Sukurti naują", + "client-authentication-method": "Kliento autentifikavimo metodas", + "client-id": "Kliento ID", + "client-id-required": "Kliento ID yra privalomas.", + "client-id-max-length": "Kliento ID turi būti trumpesnis nei 256 simboliai", + "client-secret": "Kliento slaptas raktas", + "client-secret-required": "Kliento slaptas raktas yra privalomas.", + "client-secret-max-length": "Kliento slaptis turi būti trumpesnė nei 2049 simboliai", + "custom-setting": "Pasirinktiniai nustatymai.", + "customer-name-pattern": "Kliento vardo šablonas.", + "customer-name-pattern-max-length": "Kliento vardo šablonas turi būti trumpesnis nei 256 simboliai.", + "default-dashboard-name": "Numatytas prietaisų skydelio pavadinimas", + "default-dashboard-name-max-length": "Numatytojo prietaisų skydelio pavadinimas turi būti trumpesnis nei 256 simboliai", + "delete-domain-text": "Būkite atsargūs — po patvirtinimo domenas ir visi tiekėjo duomenys taps nepasiekiami.", + "delete-domain-title": "Ar tikrai norite ištrinti domeną „{{domainName}}“?", + "delete-registration-text": "Būkite atsargūs, po patvirtinimo tiekėjo duomenys taps nepasiekiami.", + "delete-registration-title": "Ar tikrai norite ištrinti tiekėją „{{name}}“?", + "email-attribute-key": "Email attribute key", + "email-attribute-key-required": "Email attribute key is required.", + "email-attribute-key-max-length": "Email attribute key should be less than 32", + "first-name-attribute-key": "First name attribute key", + "first-name-attribute-key-max-length": "First name attribute key should be less than 32", + "general": "General", + "jwk-set-uri": "JSON Web Key URI", + "last-name-attribute-key": "Last name attribute key", + "last-name-attribute-key-max-length": "Last name attribute key should be less than 32", + "login-button-icon": "Login button icon", + "login-button-label": "Provider label", + "login-button-label-placeholder": "Login with $(Provider label)", + "login-button-label-required": "Label is required.", + "login-provider": "Login provider", + "mapper": "Mapper", + "new-domain": "New domain", + "oauth2": "OAuth2", + "password-max-length": "Password should be less than 256", + "redirect-uri-template": "Redirect URI template", + "copy-redirect-uri": "Nukopijuoti nukreipimo URI.", + "registration-id": "Registration ID", + "registration-id-required": "Registration ID is required.", + "registration-id-unique": "Registration ID need to unique for the system.", + "scope": "Scope", + "scope-required": "Scope is required.", + "tenant-name-pattern": "Tenant name pattern", + "tenant-name-pattern-required": "Tenant name pattern is required.", + "tenant-name-pattern-max-length": "Tenant name pattern ishould be less than 256", + "tenant-name-strategy": "Tenant name strategy", + "type": "Mapper type", + "uri-pattern-error": "Invalid URI format.", + "url": "URL", + "url-pattern": "Invalid URL format.", + "url-required": "URL is required.", + "url-max-length": "URL should be less than 256", + "user-info-uri": "User info URI", + "user-info-uri-required": "User info URI is required.", + "username-max-length": "User name should be less than 256", + "user-name-attribute-name": "User name attribute key", + "user-name-attribute-name-required": "User name attribute key is required", + "protocol": "Protocol", + "domain-schema-http": "HTTP", + "domain-schema-https": "HTTPS", + "domain-schema-mixed": "HTTP+HTTPS", + "enable": "Enable OAuth2 settings", + "disable": "Išjungti OAuth 2.0 nustatymus", + "edge": "Propaguoti į Edge", + "edge-enable": "Įjungti propagavimą į „Edge“", + "edge-disable": "Išjungti propagavimą į „Edge“", + "domains": "Domains", + "mobile-apps": "Mobile applications", + "mobile-package": "Application package", + "mobile-package-placeholder": "Ex.: my.example.app", + "mobile-package-hint": "For Android: your own unique Application ID. For iOS: Product bundle identifier.", + "mobile-package-unique": "Application package must be unique.", + "mobile-package-required": "Programėlės paketo pavadinimas yra privalomas.", + "mobile-package-max-length": "Programėlės paketo pavadinimas turi būti trumpesnis nei 256 simboliai.", + "mobile-package-spaces": "Programėlės paketo pavadinimas negali turėti tarpų.", + "mobile-app-secret": "Application secret", + "mobile-app-secret-hint": "Base64 koduota eilutė, vaizduojanti bent 512 bitų duomenų.", + "mobile-app-secret-required": "Programėlės slaptasis raktas yra privalomas.", + "mobile-app-secret-min-length": "Programėlės slaptasis raktas turi būti bent 512 bitų duomenų.", + "mobile-app-secret-base64": "Programos paslaptis turi būti „base64“ formato.", + "invalid-mobile-app-secret": "Application secret must contain only alphanumeric characters and must be between 16 and 2048 characters long.", + "copy-mobile-app-secret": "Nukopijuoti programos slaptą raktą", + "delete-mobile-app": "Ištrinti programos informaciją", + "providers": "Providers", + "platform-web": "Web", + "platform-android": "Android", + "platform-ios": "iOS", + "all-platforms": "Visos platformos", + "smtp-provider": "SMTP provider", + "allowed-platforms": "Leistinos platforms", + "authentication": "Autentifikacija", + "basic": "Bazinis", + "provider": "Provider", + "redirect-url": "Redirect URI", + "domain-name": "Domeno pavadinimas", + "domain-name-required": "Domeno pavadinimas yra privalomas", + "redirect-url-template": "Redirect URI template", + "microsoft-tenant-id": "Directory (tenant) Id", + "microsoft-tenant-id-required": "Directory (tenant) Id is required", + "token-uri": "Token URI", + "token-uri-required": "Token URI is required", + "redirect-uri": "Redirect URI", + "google-provider": "Google", + "microsoft-provider": "Office 365", + "sendgrid-provider": "Sendgrid", + "custom-provider": "Pasirinktinis", + "generate-access-token": "Generate access token", + "update-access-token": "Update access token", + "access-token-status": "Prieigos rakto būsena:", + "token-status-generated": "generated", + "token-status-not-generated": "not generated" + }, + "smpp-provider": { + "smpp-version": "SMPP versija", + "smpp-host": "SMPP serveris", + "smpp-host-required": "SMPP serveris yra privalomas", + "smpp-port": "SMPP prievadas", + "smpp-port-required": "SMPP prievadas yra privalomas", + "system-id": "Sistemos ID", + "system-id-required": "Sistemos ID yra privalomas", + "password": "Slaptažodis", + "password-required": "Slaptažodis yra privalomas", + "type-settings": "Tipo nustatymai", + "source-settings": "Šaltinio nustatymai", + "destination-settings": "Paskirties nustatymai", + "additional-settings": "Papildomi nustatymai", + "system-type": "Sistemos tipas", + "bind-type": "Susiejimo tipas", + "service-type": "Paslaugos tipas", + "source-address": "Šaltinio adresas", + "source-ton": "Šaltinio TON", + "source-npi": "Šaltinio NPI", + "destination-ton": "Paskirties TON (Numerio tipas)", + "destination-npi": "Paskirties NPI (Numeracijos plano identifikacija)", + "address-range": "Adreso diapazonas", + "coding-scheme": "Koduotės schema", + "bind-type-tx": "Siuntėjas", + "bind-type-rx": "Gavėjas", + "bind-type-trx": "Siuntėjas/Gavėjas (Transceiver)", + "ton-unknown": "Nežinomas", + "ton-international": "Tarptautinis", + "ton-national": "Nacionalinis", + "ton-network-specific": "Tinklo specifinis", + "ton-subscriber-number": "Abonento numeris", + "ton-alphanumeric": "Raidinis-skaitmeninis", + "ton-abbreviated": "Sutrumpintas", + "npi-unknown": "0 - Nežinomas", + "npi-isdn": "1 - ISDN/telefono numeracijos planas (E163/E164)", + "npi-data-numbering-plan": "3 - Duomenų numeracijos planas (X.121)", + "npi-telex-numbering-plan": "4 - Telex numeracijos planas (F.69)", + "npi-land-mobile": "6 - Mobilusis (E.212)", + "npi-national-numbering-plan": "8 - Nacionalinis numeracijos planas", + "npi-private-numbering-plan": "9 - Privatus numeracijos planas", + "npi-ermes-numbering-plan": "10 - ERMES numeracijos planas (ETSI DE/PS 3 01-3)", + "npi-internet": "13 - Internetas (IP)", + "npi-wap-client-id": "18 - WAP kliento ID (nustatomas WAP forumo)", + "scheme-smsc": "0 - SMSC numatytoji abėcėlė (ASCII trumpiems ir ilgiems kodams bei GSM be mokesčio numeriams)", + "scheme-ia5": "1 - IA5 (ASCII trumpiems ir ilgiems kodams, Latin 9 be mokesčio numeriams (ISO-8859-9))", + "scheme-octet-unspecified-2": "2 - Neapibrėžtas aštuonetas (8 bitų dvejetainis)", + "scheme-latin-1": "3 - Lotynų 1 (ISO-8859-1)", + "scheme-octet-unspecified-4": "4 - Neapibrėžtas aštuonetas (8 bitų dvejetainis)", + "scheme-jis": "5 - JIS (X 0208-1990)", + "scheme-cyrillic": "6 - Kirilica (ISO-8859-5)", + "scheme-latin-hebrew": "7 - Lotynų/Hebrajų (ISO-8859-8)", + "scheme-ucs-utf": "8 - UCS2/UTF-16 (ISO/IEC-10646)", + "scheme-pictogram-encoding": "9 - Piktogramų koduotė", + "scheme-music-codes": "10 - Muzikos kodai (ISO-2022-JP)", + "scheme-extended-kanji-jis": "13 - Išplėstinė Kanji JIS (X 0212-1990)", + "scheme-korean-graphic-character-set": "14 - Korėjiečių grafinis simbolių rinkinys (KS C 5601/KS X 1001)" + }, + "queue-select-name": "Pasirinkite eilės pavadinimą", + "queue-name": "Pavadinimas", + "queue-name-required": "Eilės pavadinimas yra privalomas!", + "queues": "Eilės", + "queue-partitions": "Skirsniai", + "queue-submit-strategy": "Pateikimo strategija", + "queue-processing-strategy": "Apdorojimo strategija", + "queue-configuration": "Eilės konfigūracija", + "repository-settings": "Repozitorijos nustatymai", + "repository": "Repozitorija", + "repository-url": "Repozitorijos URL", + "repository-url-required": "Repozitorijos URL yra privalomas.", + "default-branch": "Numatytasis šakos pavadinimas", + "repository-read-only": "Tik skaitymui", + "show-merge-commits": "Rodyti sujungimo (merge) įrašus", + "authentication-settings": "Autentifikavimo nustatymai", + "auth-method": "Autentifikavimo metodas", + "auth-method-username-password": "Slaptažodis / prieigos raktas", + "auth-method-username-password-hint": "GitHub naudotojai privalo naudoti prieigos raktus su rašymo teisėmis į repozitoriją.", + "auth-method-private-key": "Privatus raktas", + "password-access-token": "Slaptažodis / prieigos raktas", + "change-password-access-token": "Pakeisti slaptažodį / prieigos raktą", + "private-key": "Privatus raktas", + "drop-private-key-file-or": "Vilkite ir numeskite privataus rakto failą arba", + "passphrase": "Slaptažodžio frazė", + "enter-passphrase": "Įveskite slaptažodžio frazę", + "change-passphrase": "Pakeisti slaptažodžio frazę", + "check-access": "Patikrinti prieigą", + "check-repository-access-success": "Repozitorijos prieiga sėkmingai patvirtinta!", + "delete-repository-settings-title": "Ar tikrai norite ištrinti repozitorijos nustatymus?", + "delete-repository-settings-text": "Būkite atsargūs, po patvirtinimo repozitorijos nustatymai bus pašalinti ir versijų valdymo funkcija taps nepasiekiama.", + "auto-commit-settings": "Automatinio įrašo nustatymai", + "auto-commit": "Automatinis įrašas (commit)", + "auto-commit-entities": "Automatinio įrašo objektai", + "no-auto-commit-entities-prompt": "Nėra sukonfigūruotų objektų automatiniam įrašui", + "delete-auto-commit-settings-title": "Ar tikrai norite ištrinti automatinio įrašo nustatymus?", + "delete-auto-commit-settings-text": "Būkite atsargūs, po patvirtinimo automatinio įrašo nustatymai bus pašalinti ir funkcija bus išjungta visiems objektams.", + "mobile-app": { + "mobile-app": "Mobilioji programėlė", + "mobile-app-qr-code-widget-settings": "Mobiliosios programėlės QR kodo valdiklio nustatymai", + "applications": "Programėlės", + "default": "Numatytasis", + "custom": "Pasirinktinis", + "android": "Android", + "ios": "iOS", + "appearance": "Išvaizda", + "appearance-on-home-page": "Išvaizda pagrindiniame puslapyje", + "enabled": "Įjungta", + "disabled": "Išjungta", + "badges": "Ženkleliai", + "label": "Etiketė", + "label-required": "Etiketė yra privaloma", + "label-max-length": "Etiketė turi būti ne ilgesnė kaip 50 simbolių", + "right": "Dešinėje", + "left": "Kairėje", + "set": "Nustatyti", + "preview": "Peržiūra", + "connect-mobile-app": "Prijungti mobiliąją programėlę", + "use-system-settings": "Naudoti sistemos nustatymus" + }, + "2fa": { + "2fa": "Dvigubas autentifikavimas", + "available-providers": "Galimi tiekėjai", + "issuer-name": "Leidėjo pavadinimas", + "issuer-name-required": "Leidėjo pavadinimas yra privalomas.", + "max-verification-failures-before-user-lockout": "Maksimalus neteisingų patvirtinimų skaičius prieš naudotojo užrakinimą", + "max-verification-failures-before-user-lockout-pattern": "Maksimalus patvirtinimų skaičius turi būti teigiamas sveikasis skaičius.", + "number-of-checking-attempts": "Tikrinimo bandymų skaičius", + "number-of-checking-attempts-pattern": "Tikrinimo bandymų skaičius turi būti teigiamas sveikasis skaičius.", + "number-of-checking-attempts-required": "Tikrinimo bandymų skaičius yra privalomas.", + "number-of-codes": "Kodų skaičius", + "number-of-codes-pattern": "Kodų skaičius turi būti teigiamas sveikasis skaičius.", + "number-of-codes-required": "Kodų skaičius yra privalomas.", + "provider": "Tiekėjas", + "retry-verification-code-period": "Pakartotinio patvirtinimo kodo laikotarpis (sek)", + "retry-verification-code-period-pattern": "Minimalus laikotarpis yra 5 sek.", + "retry-verification-code-period-required": "Pakartotinio patvirtinimo kodo laikotarpis yra privalomas.", + "total-allowed-time-for-verification": "Bendras leidžiamas patvirtinimo laikas (sek)", + "total-allowed-time-for-verification-pattern": "Minimalus bendras leidžiamas laikas yra 60 sek.", + "total-allowed-time-for-verification-required": "Bendras leidžiamas laikas yra privalomas.", + "use-system-two-factor-auth-settings": "Naudoti sistemos dviejų veiksnių autentifikavimo nustatymus", + "verification-code-check-rate-limit": "Patvirtinimo kodo tikrinimo dažnio limitas", + "verification-code-lifetime": "Patvirtinimo kodo galiojimo laikas (sek)", + "verification-code-lifetime-pattern": "Patvirtinimo kodo galiojimo laikas turi būti teigiamas sveikasis skaičius.", + "verification-code-lifetime-required": "Patvirtinimo kodo galiojimo laikas yra privalomas.", + "verification-message-template": "Patvirtinimo pranešimo šablonas", + "verification-limitations": "Patvirtinimo apribojimai", + "verification-message-template-pattern": "Patvirtinimo pranešime turi būti šablonas: ${code}", + "verification-message-template-required": "Patvirtinimo pranešimo šablonas yra privalomas.", + "within-time": "Per laiką (sek)", + "within-time-pattern": "Laikas turi būti teigiamas sveikasis skaičius.", + "within-time-required": "Laikas yra privalomas." + }, + "jwt": { + "security-settings": "JWT saugumo nustatymai", + "issuer-name": "Leidėjo pavadinimas", + "issuer-name-required": "Leidėjo pavadinimas yra privalomas.", + "signings-key": "Pasirašymo raktas", + "signings-key-hint": "Base64 koduota eilutė, atitinkanti bent 256 bitų duomenis.", + "signings-key-required": "Pasirašymo raktas yra privalomas.", + "signings-key-min-length": "Pasirašymo raktas turi būti bent 256 bitų duomenų ilgio.", + "signings-key-base64": "Pasirašymo raktas turi būti Base64 formatu.", + "expiration-time": "Žetono galiojimo laikas (sek)", + "expiration-time-required": "Žetono galiojimo laikas yra privalomas.", + "expiration-time-max": "Didžiausias leidžiamas laikas – 2147483647 sekundės (68 metai).", + "expiration-time-min": "Mažiausias laikas – 60 sekundžių (1 minutė).", + "refresh-expiration-time": "Atnaujinimo žetono galiojimo laikas (sek)", + "refresh-expiration-time-required": "Atnaujinimo žetono galiojimo laikas yra privalomas.", + "refresh-expiration-time-max": "Didžiausias leidžiamas laikas – 2147483647 sekundės (68 metai).", + "refresh-expiration-time-min": "Mažiausias laikas – 900 sekundžių (15 minučių).", + "refresh-expiration-time-less-token": "Atnaujinimo žetono laikas turi būti ilgesnis už pagrindinio žetono laiką.", + "generate-key": "Generuoti raktą", + "info-header": "Visi naudotojai turės prisijungti iš naujo", + "info-message": "JWT pasirašymo rakto pakeitimas panaikins visų išduotų žetonų galiojimą. Visi naudotojai turės prisijungti iš naujo. Tai taip pat paveiks scenarijus, naudojančius Rest API / Websockets." + }, + "resources": "Ištekliai", + "notifications": "Pranešimai", + "notifications-settings": "Pranešimų nustatymai", + "slack-api-token": "Slack API prieigos raktas", + "slack": "Slack", + "slack-settings": "Slack nustatymai", + "mobile-settings": "Mobiliosios programos nustatymai", + "firebase-service-account-file": "Firebase paslaugos paskyros kredencialų JSON failas", + "select-firebase-service-account-file": "Vilkite ir numeskite savo Firebase paslaugos paskyros kredencialų failą arba ", + "trendz": "PredAna", + "trendz-settings": "PredAna nustatymai", + "trendz-url": "PredAna URL", + "trendz-url-required": "PredAna URL yra privalomas", + "trendz-api-key": "PredAna API raktas", + "trendz-enable": "Įjungti PredAna" + }, + "alarm": { + "alarm": "Įspėjimas", + "alarms": "Įspėjimai", + "all-alarms": "Visi įspėjimai", + "select-alarm": "Pasirinkite įspėjimą", + "no-alarms-matching": "Su '{{entity}}' susijusių įspėjimų nerasta.", + "alarm-required": "Įspėjimas yra privalomas", + "alarm-filter": "Įspėjimų filtras", + "filter": "Filtras", + "alarm-status": "Įspėjimo būsena", + "alarm-status-list": "Įspėjimo būsenų sąrašas", + "any-status": "Visos būsenos", + "search-status": { + "ANY": "Visi", + "ACTIVE": "Aktyvūs", + "CLEARED": "Išvalyti", + "ACK": "Patvirtinti", + "UNACK": "Nepatvirtinti" + }, + "display-status": { + "ACTIVE_UNACK": "Aktyvūs nepatvirtinti", + "ACTIVE_ACK": "Aktyvūs pripažinti", + "CLEARED_UNACK": "Atmesti nepatvirtinti", + "CLEARED_ACK": "Atmesti pripažinti" + }, + "no-alarms-prompt": "Įspėjimų nėra", + "created-time": "Sukūrimo laikas", + "type": "Tipas", + "severity": "Lygis", + "originator": "Iniciatorius", + "originator-type": "Iniciatoriaus tipas", + "details": "Pastabos", + "originator-label": "Iniciatoriaus pavadinimas", + "assign": "Priskirti", + "assignments": "Priskyrimai", + "assignee": "Atsakingas", + "assignee-id": "Atsakingo asmens ID", + "assignee-first-name": "Atsakingo asmens vardas", + "assignee-last-name": "Atsakingo asmens pavardė", + "assignee-email": "Atsakingo asmens e-paštas", + "unassigned": "Panaikinti priskyrimą", + "user-deleted": "Vartotojas ištrintas", + "assignee-not-set": "Visi", + "status": "Statusas", + "alarm-details": "Įspėjimo pastabos", + "start-time": "Pradžia", + "assign-time": "Priskyrimo laikas", + "end-time": "Pabaiga", + "ack-time": "Pripažinimo laikas", + "clear-time": "Atmetimo laikas", + "duration": "Trukmė", + "alarm-severity": "Alarm severity", + "alarm-severity-list": "Įspėjimų lygiai", + "any-severity": "Visi lygiai", + "severity-critical": "Kritinis", + "severity-major": "Svarbus", + "severity-minor": "Antraeilis", + "severity-warning": "Įspėjimas", + "severity-indeterminate": "Nenustatytas", + "acknowledge": "Patvirtinti", + "clear": "Atmesti", + "delete": "Panaikinti", + "search": "Įspėjimo paieška", + "selected-alarms": "Pasirinkta { count, plural, =1 {1 įspėjimas} other {# įspėjimai} }", + "no-data": "Nėra duomenų", + "polling-interval": "Įspėjimų tikrinimo intervalas (sek)", + "polling-interval-required": "Reikalingas įspėjimų tikrinimo intervalas", + "min-polling-interval-message": "Mažiausias įspėjimų tikrinimo intervalas yra 1 sekundė.", + "aknowledge-alarms-title": "Pripažinti { count, plural, =1 {1 įspėjimą} other {# įspėjimus} }", + "aknowledge-alarms-text": "Pripažinti { count, plural, =1 {1 įspėjimą} other {# įspėjimus} }?", + "aknowledge-alarm-title": "Pripažinti įspėjimą", + "aknowledge-alarm-text": "Pripažinti įspėjimą?", + "selected-alarms-are-acknowledged": "Pasirinkti įspėjimai pripažinti", + "clear-alarms-title": "Atmesti { count, plural, =1 {1 įspėjimą} other {# įspėjimus} }", + "clear-alarms-text": "Atmesti { count, plural, =1 {1 įspėjimą} other {# įspėjimus} }?", + "clear-alarm-title": "Atmesti įspėjimą", + "clear-alarm-text": "Atmesti įspėjimą?", + "delete-alarms-title": "Panaikinti { count, plural, =1 {1 įspėjimą} other {# įspėjimus} }", + "delete-alarms-text": "Panaikinti { count, plural, =1 {1 įspėjimą} other {# įspėjimus} }?", + "selected-alarms-are-cleared": "Pasirinkti įspėjimai atmesti", + "alarm-status-filter": "Įspėjimų statusai", + "alarm-filter-title": "Įspėjimų filtras", + "assigned": "Priskirta", + "filter-title": "Filtras", + "max-count-load": "Didžiausias rodomų įspėjimų skaičius (0 – neribotas)", + "max-count-load-required": "Reikalingas didžiausias rodomų įspėjimų skaičius (0 – neribotas).", + "max-count-load-error-min": "Mažiausia reikšmė yra 0.", + "fetch-size": "Fetch size", + "fetch-size-required": "Fetch size is required.", + "fetch-size-error-min": "Mažiausia rekšmė yra 10.", + "alarm-types": "Įspėjimų tipai", + "alarm-type-list": "Įspėjimų tipų sąrašas", + "any-type": "Visi tipai", + "assigned-to-current-user": "Priskirta prisijungusiam vartotojui", + "assigned-to-me": "Priskirta man", + "search-propagated-alarms": "Ieškoti išplatintų įspėjimų", + "comments": "Įspėjimo pastabos", + "show-more": "Rodyti daugiau", + "additional-info": "Papildoma informacija", + "alarm-type": "Įspėjimo tipas", + "enter-alarm-type": "Įveskite įspėjimo tipą", + "no-alarm-types-matching": "Nėra įspėjimų tipų, kurie atitiktų '{{entitySubtype}}'.", + "alarm-type-list-empty": "Nepasirinktas įspėjimų tipas" + }, + "alarm-activity": { + "add": "Pridėti komentarą...", + "alarm-comment": "Įspėjimo komentaras", + "comments": "Komentarai", + "delete-alarm-comment": "Ištrinti komentarą?", + "refresh": "Atnaujinti", + "oldest-first": "Seniausi viršuje", + "newest-first": "Naujausi viršuje", + "activity": "Veikla", + "export": "Eksportuoti į CSV", + "author": "Sukūrė", + "created-date": "Sukūrimo dara", + "edited-date": "Redagavimo data", + "text": "Tekstas", + "system": "Sistema" + }, + "alias": { + "add": "Pridėti pseudonimą", + "edit": "Redaguoti pseudonimą", + "name": "Pseudonimas", + "name-required": "Pseudonimas yra privalomas", + "duplicate-alias": "Toks pseudonimas sistemoje jau egzistuoja.", + "filter-type-single-entity": "Vienas subjektas", + "filter-type-entity-list": "Subjektų sąrašas", + "filter-type-entity-name": "Subjekto pavadinimas", + "filter-type-entity-type": "Subjekto tipas", + "filter-type-state-entity": "Subjektas iš skydelio būsenos", + "filter-type-state-entity-description": "Subjektas iš skydelio būsenos parametrų", + "filter-type-asset-type": "Turto tipas", + "filter-type-asset-type-description": "Turtas, kurio tipas '{{assetTypes}}'", + "filter-type-asset-type-and-name-description": "Turtas, kurio tipas '{{assetTypes}}' ir pavadinimas prasideda '{{prefix}}'", + "filter-type-device-type": "Įrenginio tipas", + "filter-type-device-type-description": "Įrenginiai, kurių tipas '{{deviceTypes}}'", + "filter-type-device-type-and-name-description": "Įrenginiai, kurių tipas '{{deviceTypes}}' ir kurių pavadinimas prasideda '{{prefix}}'", + "filter-type-entity-view-type": "Subjekto rodinio tipas", + "filter-type-entity-view-type-description": "Subjektų rodiniai, kurių tipas '{{entityViewTypes}}'", + "filter-type-entity-view-type-and-name-description": "Subjektų rodiniai, kurių tipas '{{entityViewTypes}}' ir kurių pavadinimas prasideda '{{prefix}}'", + "filter-type-edge-type": "Krašto (Edge) tipas", + "filter-type-edge-type-description": "Kraštai (Edges), kurių tipas '{{edgeTypes}}'", + "filter-type-edge-type-and-name-description": "Kraštai, kurių tipas '{{edgeTypes}}' ir pavadinimas prasideda '{{prefix}}'", + "filter-type-relations-query": "Ryšių užklausa", + "filter-type-relations-query-description": "{{entities}} turintys {{relationType}} ryšį {{direction}} {{rootEntity}}", + "filter-type-edge-search-query": "Kraštų (Edge) paieškos užklausa", + "filter-type-edge-search-query-description": "Kraštai, kurių tipai {{edgeTypes}}, turintys {{relationType}} ryšį {{direction}} {{rootEntity}}", + "filter-type-asset-search-query": "Turto paieškos užklausa", + "filter-type-asset-search-query-description": "{{assetTypes}} tipo turtas, turintis {{relationType}} tipo ryšį {{direction}} {{rootEntity}}", + "filter-type-device-search-query": "Įrenginio paieškos užklausa", + "filter-type-device-search-query-description": "{{deviceTypes}} tipo įrenginiai, turintys {{relationType}} tipo ryšį {{direction}} {{rootEntity}}", + "filter-type-entity-view-search-query": "Subjektų rodinio paieškos užklausa", + "filter-type-entity-view-search-query-description": "{{entityViewTypes}} tipo subjektai, turintys {{relationType}} tipo ryšį {{direction}} {{rootEntity}}", + "filter-type-apiUsageState": "API naudojimo būsena", + "entity-filter": "Subjektų filtras", + "resolve-multiple": "Apdoroti kelis subjektus vienu metu", + "resolve-multiple-hint": "Įjunkite, jei norite vienu metu atvaizduoti duomenis iš visų filtruotų subjektų.\nJei išjungta, valdiklis rodys duomenis tik iš pasirinkto subjekto.", + "filter-type": "Filtro tipas", + "filter-type-required": "Filtro tipas yra privalomas.", + "entity-filter-no-entity-matched": "Subjektų, atitinkančių filtro kriterijus, nerasta.", + "no-entity-filter-specified": "Subjektų filtras nenustatytas", + "root-state-entity": "Naudoti subjektą iš skydelio būsenos kaip pagrindinį", + "last-level-relation": "Gauti tik paskutinio lygio ryšį", + "root-entity": "Pagrindinis subjektas", + "state-entity-parameter-name": "Būsenos subjekto parametro pavadinimas", + "default-state-entity": "Numatytasis būsenos subjektas", + "default-entity-parameter-name": "Numatytasis parametro pavadinimas", + "query-options": "Užklausos parinktys", + "max-relation-level": "Maksimalus ryšių lygis", + "unlimited-level": "Neribotas lygis", + "state-entity": "Skydelio būsenos subjektas", + "all-entities": "Visi subjektai", + "any-relation": "Visi ryšiai" + }, + "asset": { + "asset": "Turtas", + "assets": "Turtas", + "management": "Turto valdymas", + "view-assets": "Peržiūrėti turtą", + "add": "Pridėti turtą", + "asset-type-max-length": "Turto tipas turi būti trumpesnis nei 256 simboliai", + "assign-to-customer": "Priskirti klientui", + "assign-asset-to-customer": "Priskirti turtą klientui", + "assign-asset-to-customer-text": "Pasirinkite turtą, kurį norite priskirti klientui", + "no-assets-text": "Turtas nerastas", + "assign-to-customer-text": "Pasirinkite klientą, kuriam priskiriamas turtas", + "public": "Viešas", + "assignedToCustomer": "Priskirtas klientui", + "make-public": "Neriboti turto matomumo", + "make-private": "Riboti turto matomumą", + "unassign-from-customer": "Atsieti nuo kliento", + "delete": "Pašalinti turtą", + "asset-public": "Turtas yra viešas", + "asset-type": "Turto tipas", + "asset-type-required": "Turto tipas yra privalomas.", + "select-asset-type": "Pasirinkite turto tipą", + "enter-asset-type": "Įveskite turto tipą", + "any-asset": "Bet koks turtas", + "no-asset-types-matching": "Turto tipas, atitinkantis '{{entitySubtype}}', nerastas.", + "asset-type-list-empty": "Nepasirinkti turto tipai.", + "asset-types": "Turto tipai", + "name": "Pavadinimas", + "name-required": "Pavadinimas yra privalomas.", + "name-max-length": "Pavadinimas turi būti trumpesnis nei 256 simboliai", + "label-max-length": "Etiketė turi būti trumpesnė nei 256 simboliai", + "description": "Aprašymas", + "type": "Tipas", + "type-required": "Tipas yra privalomas.", + "details": "Pastabos", + "events": "Įvykiai", + "add-asset-text": "Pridėti turtą", + "asset-details": "Turto informacija", + "assign-assets": "Priskirti turtą", + "assign-assets-text": "Priskirti { count, plural, =1 {1 turtą} other {# turtus} } klientui", + "assign-asset-to-edge-title": "Priskirti turtą (-us) Edge įrenginiui", + "assign-asset-to-edge-text": "Pasirinkite turtą (-us), kuriuos norite priskirti Edge įrenginiui", + "delete-assets": "Pašalinti turtą", + "unassign-assets": "Atsieti turtą", + "unassign-assets-action-title": "Atsieti { count, plural, =1 {1 turtą} other {# turtus} } nuo kliento?", + "assign-new-asset": "Priskirti naują turtą", + "delete-asset-title": "Pašalinti turtą '{{assetName}}'?", + "delete-asset-text": "Būkite atsargūs, po patvirtinimo turtas ir visa su juo susijusi informacija bus pašalinta.", + "delete-assets-title": "Pašalinti { count, plural, =1 {1 turtą} other {# turtus} }?", + "delete-assets-action-title": "Pašalinti { count, plural, =1 {1 turtą} other {# turtus} }", + "delete-assets-text": "Būkite atsargūs, po patvirtinimo visas turtas ir su juo susijusi informacija bus pašalinta.", + "make-public-asset-title": "Ar tikrai norite neriboti turto '{{assetName}}' matomumo?", + "make-public-asset-text": "Po patvirtinimo turtas ir visa su juo susijusi informacija bus prieinama visiems.", + "make-private-asset-title": "Ar tikrai norite apriboti turto '{{assetName}}' matomumą?", + "make-private-asset-text": "Po patvirtinimo turtas ir visa su juo susijusi informacija nebebus prieinama kitiems.", + "unassign-asset-title": "Ar tikrai norite atsieti turtą '{{assetName}}'?", + "unassign-asset-text": "Po patvirtinimo turtas bus atsietas, o klientas neteks prieigos prie jo.", + "unassign-asset": "Atsieti turtą", + "unassign-assets-title": "Ar tikrai norite atsieti { count, plural, =1 {1 turtą} other {# turtus} }?", + "unassign-assets-text": "Po patvirtinimo visas pasirinktas turtas bus atsietas, o klientas neteks prieigos prie jo.", + "copyId": "Kopijuoti turto ID", + "idCopiedMessage": "Turto ID nukopijuotas į iškarpinę", + "select-asset": "Pasirinkite turtą", + "no-assets-matching": "Turtas, atitinkantis '{{entity}}', nerastas.", + "asset-required": "Turtas yra privalomas", + "name-starts-with": "Turto pavadinimas prasideda nuo", + "help-text": "Naudokite simbolį '%' pagal paieškos poreikį: '%turto_fragmentas%', '%turto_pabaiga', 'turto_pradžia%'.", + "search": "Turto paieška", + "import": "Importuoti turtą", + "asset-file": "Turto failas", + "label": "Etiketė", + "assign-asset-to-edge": "Priskirti turtą (-us) Edge įrenginiui", + "unassign-asset-from-edge": "Atsieti turtą nuo Edge", + "unassign-asset-from-edge-title": "Ar tikrai norite atsieti turtą '{{assetName}}' nuo Edge?", + "unassign-asset-from-edge-text": "Po patvirtinimo turtas bus atsietas ir nebebus pasiekiamas Edge įrenginyje.", + "unassign-assets-from-edge-title": "Ar tikrai norite atsieti { count, plural, =1 {1 turtą} other {# turtus} } nuo Edge?", + "unassign-assets-from-edge-text": "Po patvirtinimo visi pasirinkti turtai bus atsieti ir nebebus prieinami Edge įrenginiuose.", + "selected-assets": "Pasirinkta { count, plural, =1 {1 turtas} other {# turtai} }" + }, + "attribute": { + "attributes": "Atributai", + "latest-telemetry": "Naujausia telemetrija", + "no-latest-telemetry": "Telemetrijos duomenų nėra", + "attributes-scope": "Subjekto atributų sritis", + "scope-telemetry": "Telemetrija", + "scope-latest-telemetry": "Naujausia telemetrija", + "scope-client": "Kliento atributai", + "scope-server": "Serverio atributai", + "scope-shared": "Bendrinami atributai", + "scope-client-short": "Client", + "scope-server-short": "Server", + "scope-shared-short": "Shared", + "scope-latest-short": "Latest", + "scope-any": "Bet kurie", + "add": "Pridėti atributą", + "key": "Raktas", + "key-max-length": "Raktas negali viršyti 256 simbolių", + "last-update-time": "Paskutinio atnaujinimo laikas", + "key-required": "Atributo raktas yra privalomas.", + "value": "Reikšmė", + "value-required": "Atributo reikšmė yra privaloma.", + "telemetry-key-required": "Telemetrijos raktas yra privalomas.", + "telemetry-value-required": "Telemetrijos reikšmė yra privaloma.", + "delete-attributes-title": "Ar tikrai norite pašalinti { count, plural, =1 {1 atributą} other {# atributus} }?", + "delete-attributes-text": "Būkite atsargūs — po patvirtinimo pasirinkti atributai bus pašalinti.", + "delete-attributes": "Pašalinti atributus", + "enter-attribute-value": "Įveskite atributo reikšmę", + "show-on-widget": "Rodyti valdiklyje", + "widget-mode": "Valdiklio režimas", + "next-widget": "Kitas valdiklis", + "prev-widget": "Ankstesnis valdiklis", + "add-to-dashboard": "Pridėti į skydelį", + "add-widget-to-dashboard": "Pridėti valdiklį į skydelį", + "selected-attributes": "Pasirinkta { count, plural, =1 {1 atributas} other {# atributai} }", + "selected-telemetry": "Pasirinkta { count, plural, =1 {1 telemetrijos įrašas} other {# telemetrijos įrašai} }", + "no-attributes-text": "Atributų nėra", + "no-telemetry-text": "Telemetrijos duomenų nėra", + "copy-key": "Kopijuoti raktą", + "add-telemetry": "Pridėti telemetriją", + "copy-value": "Kopijuoti reikšmę", + "delete-timeseries": { + "start-time": "Pradžios laikas", + "ends-on": "Pabaigos laikas", + "strategy": "Strategija", + "delete-strategy": "Šalinimo strategija", + "all-data": "Pašalinti visus duomenis", + "all-data-except-latest-value": "Pašalinti visus duomenis, išskyrus naujausią reikšmę", + "latest-value": "Pašalinti naujausią reikšmę", + "all-data-for-time-period": "Pašalinti visus duomenis laikotarpiui", + "rewrite-latest-value": "Perrašyti naujausią reikšmę" + } + }, + "api-usage": { + "api-features": "API funkcijos", + "api-usage": "API naudojimas", + "alarm": "Įspėjimas", + "alarms-created": "Sukurti įspėjimai", + "queue-stats": "Eilės statistika", + "processing-failures-and-timeouts": "Apdorojimo klaidos ir laiko limitai", + "exceptions": "Išimtys", + "alarms-created-daily-activity": "Įspėjimų dienos veikla", + "alarms-created-hourly-activity": "Įspėjimų valandinė veikla", + "alarms-created-monthly-activity": "Įspėjimų mėnesinė veikla", + "data-points": "Duomenų taškai", + "data-points-storage-days": "Duomenų taškų saugojimo dienos", + "device-api": "Įrenginio API", + "email": "El. paštas", + "email-messages": "El. laiškai", + "email-messages-daily-activity": "El. laiškų dienos veikla", + "email-messages-monthly-activity": "El. laiškų mėnesinė veikla", + "executions": "Vykdymai", + "scripts": "Skriptai", + "scripts-hourly-activity": "Skriptų valandinė veikla", + "scripts-daily-activity": "Skriptų dienos veikla", + "scripts-monthly-activity": "Skriptų mėnesinė veikla", + "javascript": "JavaScript", + "javascript-executions": "JavaScript vykdymai", + "tbel": "TBEL", + "tbel-executions": "TBEL vykdymai", + "latest-error": "Naujausia klaida", + "messages": "Pranešimai", + "notifications": "Pranešimai", + "notifications-email-sms": "Pranešimai (El. paštas / SMS)", + "notifications-hourly-activity": "Pranešimų valandinė veikla", + "permanent-failures": "${entityName} nuolatinės klaidos", + "permanent-timeouts": "${entityName} nuolatiniai laiko limitai", + "processing-failures": "${entityName} apdorojimo klaidos", + "processing-timeouts": "${entityName} apdorojimo laiko limitai", + "rule-chain": "Taisyklių grandinė (Rule Chain)", + "rule-engine": "Taisyklių variklis (Rule Engine)", + "rule-engine-daily-activity": "Taisyklių variklio dienos veikla", + "rule-engine-executions": "Taisyklių variklio vykdymai", + "rule-engine-hourly-activity": "Taisyklių variklio valandinė veikla", + "rule-engine-monthly-activity": "Taisyklių variklio mėnesinė veikla", + "rule-engine-statistics": "Taisyklių variklio statistika", + "rule-node": "Taisyklių mazgas (Rule Node)", + "sms": "SMS", + "sms-messages": "SMS žinutės", + "sms-messages-daily-activity": "SMS žinučių dienos veikla", + "sms-messages-monthly-activity": "SMS žinučių mėnesinė veikla", + "successful": "${entityName} sėkmingi vykdymai", + "telemetry": "Telemetrija", + "telemetry-persistence": "Telemetrijos įrašymas", + "telemetry-persistence-daily-activity": "Telemetrijos įrašymo dienos veikla", + "telemetry-persistence-hourly-activity": "Telemetrijos įrašymo valandinė veikla", + "telemetry-persistence-monthly-activity": "Telemetrijos įrašymo mėnesinė veikla", + "transport": "Transportas", + "transport-daily-activity": "Transporto dienos veikla", + "transport-data-points": "Transporto duomenų taškai", + "transport-hourly-activity": "Transporto valandinė veikla", + "transport-messages": "Transporto pranešimai", + "transport-monthly-activity": "Transporto mėnesinė veikla", + "view-details": "Peržiūrėti detales", + "view-statistics": "Peržiūrėti statistiką" + }, + "api-limit": { + "cassandra-write-queries-core": "REST API Cassandra rašymo užklausos", + "cassandra-read-queries-core": "REST API ir WS telemetrijos Cassandra skaitymo užklausos", + "cassandra-write-queries-rule-engine": "Taisyklių variklio (Rule Engine) telemetrijos Cassandra rašymo užklausos", + "cassandra-read-queries-rule-engine": "Taisyklių variklio (Rule Engine) telemetrijos Cassandra skaitymo užklausos", + "cassandra-write-queries-monolith": "Monolitinės telemetrijos Cassandra rašymo užklausos", + "cassandra-read-queries-monolith": "Monolitinės telemetrijos Cassandra skaitymo užklausos", + "entity-version-creation": "Subjekto versijos kūrimas", + "entity-version-load": "Subjekto versijos įkėlimas", + "notification-requests": "Pranešimų užklausos", + "notification-requests-per-rule": "Pranešimų užklausos pagal taisyklę", + "rest-api-requests": "REST API užklausos", + "rest-api-requests-per-customer": "REST API užklausos pagal klientą", + "transport-messages": "Transporto pranešimai", + "transport-messages-per-device": "Transporto pranešimai pagal įrenginį", + "transport-messages-per-gateway": "Transporto pranešimai pagal šliuzą (gateway)", + "transport-messages-per-gateway-device": "Transporto pranešimai pagal šliuzo įrenginį", + "ws-updates-per-session": "WS atnaujinimai per sesiją", + "edge-events": "Edge įvykiai", + "edge-events-per-edge": "Edge įvykiai pagal Edge", + "edge-uplink-messages": "Edge uplink pranešimai", + "edge-uplink-messages-per-edge": "Edge uplink pranešimai pagal Edge" + }, + "audit-log": { + "audit": "Auditas", + "audit-logs": "Audito žurnalas", + "timestamp": "Laiko žyma", + "entity-type": "Subjektas", + "entity-name": "Pavadinimas", + "user": "Vartotojas", + "type": "Veiksmas", + "status": "Statusas", + "details": "Informacija", + "type-added": "Pridėta", + "type-deleted": "Pašalinta", + "type-updated": "Atnaujinta", + "type-attributes-updated": "Atributai atnaujinti", + "type-attributes-deleted": "Atributai pašalinti", + "type-rpc-call": "RPC iškvietimas", + "type-credentials-updated": "Įgaliojimai atnaujinti", + "type-assigned-to-customer": "Priskirta klientui", + "type-unassigned-from-customer": "Atsieta nuo kliento", + "type-assigned-to-edge": "Priskirta Edge įrenginiui", + "type-unassigned-from-edge": "Atsieta nuo Edge įrenginio", + "type-activated": "Aktyvuota", + "type-suspended": "Sustabdyta", + "type-credentials-read": "Įgaliojimų skaitymas", + "type-attributes-read": "Atributų skaitymas", + "type-relation-add-or-update": "Ryšys pridėtas arba atnaujintas", + "type-relation-delete": "Ryšys panaikintas", + "type-relations-delete": "Visi ryšiai panaikinti", + "type-alarm-ack": "Įspėjimas patvirtintas", + "type-alarm-clear": "Įspėjimas išvalytas", + "type-alarm-delete": "Įspėjimas pašalintas", + "type-alarm-assign": "Įspėjimas priskirtas", + "type-alarm-unassign": "Įspėjimas atsietas", + "type-added-comment": "Pridėtas komentaras", + "type-updated-comment": "Atnaujintas komentaras", + "type-deleted-comment": "Pašalintas komentaras", + "type-login": "Prisijungimas", + "type-logout": "Atsijungimas", + "type-lockout": "Užblokuotas", + "status-success": "Sėkminga", + "status-failure": "Nesėkminga", + "audit-log-details": "Audito žurnalo informacija", + "no-audit-logs-prompt": "Audito žurnalo įrašų nėra", + "action-data": "Veiksmų informacija", + "failure-details": "Nesėkmės informacija", + "search": "Žurnalo įrašų paieška", + "clear-search": "Išvalyti paiešką", + "type-assigned-from-tenant": "Priskirta iš nuomotojo", + "type-assigned-to-tenant": "Priskirta nuomotojui", + "type-provision-success": "Įrenginys sėkmingai įtrauktas (provisioned)", + "type-provision-failure": "Įrenginio įtraukimas nepavyko", + "type-timeseries-updated": "Telemetrija atnaujinta", + "type-timeseries-deleted": "Telemetrija pašalinta", + "type-sms-sent": "SMS išsiųsta" + }, + "debug-settings": { + "label": "Derinimo konfigūracija", + "on-failure": "Tik klaidos (24/7)", + "all-messages": "Visos žinutės ({{time}})", + "failures": "Klaidos", + "entity": "objektas", + "hint": { + "main-limited": "Per {{time}} bus įrašyta ne daugiau kaip {{msg}} derinimo žinučių iš {{entity}}.", + "on-failure": "Registruoti tik klaidų žinutes.", + "all-messages": "Registruoti visas derinimo žinutes." + } + }, + "calculated-fields": { + "expression": "Išraiška", + "no-found": "Apskaičiuotų laukų nerasta", + "list": "{ count, plural, =1 {Vienas apskaičiuotas laukas} other {# apskaičiuotų laukų sąrašas} }", + "selected-fields": "{ count, plural, =1 {1 apskaičiuotas laukas} other {# apskaičiuoti laukai} } pasirinkta", + "type": { + "simple": "Paprastas", + "script": "Skriptas" + }, + "arguments": "Argumentai", + "decimals-by-default": "Numatytasis dešimtainių skaičius", + "debugging": "Apskaičiuoto lauko derinimas", + "argument-name": "Argumento pavadinimas", + "datasource": "Duomenų šaltinis", + "add-argument": "Pridėti argumentą", + "test-script-function": "Išbandyti skripto funkciją", + "no-arguments": "Argumentai nesukonfigūruoti", + "argument-settings": "Argumento nustatymai", + "argument-current": "Dabartinis subjektas", + "argument-current-tenant": "Dabartinis valdytojas", + "argument-device": "Įrenginys", + "argument-asset": "Turtas", + "argument-customer": "Klientas", + "argument-tenant": "Dabartinis valdytojas", + "argument-type": "Argumento tipas", + "see-debug-events": "Peržiūrėti derinimo įvykius", + "attribute": "Atributas", + "copy-argument-name": "Kopijuoti argumento pavadinimą", + "timeseries-key": "Laiko sekos raktas", + "device-name": "Įrenginio pavadinimas", + "latest-telemetry": "Naujausia telemetrija", + "rolling": "Laiko sekos kaupimas", + "attribute-scope": "Atributo sritis", + "server-attributes": "Serverio atributai", + "client-attributes": "Kliento atributai", + "shared-attributes": "Bendrinami atributai", + "attribute-key": "Atributo raktas", + "default-value": "Numatytoji reikšmė", + "limit": "Maksimalių reikšmių skaičius", + "time-window": "Laiko intervalas", + "customer-name": "Kliento pavadinimas", + "asset-name": "Turto pavadinimas", + "timeseries": "Laiko seka", + "output": "Rezultatas", + "create": "Sukurti naują apskaičiuotą lauką", + "file": "Apskaičiuoto lauko failas", + "invalid-file-error": "Netinkamas failo formatas. Įsitikinkite, kad failas yra tinkamas JSON formatas.", + "import": "Importuoti apskaičiuotą lauką", + "export": "Eksportuoti apskaičiuotą lauką", + "export-failed-error": "Nepavyko eksportuoti apskaičiuoto lauko: {{error}}", + "output-type": "Rezultato tipas", + "delete-title": "Ar tikrai norite pašalinti apskaičiuotą lauką '{{title}}'?", + "delete-text": "Būkite atsargūs — po patvirtinimo apskaičiuotas laukas ir visa susijusi informacija bus negrįžtamai pašalinta.", + "delete-multiple-title": "Ar tikrai norite pašalinti { count, plural, =1 {1 apskaičiuotą lauką} other {# apskaičiuotus laukus} }?", + "delete-multiple-text": "Būkite atsargūs — po patvirtinimo visi pasirinkti apskaičiuoti laukai bus pašalinti kartu su visa susijusia informacija.", + "test-with-this-message": "Išbandyti su šia žinute", + "use-latest-timestamp": "Naudoti naujausią laiko žymą", + "hint": { + "arguments-simple-with-rolling": "Paprasto tipo apskaičiuotas laukas neturėtų turėti laiko sekos kaupimo tipo raktų.", + "arguments-empty": "Argumentai negali būti tušti.", + "expression-required": "Reikalinga išraiška.", + "expression-invalid": "Išraiška netinkama.", + "expression-max-length": "Išraiškos ilgis turi būti trumpesnis nei 255 simboliai.", + "argument-name-required": "Argumento pavadinimas yra būtinas.", + "argument-name-pattern": "Argumento pavadinimas netinkamas.", + "argument-name-duplicate": "Toks argumento pavadinimas jau egzistuoja.", + "argument-name-max-length": "Argumento pavadinimas turi būti trumpesnis nei 256 simboliai.", + "argument-name-forbidden": "Argumento pavadinimas yra rezervuotas ir negali būti naudojamas.", + "argument-type-required": "Reikalingas argumento tipas.", + "max-args": "Pasiektas didžiausias leidžiamų argumentų skaičius.", + "decimals-range": "Numatytasis dešimtainių skaičius turi būti tarp 0 ir 15.", + "expression": "Numatytoji išraiška parodo, kaip paversti temperatūrą iš Farenheito į Celsijų.", + "arguments-entity-not-found": "Argumento paskirties subjektas nerastas.", + "use-latest-timestamp": "Jei įjungta, apskaičiuota reikšmė bus išsaugota naudojant naujausią argumentų telemetrijos laiko žymą, o ne serverio laiką." + } + }, + "ai-models": { + "ai-models": "AI modeliai", + "ai-model": "AI modelis", + "model": "Modelis", + "name": "Pavadinimas", + "ai-provider": "AI tiekėjas", + "no-found": "AI modelių nerasta", + "list": "{ count, plural, =1 {Vienas modelis} other {# modelių sąrašas} }", + "selected-fields": "{ count, plural, =1 {1 modelis} other {# modeliai} } pasirinkta", + "add": "Pridėti modelį", + "delete-model-title": "Ar tikrai norite pašalinti modelį '{{modelName}}'?", + "delete-model-text": "Būkite atsargūs — po patvirtinimo modelis ir visa su juo susijusi informacija bus negrįžtamai pašalinta.", + "delete-models-title": "Ar tikrai norite pašalinti { count, plural, =1 {1 modelį} other {# modelius} }?", + "delete-models-text": "Būkite atsargūs — po patvirtinimo visi pasirinkti modeliai bus pašalinti kartu su visa susijusia informacija.", + "ai-providers": { + "openai": "OpenAI", + "azure-openai": "Azure OpenAI", + "google-ai-gemini": "Google AI Gemini", + "google-vertex-ai-gemini": "Google Vertex AI Gemini", + "mistral-ai": "Mistral AI", + "anthropic": "Anthropic", + "amazon-bedrock": "Amazon Bedrock", + "github-models": "GitHub Modeliai" + }, + "name-required": "Pavadinimas yra privalomas.", + "name-max-length": "Pavadinimas turi būti ne ilgesnis nei 255 simboliai.", + "provider": "Tiekėjas", + "api-key": "API raktas", + "api-key-required": "API raktas yra privalomas.", + "project-id": "Projekto ID", + "project-id-required": "Projekto ID yra privalomas.", + "location": "Vieta", + "location-required": "Vieta yra privaloma.", + "service-account-key-file": "Paslaugos paskyros rakto failas", + "service-account-key-file-required": "Paslaugos paskyros rakto failas yra privalomas.", + "no-file": "Failas nepasirinktas.", + "drop-file": "Vilkite failą arba spustelėkite, kad pasirinktumėte įkelti failą.", + "personal-access-token": "Asmeninis prieigos raktas", + "personal-access-token-required": "Asmeninis prieigos raktas yra privalomas.", + "configuration": "Konfigūracija", + "model-id": "Modelio ID", + "model-id-required": "Modelio ID yra privalomas.", + "deployment-name": "Diegimo pavadinimas", + "deployment-name-required": "Diegimo pavadinimas yra privalomas.", + "set": "Nustatyti", + "region": "Regionas", + "region-required": "Regionas yra privalomas.", + "access-key-id": "Prieigos rakto ID", + "access-key-id-required": "Prieigos rakto ID yra privalomas.", + "secret-access-key": "Slaptas prieigos raktas", + "secret-access-key-required": "Slaptas prieigos raktas yra privalomas.", + "temperature": "Temperatūra", + "temperature-hint": "Nustato modelio atsakymo atsitiktinumo lygį. Didesnės reikšmės didina atsitiktinumą, mažesnės – mažina.", + "temperature-min": "Turi būti 0 arba daugiau.", + "top-p": "Top P", + "top-p-hint": "Sukuria baseiną tikėtiniausių žetonų, iš kurių modelis gali rinktis. Didesnės reikšmės sukuria didesnį ir įvairesnį baseiną, mažesnės – siauresnį.", + "top-p-min-max": "Turi būti didesnis nei 0 ir neviršyti 1.", + "top-k": "Top K", + "top-k-hint": "Apriboja modelio pasirinkimus iki fiksuoto „K“ tikėtiniausių žetonų rinkinio.", + "top-k-min": "Turi būti 0 arba daugiau.", + "presence-penalty": "Buvo pasirodymo bauda", + "presence-penalty-hint": "Taikoma fiksuota bauda žetonui, jei jis jau buvo panaudotas tekste.", + "frequency-penalty": "Dažnio bauda", + "frequency-penalty-hint": "Taikoma bauda žetono tikimybei, kuri didėja priklausomai nuo jo pasikartojimo dažnio tekste.", + "max-output-tokens": "Maksimalus išvesties žetonų skaičius", + "max-output-tokens-hint": "Nustato didžiausią žetonų skaičių, kurį modelis gali sugeneruoti viename atsakyme.", + "endpoint": "Pabaigos taškas (Endpoint)", + "endpoint-required": "Pabaigos taškas yra privalomas.", + "service-version": "Paslaugos versija", + "check-connectivity": "Tikrinti ryšį", + "check-connectivity-success": "Bandomasis užklausimas sėkmingas", + "check-connectivity-failed": "Bandomasis užklausimas nepavyko", + "no-model-matching": "Modelių, atitinkančių '{{entity}}', nerasta.", + "model-required": "Modelis yra privalomas.", + "no-model-text": "Modelių nerasta." + }, + "confirm-on-exit": { + "message": "Turite neišsaugotų pakeitimų. Ar tikrai norite palikti šį puslapį?", + "html-message": "Turite neišsaugotų pakeitimų.
Ar tikrai norite palikti šį puslapį?", + "title": "Neišsaugoti pakeitimai" + }, + "contact": { + "country": "Šalis", + "country-required": "Country is required.", + "city": "Miestas", + "state": "Rajonas", + "postal-code": "Pašto kodas", + "postal-code-invalid": "Neteisingas pašto kodo formatas.", + "address": "Adresas", + "address2": "Adresas 2", + "phone": "Telefonas", + "email": "El. paštas", + "no-address": "Adresas nenurodytas", + "no-country-found": "No countries found.", + "no-country-matching": "No country matching '{{country}}' were found.", + "state-max-length": "Rajono pavadinimas negali viršyti 256 simbolių", + "phone-max-length": "Telefono numeris negali viršyti 256 simbolių", + "city-max-length": "Miesto pavadinimas negali viršyti 256 simbolių" + }, + "common": { + "name": "Pavadinimas", + "type": "Tipas", + "general": "Bendra informacija", + "username": "Vartotojo vardas", + "password": "Slaptažodis", + "data": "Duomenys", + "timestamp": "Laiko žyma", + "enter-username": "Įveskite vartotojo vardą", + "enter-password": "Įveskite slaptažodį", + "enter-search": "Įveskite paieškos kriterijus", + "created-time": "Sukūrimo laikas", + "disabled": "Išjungta", + "loading": "Įkeliama...", + "proceed": "Tęsti", + "open-details-page": "Atidaryti informacijos puslapį", + "not-found": "Nerasta", + "value": "Reikšmė", + "documentation": "Dokumentacija", + "time-left": "Likęs laikas: {{time}}", + "output": "Išvestis", + "suffix": { + "s": "s", + "ms": "ms" + }, + "hint": { + "name-required": "Pavadinimas yra privalomas.", + "name-pattern": "Pavadinimas netinkamas.", + "name-max-length": "Pavadinimas turi būti trumpesnis nei 256 simboliai.", + "title-required": "Antraštė yra privaloma.", + "title-pattern": "Antraštė netinkama.", + "title-max-length": "Antraštė turi būti trumpesnė nei 256 simboliai.", + "key-required": "Raktas yra privalomas.", + "key-pattern": "Raktas netinkamas.", + "key-max-length": "Raktas turi būti trumpesnis nei 256 simboliai." + }, + "required-fields": "Trūksta privalomų laukų" + }, + "content-type": { + "json": "Json", + "text": "Tekstas", + "binary": "Binarinis (Base64)" + }, + "color": { + "color": "Spalva" + }, + "customer": { + "customer": "Klientas", + "customers": "Klientai", + "management": "Klientų valdymas", + "dashboard": "Kliento skydelis", + "dashboards": "Klientų skydeliai", + "devices": "Kliento įrenginiai", + "entity-views": "Kliento subjektų rodiniai", + "assets": "Kliento turtas", + "public-dashboards": "Vieši skydeliai", + "public-devices": "Vieši įrenginiai", + "public-assets": "Viešas turtas", + "public-entity-views": "Vieši subjektų rodiniai", + "add": "Pridėti klientą", + "delete": "Pašalinti klientą", + "manage-customer-users": "Kliento vartotojai", + "manage-customer-devices": "Kliento įrenginiai", + "manage-customer-dashboards": "Kliento skydeliai", + "manage-public-devices": "Vieši įrenginiai", + "manage-public-dashboards": "Vieši skydeliai", + "manage-customer-assets": "Kliento turtas", + "manage-customer-edges": "Kliento Edge įrenginiai", + "manage-public-assets": "Viešas turtas", + "add-customer-text": "Pridėti naują klientą", + "no-customers-text": "Klientų nėra", + "customer-details": "Informacija apie klientą", + "delete-customer-title": "Ar tikrai norite pašalinti klientą '{{customerTitle}}'?", + "delete-customer-text": "Būkite dėmesingi – po patvirtinimo kliento ir su juo susijusios informacijos atkurti nebegalėsite.", + "delete-customers-title": "Ar tikrai norite pašalinti { count, plural, =1 {1 klientą} other {# klientus} }?", + "delete-customers-action-title": "Pašalinti { count, plural, =1 {1 klientą} other {# klientus} }", + "delete-customers-text": "Būkite dėmesingi – po patvirtinimo klientų ir su jais susijusios informacijos atkurti nebegalėsite.", + "manage-users": "Vartotojai", + "manage-assets": "Turtas", + "manage-devices": "Įrenginiai", + "manage-dashboards": "Skydeliai", + "title": "Pavadinimas", + "title-required": "Pavadinimas yra privalomas.", + "title-max-length": "Pavadinimas negali viršyti 256 simbolių.", + "description": "Aprašymas", + "details": "Informacija", + "events": "Įvykiai", + "copyId": "Kopijuoti kliento ID", + "idCopiedMessage": "Kliento ID nukopijuotas į iškarpinę", + "select-customer": "Pasirinkti klientą", + "no-customers-matching": "Klientų, atitinkančių '{{entity}}', nerasta.", + "customer-required": "Klientas yra privalomas", + "select-default-customer": "Pasirinkite numatytąjį klientą", + "default-customer": "Numatytasis klientas", + "default-customer-required": "Numatytasis klientas būtinas, norint suderinti prietaisų skydelį valdytojo lygiu", + "search": "Klientų paieška", + "selected-customers": "Pasirinkta { count, plural, =1 {1 klientas} other {# klientai} }", + "edges": "Kliento Edge įrenginiai", + "manage-edges": "Valdyti Edge įrenginius" + }, + "css-size": { + "size-value-required": "Dydžio reikšmė yra privaloma", + "invalid-size-value": "Neteisinga dydžio reikšmė" + }, + "date": { + "last-update-n-ago": "Paskutinis atnaujinimas prieš N", + "last-update-n-ago-text": "Paskutinis atnaujinimas prieš {{ agoText }}", + "custom-date": "Pasirinkta data", + "format": "Formatas", + "preview": "Peržiūra", + "auto": "Automatinis", + "time-granularity-formats": "Laiko granuliacijos formatai", + "unit-year": "Metai", + "unit-month": "Mėnesiai", + "unit-day": "Dienos", + "unit-hour": "Valandos", + "unit-minute": "Minutės", + "unit-second": "Sekundės", + "unit-millisecond": "Milisekundės" + }, + "datetime": { + "date-from": "Data nuo", + "time-from": "Laikas nuo", + "date-to": "Data iki", + "time-to": "Laikas iki", + "from": "Nuo", + "to": "Iki" + }, + "dashboard": { + "dashboard": "Skydelis", + "dashboards": "Skydeliai", + "management": "Skydelių valdymas", + "view-dashboards": "Peržiūrėti skydelius", + "add": "Pridėti skydelį", + "assign-dashboard-to-customer": "Skydelį (-ius) priskirti klientui", + "assign-dashboard-to-customer-text": "Pasirinkite skydelius, kuriuos norite priskirti klientui", + "assign-to-customer-text": "Pasirinkite klientą, kuriam priskirti skydelį (-ius)", + "assign-to-customer": "Priskirti klientui", + "unassign-from-customer": "Atsieti nuo kliento", + "make-public": "Skydelį padaryti viešą", + "make-private": "Skydelį padaryti privatų", + "manage-assigned-customers": "Valdyti priskirtus klientus", + "assigned-customers": "Priskirti klientai", + "assign-to-customers": "Skydelį (-ius) priskirti klientams", + "assign-to-customers-text": "Pasirinkite klientus, kuriems priskirti skydelį (-ius)", + "unassign-from-customers": "Skydelį (-ius) atsieti nuo klientų", + "unassign-from-customers-text": "Pasirinkite klientus, kuriems atsieti skydelį (-ius)", + "no-dashboards-text": "Skydelių nėra", + "no-widgets": "Valdikliai nesukonfigūruoti", + "add-widget": "Pridėti naują valdiklį", + "add-widget-button-text": "Pridėti valdiklį", + "title": "Pavadinimas", + "image": "Skydelio paveikslėlis", + "mobile-app-settings": "Mobiliosios programėlės nustatymai", + "mobile-order": "Skydelio eiliškumas mobiliojoje programėlėje", + "mobile-hide": "Skydelį slėpti mobiliojoje programėlėje", + "update-image": "Atnaujinti skydelio paveikslėlį", + "take-screenshot": "Padaryti ekrano nuotrauką", + "select-widget-title": "Pasirinkite valdiklį", + "select-widget-value": "{{title}}: pasirinkite valdiklį", + "select-widget-subtitle": "Galimų valdiklių sąrašas", + "delete": "Pašalinti skydelį", + "title-required": "Pavadinimas būtinas.", + "title-max-length": "Pavadinimas negali viršyti 256 simbolių", + "description": "Aprašymas", + "details": "Informacija", + "dashboard-details": "Skydelio informacija", + "add-dashboard-text": "Pridėti naują skydelį", + "assign-dashboards": "Priskirti skydelius", + "assign-new-dashboard": "Priskirti naują skydelį", + "assign-dashboards-text": "Priskirti { count, plural, =1 {1 skydelį} other {# skydelius} } klientams", + "unassign-dashboards-action-text": "Atsieti { count, plural, =1 {1 skydelį} other {# skydelius} } nuo klientų", + "delete-dashboards": "Panaikinti skydelius", + "unassign-dashboards": "Atsieti skydelius", + "unassign-dashboards-action-title": "Atsieti { count, plural, =1 {1 skydelį} other {# skydelius} } nuo kliento", + "delete-dashboard-title": "Ar tikrai norite pašalinti skydelį '{{dashboardTitle}}'?", + "delete-dashboard-text": "Būkite dėmesingi, po patvirtinimo skydelio ir su juo susijusios informacijos atkurti nebegalėsite.", + "delete-dashboards-title": "Ar tikrai norite pašalinti { count, plural, =1 {1 skydelį} other {# skydelius} }?", + "delete-dashboards-action-title": "Pašalinti { count, plural, =1 {1 skydelį} other {# skydelius} }", + "delete-dashboards-text": "Būkite dėmesingi, po patvirtinimo pasirinkti skydeliai ir su jais susijusi informacija bus pašalinti ir jų atkurti nebegalėsite.", + "unassign-dashboard-title": "Ar tikrai norite atsieti skydelį '{{dashboardTitle}}'?", + "unassign-dashboard-text": "Po patvirtinimo skydelis bus atsietas ir klientas jo nebematys.", + "unassign-dashboard": "Atsieti skydelį", + "unassign-dashboards-title": "Ar tikrai norite atsieti { count, plural, =1 {1 skydelį} other {# skydelius} }?", + "unassign-dashboards-text": "Po patvirtinimo visi skydeliai bus atsieti ir klientas jų nebematys.", + "public-dashboard-title": "Skydelis dabar yra viešas", + "public-dashboard-text": "Skydelis {{dashboardTitle}} dabar yra viešas ir pasiekiamas per šią nuorodą:", + "public-dashboard-notice": "Pastaba: Įrenginiai turi būti vieši, jei norite matyti jų duomenis.", + "make-private-dashboard-title": "Ar tikrai norite skydelį '{{dashboardTitle}}' padaryti privačiu?", + "make-private-dashboard-text": "Po patvirtinimo skydelis taps privačiu ir jo nematys kiti vartotojai.", + "make-private-dashboard": "Skydelį padaryti privačiu", + "socialshare-text": "'{{dashboardTitle}}' sukurta naudojant ThingsBoard", + "socialshare-title": "'{{dashboardTitle}}' sukurta naudojant ThingsBoard", + "select-dashboard": "Pasirinkti skydelį", + "no-dashboards-matching": "Skydelio, atitinkančio '{{entity}}', nėra.", + "dashboard-required": "Skydelis būtinas.", + "select-existing": "Pasirinkti esamą skydelį", + "create-new": "Sukurti naują skydelį", + "new-dashboard-title": "Naujo skydelio pavadinimas", + "open-dashboard": "Atidaryti skydelį", + "set-background": "Nustatyti foną", + "background-color": "Fono spalva", + "background-image": "Fono paveikslėlis", + "background-size-mode": "Fono dydis", + "no-image": "Paveikslėlis nepasirinktas", + "empty-image": "Nėra paveikslėlio", + "drop-image": "Užvilkite paveikslėlį arba spustelėkite ir pasirinkite failą.", + "maximum-upload-file-size": "Maksimalus įkeliamo failo dydis: {{ size }}", + "cannot-upload-file": "Failo įkelti nepavyko", + "settings": "Nustatymai", + "move-all-widgets": "Perkelti visus valdiklius", + "move-by": "Perkelti per", + "cols": "Stulpeliai", + "rows": "Eilutės", + "layout": "Išdėstymas", + "layout-type-default": "Numatytasis", + "layout-type-scada": "SCADA", + "layout-type-divider": "Skyriklis", + "layout-settings-type": "Išdėstymo nustatymai: {{ type }} lūžio taškas", + "columns-count": "Stulpelių skaičius", + "columns-count-required": "Stulpelių skaičius būtinas.", + "min-columns-count-message": "Minimalus stulpelių skaičius - 10.", + "max-columns-count-message": "Maksimalus stulpelių skaičius - 1000.", + "min-layout-width": "Minimalus išdėstymo plotis", + "columns-suffix": "stulpeliai", + "widgets-margins": "Paraštės tarp valdiklių dydis", + "margin-required": "Paraštės dydžio reikšmė būtina.", + "min-margin-message": "Minimali paraštės dydžio reikšmė - 0.", + "max-margin-message": "Maksimali paraštės dydžio reikšmė - 50.", + "horizontal-margin": "Horizontalios paraštės dydis", + "horizontal-margin-required": "Horizontalios paraštės dydžio reikšmė būtina.", + "min-horizontal-margin-message": "Minimali horizontalios paraštės dydžio reikšmė - 0", + "max-horizontal-margin-message": "Maksimali horizontalios paraštės dydžio reikšmė - 50.", + "vertical-margin": "Vertikalios paraštės dydis", + "vertical-margin-required": "Vertikalios paraštės dydžio reikšmė būtina.", + "min-vertical-margin-message": "Minimali vertikalios paraštės dydžio reikšmė - 0.", + "max-vertical-margin-message": "Maksimali vertikalios paraštės dydžio reikšmė - 50.", + "apply-outer-margin": "Taikyti paraštes maketo šonuose", + "autofill-height": "Automatiškai pritaikyti aukštį", + "mobile-layout": "Mobiliojo režimo išdėstymo nustatymai", + "mobile-row-height": "Mobiliojo režimo eilutės aukštis pikseliais", + "mobile-row-height-required": "Mobiliojo režimo eilutės aukštis būtinas.", + "min-mobile-row-height-message": "Minimalus mobiliojo režimo eilutės aukštis yra 5 pikseliai.", + "max-mobile-row-height-message": "Maksimalus mobiliojo režimo eilutės aukštis yra 200 pikselių.", + "row-height": "Eilutės aukštis", + "row-height-required": "Eilutės aukščio reikšmė yra privaloma.", + "min-row-height-message": "Mažiausias eilutės aukštis – 5 pikseliai.", + "max-row-height-message": "Didžiausias eilutės aukštis – 200 pikselių.", + "display-first-in-mobile-view": "Rodyti pirmą mobiliajame rodinyje", + "title-settings": "Pavadinimo nustatymai", + "display-title": "Rodyti skydelio pavadinimą", + "title-color": "Pavadinimo spalva", + "toolbar-settings": "Įrankių juostos nustatymai", + "hide-toolbar": "Paslėpti įrankių juostą", + "toolbar-always-open": "Įrankių juostą laikyti atidarytą", + "display-dashboards-selection": "Rodyti skydelių pasirinkimą", + "display-entities-selection": "Rodyti subjektų pasirinkimą", + "display-filters": "Rodyti filtrus", + "display-dashboard-timewindow": "Rodyti laiko langą", + "display-dashboard-export": "Rodyti eksportą", + "display-update-dashboard-image": "Rodyti skydelio paveikslėlio atnaujinimą", + "dashboard-logo-settings": "Skydelio logotipo nustatymai", + "display-dashboard-logo": "Rodyti logotipą skydelio viso ekrano režime", + "dashboard-logo-image": "Skydelio logotipo paveikslėlis", + "advanced-settings": "Išplėstiniai nustatymai", + "dashboard-css": "Skydelio CSS", + "import": "Importuoti skydelį", + "export": "Eksportuoti skydelį", + "export-failed-error": "Skydelio eksportuoti nepavyko: {{error}}", + "export-prompt": "Įterpti skydelio paveikslėlius ir išteklius", + "create-new-dashboard": "Sukurti naują skydelį", + "dashboard-file": "Skydelio failas", + "invalid-dashboard-file-error": "Skydelio importuoti nepavyko: neteisinga duomenų struktūra.", + "dashboard-import-missing-aliases-title": "Konfigūruoti importuoto skydelio naudojamus pseudonimus", + "create-new-widget": "Sukurti naują valdiklį", + "import-widget": "Importuoti valdiklį", + "widget-file": "Valdiklio failas", + "invalid-widget-file-error": "Valdiklio importuoti nepavyko: neteisinga duomenų struktūra.", + "widget-import-missing-aliases-title": "Konfigūruoti importuoto valdiklio naudojamus pseudonimus", + "open-toolbar": "Atidaryti skydelio įrankių juostą", + "close-toolbar": "Uždaryti įrankių juostą", + "configuration-error": "Konfigūracijos klaida", + "alias-resolution-error-title": "Skydelio pseudonimų konfigūracijos klaida", + "invalid-aliases-config": "Įrenginių, atitinkančių pseudonimų filtrus, nėra.
Susisiekite su sistemos administratoriumi.", + "select-devices": "Pasirinkite įrenginius", + "assignedToCustomer": "Priskirta klientui", + "assignedToCustomers": "Priskirta klientams", + "public": "Viešas", + "copyId": "Kopijuoti skydelio Id", + "idCopiedMessage": "Skydelio Id nukopijuotas į iškarpinę", + "public-link": "Vieša nuoroda", + "copy-public-link": "Kopijuoti viešą nuorodą", + "public-link-copied-message": "Skydelio vieša nuoroda nukopijuota į iškarpinę", + "manage-states": "Valdyti skydelio būsenas", + "states": "Skydelio būsenos", + "states-short": "Būsenos", + "search-states": "Skydelio būsenų paieška", + "selected-states": "Pasirinkta skydelio { count, plural, =1 {1 būsena} other {# būsenos} }", + "edit-state": "Redaguoti skydelio būseną", + "delete-state": "Panaikinti skydelio būseną", + "add-state": "Pridėti skydelio būseną", + "no-states-text": "Būsenų nėra", + "state": "Skydelio būsena", + "state-name": "Pavadinimas", + "state-name-required": "Skydelio pavadinimas būtinas.", + "state-id": "Būsenos Id", + "state-id-required": "Būsenos Id būtinas.", + "state-id-exists": "Skydelio būsena su tokiu pačiu Id jau yra.", + "is-root-state": "Pagrindinė būsena", + "delete-state-title": "Panaikinti skydelio būseną", + "delete-state-text": "Ar tikrai norite panaikinti skydelio būseną '{{stateName}}'?", + "show-details": "Rodyti detales", + "hide-details": "Slėpti detales", + "select-state": "Pasirinkite būseną", + "state-controller": "Būsenų valdiklis", + "state-controller-default": "static (pasenęs)", + "search": "Skydelių paieška", + "selected-dashboards": "Pasirinkta { count, plural, =1 {1 skydelis} other {# skydeliai} }", + "home-dashboard": "Pagrindinis skydelis", + "home-dashboard-hide-toolbar": "Slėpti pagrindinio skydelio įrankių juostą", + "unassign-dashboard-from-edge-text": "Po patvirtinimo skydelis bus atsietas ir nebus pasiekiamas Edge įrenginio.", + "unassign-dashboards-from-edge-title": "Ar tikrai norite atsieti { count, plural, =1 {1 skydelį} other {# skydelius} }?", + "unassign-dashboards-from-edge-text": "Po patvirtinimo visi pasirinkti skydeliai bus atsieti ir nebus pasiekiami Edge įrenginio.", + "assign-dashboard-to-edge": "Priskirti skydelį (-ius) Edge įrenginiui", + "assign-dashboard-to-edge-text": "Pasirinkite skydelius, kuriuos priskirti Edge įrenginiui", + "non-existent-dashboard-state-error": "Skydelio būsena su id „{{ stateId }}“ nerasta", + "edit-mode": "Redagavimo režimas", + "duplicate-state-action": "Dubliuoti būseną", + "breakpoint-value": "Lūžio taškas ({{ value }})", + "breakpoints-id": { + "default": "Numatytasis", + "xs": "Mobilusis (xs)", + "sm": "Planšetė (sm)", + "md": "Nešiojamas (md)", + "lg": "Stalinis (lg)", + "xl": "Stalinis (xl)" + }, + "view-format-type-grid": "Tinklelis", + "view-format-type-list": "Sąrašas", + "view-format": "Rodinio formatas" + }, + "datakey": { + "settings": "Nustatymai", + "general": "Bendra", + "advanced": "Pažangūs nustatymai", + "key": "Raktas", + "keys": "Raktai", + "label": "Etiketė", + "color": "Spalva", + "units": "Vienetai (simboliai, rodomi šalia reikšmės)", + "decimals": "Skaitmenų po kablelio kiekis", + "data-generation-func": "Duomenų generavimo funkcija", + "use-data-post-processing-func": "Naudoti papildomo duomenų apdorojimo funkciją", + "configuration": "Duomenų raktų konfigūracija", + "timeseries": "Telemetrija", + "attributes": "Atributai", + "entity-field": "Subjekto laukas", + "alarm": "Įspėjimo laukai", + "timeseries-required": "Subjekto telemetrija būtina.", + "timeseries-or-attributes-required": "Subjekto telemetrija arba atributai būtini.", + "alarm-fields-timeseries-or-attributes-required": "Įspėjimo laukai arba subjekto telemetrija/atributai būtini.", + "maximum-timeseries-or-attributes": "Leidžiama daugiausiai { count, plural, =1 {1 telemetrija/atributas} other {# telemetrijų/atributų} }.", + "alarm-fields-required": "Įspėjimo laukai būtini.", + "function-types": "Funkcijų tipai", + "function-type": "Funkcijos tipas", + "function-types-required": "Funkcijos tipas būtinas.", + "data-keys": "Duomenų raktai", + "data-key": "Duomenų raktas", + "data-keys-required": "Duomenų raktai būtini.", + "data-key-required": "Duomenų raktas būtinas.", + "alarm-keys": "Įspėjimo duomenų raktai", + "alarm-key": "Įspėjimo duomenų raktas", + "alarm-key-functions": "Įspėjimo rakto funkcijos", + "alarm-key-function": "Įspėjimo rakto funkcija", + "latest-keys": "Naujausi duomenų raktai", + "latest-key": "Naujausias duomenų raktas", + "latest-key-functions": "Naujausio rakto funkcijos", + "latest-key-function": "Naujausio rakto funkcija", + "timeseries-keys": "Telemetrijos duomenų raktai", + "timeseries-key": "Telemetrijos duomenų raktas", + "timeseries-key-functions": "Telemetrijos rakto funkcijos", + "timeseries-key-function": "Telemetrijos rakto funkcija", + "maximum-function-types": "Daugiausia leidžiama { count, plural, =1 {1 funkcijos tipas} other {# funkcijos tipai} }.", + "time-description": "Dabartinės vertės laiko žyma;", + "value-description": "Dabartinė vertė;", + "prev-value-description": "Ankstesnio funkcijos kvietimo rezultatas;", + "time-prev-description": "Ankstesnės vertės laiko žyma;", + "prev-orig-value-description": "Pradinė ankstesnė vertė;", + "aggregation": "Agregavimas", + "aggregation-type-hint-common": "Dėl našumo priežasčių agreguotų reikšmių skaičiavimas galimas tik fiksuotiems laiko intervalams, pvz., 'dabartinė diena', 'dabartinis mėnuo' ir pan. Tai netaikoma slankiesiems intervalams, kaip 'paskutinės 30 min' ar 'paskutinės 24 val'.", + "aggregation-type-none-hint": "Naudoti naujausią reikšmę.", + "aggregation-type-min-hint": "Rasti mažiausią reikšmę tarp duomenų taškų pasirinktoje laiko atkarpoje.", + "aggregation-type-max-hint": "Rasti didžiausią reikšmę tarp duomenų taškų pasirinktoje laiko atkarpoje.", + "aggregation-type-avg-hint": "Apskaičiuoti vidurkį tarp duomenų taškų pasirinktoje laiko atkarpoje.", + "aggregation-type-sum-hint": "Suskaičiuoti visų duomenų taškų reikšmių sumą pasirinktoje laiko atkarpoje.", + "aggregation-type-count-hint": "Duomenų taškų skaičius pasirinktoje laiko atkarpoje.", + "delta-calculation": "Delta skaičiavimas", + "enable-delta-calculation": "Įjungti delta skaičiavimą", + "enable-delta-calculation-hint": "Kai įjungta, rakto reikšmė skaičiuojama pagal agreguotas reikšmes pasirinktam laikotarpiui ir lyginimo periodui. Dėl našumo delta skaičiavimas galimas tik istoriniams laikotarpiams, o ne realaus laiko reikšmėms. Pvz., galima apskaičiuoti skirtumą tarp vakarykščio ir užvakar dienos energijos suvartojimo.", + "delta-calculation-result": "Delta skaičiavimo rezultatas", + "delta-calculation-result-previous-value": "Ankstesnė reikšmė", + "delta-calculation-result-delta-absolute": "Delta (absoliuti)", + "delta-calculation-result-delta-percent": "Delta (procentinė)", + "source": "Šaltinis", + "latest": "Naujausia", + "latest-value": "Naujausia reikšmė", + "delta": "delta", + "percent": "procentai", + "absolute": "absoliuti" + }, + "datasource": { + "type": "Duomenų šaltinio tipas", + "name": "Pavadinimas", + "label": "Etiketė", + "add-datasource-prompt": "Pridėkite duomenų šaltinį" + }, + "details": { + "details": "Informacija", + "edit-mode": "Redagavimo režimas", + "edit-json": "Redaguoti JSON", + "toggle-edit-mode": "Redagavimo režimas" + }, + "device": { + "device": "Įrenginys", + "device-required": "Įrenginys būtinas.", + "devices": "Įrenginiai", + "management": "Įrenginių valdymas", + "view-devices": "Peržiūrėti įrenginius", + "device-alias": "Įrenginio pseudonimas", + "device-type-max-length": "Įrenginio tipas negali viršyti 256 simbolių", + "aliases": "Įrenginių pseudonimai aliases", + "no-alias-matching": "'{{alias}}' nerasta.", + "no-aliases-found": "Pseudonimų nėra.", + "no-key-matching": "'{{key}}' nerasta.", + "no-keys-found": "Raktų nėra.", + "create-new-alias": "Sukurti naują!", + "create-new-key": "Sukurti naują!", + "duplicate-alias-error": "'{{alias}}' dubliuojasi.
Įrenginio pseudonimai skydelyje turi būti unikalūs.", + "configure-alias": "Sukonfigūruoti '{{alias}}' pseudonimą", + "no-devices-matching": "Įrenginių, attinkančių '{{entity}}' nėra.", + "alias": "Pseudonimas", + "alias-required": "Įrenginio pseudonimas būtinas.", + "remove-alias": "Panaikinti įrenginio pseudonimą", + "add-alias": "Pridėti įrenginio pseudonimą", + "name-starts-with": "Įrenginio pavadinimas prasideda", + "help-text": "Naudokite '%' simbolį pagal tai, kaip norite ieškoti: '%įrenginio_pavadinimo_fragmentas%', '%įrenginio_pavadinimo_pabaiga', 'įrenginio_pavadinimo_pradžia%'.", + "device-list": "Įrenginių sąrašas", + "use-device-name-filter": "Naudoti filtrą", + "device-list-empty": "Įrenginiai nepasirinkti.", + "device-name-filter-required": "Įrenginio pavadinimo filtras turi būti nustatytas.", + "device-name-filter-no-device-matched": "Įrenginių, kurių pavadinimas prasideda '{{device}}' nėra.", + "add": "Pridėti įrenginį", + "assign-to-customer": "Priskirti kientui", + "assign-device-to-customer": "Įrenginį (-ius) priskirti klientui", + "assign-device-to-customer-text": "Pasirinkite įrenginius, kuriuos norite priskirti klientui", + "make-public": "Įrenginį padaryti viešu", + "make-private": "Įrenginį padaryti privačiu", + "no-devices-text": "Įrenginių nėra", + "assign-to-customer-text": "Pasirinkite klientą, kuriam norite priskirti įrenginį (-ius)", + "device-details": "Įrenginio informacija", + "add-device-text": "Pridėti naują įrenginį", + "credentials": "Įgaliojimai", + "manage-credentials": "Valdyti įgaliojimus", + "delete": "Panaikinti įrenginį", + "assign-devices": "priskirti įrenginius", + "assign-devices-text": "Priskirti { count, plural, =1 {1 įrenginį} other {# įrenginius} } klientui", + "delete-devices": "Panaikinti įrenginius", + "unassign-from-customer": "Atseti nuo kliento", + "unassign-devices": "Atsieti įrenginius", + "unassign-devices-action-title": "Atsieti { count, plural, =1 {1 įrenginį} other {# įrenginius} } nuo kliento", + "unassign-device-from-edge-title": "Are you sure you want to unassign the device '{{deviceName}}'?", + "unassign-device-from-edge-text": "After the confirmation the device will be unassigned and won't be accessible by the edge.", + "unassign-devices-from-edge": "Unassign devices from edge", + "assign-new-device": "Priskirti naują įrenginį", + "make-public-device-title": "Ar tikrai norite įrenginį '{{deviceName}}' padaryti viešu?", + "make-public-device-text": "Po patvirtinimo įrenginys ir visi jo duomenys bus vieši ir prieinami kitiems vartotojams.", + "make-private-device-title": "Ar tikrai norite įrenginį '{{deviceName}}' padaryti privačiu?", + "make-private-device-text": "Po patvirtinimo įrenginys ir visi jo duomenys taps privatūs ir nebus prieinami kitiems vartotojams.", + "view-credentials": "Peržiūrėti įgaliojimus", + "delete-device-title": "Ar tikrai norite panaikinti įrenginį '{{deviceName}}'?", + "delete-device-text": "Būkite dėmesingi, po patvirtinimo įrenginys ir visa su juo susijusi informacija bus panaikinta ir jų atkurti nebegalėsite", + "delete-devices-title": "Ar tikrai norite panaikinti { count, plural, =1 {1 įrenginį} other {# įrenginius} }?", + "delete-devices-action-title": "Panaikinti { count, plural, =1 {1 įrenginį} other {# įrenginius} }", + "delete-devices-text": "Būkite dėmesingi, po patvirtinimo, visi pasirinkti įrenginiai ir su jais susijusi informacija bus panaikinta ir jų atkurti nebegalėsite.", + "unassign-device-title": "Ar tikrai norite atsieti įrenginį '{{deviceName}}'?", + "unassign-device-text": "Po patvirtinimo įrenginys bus atsietas ir klientas jo nebematys.", + "unassign-device": "Atsieti įrenginį", + "unassign-devices-title": "Ar tikrai norite atsieti { count, plural, =1 {1 įrenginį} other {# įrenginius} }?", + "unassign-devices-text": "Po patvirtinimo visi pasirinkti įrenginiai bus atsieti nuo kliento.", + "device-credentials": "įrenginio įgaliojimai", + "loading-device-credentials": "Įkeliami įrenginio įgaliojimai...", + "credentials-type": "Įgaliojimų tipas", + "access-token": "Prieigos raktas", + "access-token-required": "Prieigos raktas būtinas.", + "access-token-invalid": "Prieigos rakto ilgis turi būti nuo 1 iki 32 simbolių.", + "certificate-pem-format": "Sertifikatas PEM formate", + "certificate-pem-format-required": "Certificate is required.", + "copy-access-token": "Kopijuoti prieigos raktą", + "copy-certificate": "Kopijuoti sertifikatą", + "copy-client-id": "Kopijuoti kliento ID", + "copy-user-name": "Kopijuoti vartotojo vardą", + "copy-password": "Kopijuoti slaptažodį", + "generate-client-id": "Generuoti kliento ID", + "generate-user-name": "Generuoti vartotojo vardą", + "generate-password": "Generuoti slaptažodį", + "generate-access-token": "Generuoti prieigos raktą", + "lwm2m-security-config": { + "identity": "Kliento identifikatorius", + "identity-required": "Kliento identifikatorius būtinas.", + "identity-tooltip": "PSK identifikatorius yra savavališkai parinktas iki 128 baitų identifikatorius, kaip aprašyta standarte [RFC7925].\nPSK identifikatorius pirmiausia turi būti konvertuotas į simbolių eilutę ir tada užkoduotas į baitus naudojant UTF-8.", + "client-key": "Kliento raktas", + "client-key-required": "Kliento raktas būtinas.", + "client-key-tooltip-prk": "RPK viešasis raktas arba ID turi atitikti standartą [RFC7250] ir būti užkoduotas Base64 formatu!", + "client-key-tooltip-psk": "PSK raktas turi atitikti standartą [RFC4279] ir būti HexDec formatu: 32, 64 arba 128 simboliai!", + "endpoint": "Kliento galinio taško pavadinimas (Endpoint)", + "endpoint-required": "Kliento galinio taško pavadinimas būtinas.", + "client-public-key": "Kliento viešasis raktas", + "client-public-key-hint": "Jei viešasis raktas nenurodytas, bus naudojamas patikimas sertifikatas.", + "client-public-key-tooltip": "X509 viešasis raktas turi būti DER koduotas X509v3 formatu, naudoti tik EC algoritmą ir būti užkoduotas Base64 formatu!", + "mode": "Saugumo konfigūracijos režimas", + "client-tab": "Kliento saugumo konfigūracija", + "client-certificate": "Kliento sertifikatas", + "bootstrap-tab": "Bootstrap klientas", + "bootstrap-server": "Bootstrap serveris", + "lwm2m-server": "LwM2M serveris", + "client-publicKey-or-id": "Kliento viešasis raktas arba ID", + "client-publicKey-or-id-required": "Kliento viešasis raktas arba ID būtinas.", + "client-publicKey-or-id-tooltip-psk": "PSK identifikatorius yra savavališkai parinktas iki 128 baitų identifikatorius, kaip aprašyta standarte [RFC7925].\nPSK identifikatorius pirmiausia turi būti konvertuotas į simbolių eilutę ir tada užkoduotas į baitus naudojant UTF-8.", + "client-publicKey-or-id-tooltip-rpk": "RPK viešasis raktas arba ID turi atitikti standartą [RFC7250] ir būti užkoduotas Base64 formatu!", + "client-publicKey-or-id-tooltip-x509": "X509 viešasis raktas turi būti DER koduotas X509v3 formatu, naudoti tik EC algoritmą ir būti užkoduotas Base64 formatu!", + "client-secret-key": "Kliento slaptasis raktas", + "client-secret-key-required": "Kliento slaptasis raktas būtinas.", + "client-secret-key-tooltip-psk": "PSK raktas turi atitikti standartą [RFC4279] ir būti HexDec formatu: 32, 64 arba 128 simboliai!", + "client-secret-key-tooltip-prk": "RPK slaptasis raktas turi būti PKCS_8 formatu (DER kodavimas, standartas [RFC5958]) ir būti užkoduotas Base64 formatu!", + "client-secret-key-tooltip-x509": "X509 slaptasis raktas turi būti PKCS_8 formatu (DER kodavimas, standartas [RFC5958]) ir būti užkoduotas Base64 formatu!" + }, + "client-id": "Kliento ID", + "client-id-pattern": "Yra netinkamas simbolis.", + "user-name": "Vartotojo vardas", + "user-name-required": "Vartotojo vardas būtinas.", + "client-id-or-user-name-necessary": "Kliento ID ir/arba vartotojo vardas būtini.", + "password": "Slaptažodis", + "secret": "Slaptas raktas", + "secret-required": "Slaptas raktas būtinas.", + "device-type": "Įrenginio tipas", + "device-type-required": "Įrenginio tipas būtinas.", + "select-device-type": "Pasirinkite įrenginio tipą", + "enter-device-type": "Įveskite įrenginio tipą", + "any-device": "Bet kuris įrenginys", + "no-device-types-matching": "Įrenginio tipų, atitinkančių '{{entitySubtype}}', nėra.", + "device-type-list-empty": "Nepasirinktas įrenginio tipas!", + "device-profile-type-list-empty": "Turi būti pasirinktas bent vienas įrenginio profilis.", + "device-types": "Įrenginių tipai", + "name": "Pavadinimas", + "name-required": "Pavadinimas būtinas.", + "name-max-length": "Pavadinimas negali viršyti 256 simbolių.", + "label-max-length": "Etiketė negali viršyti 256 simbolių.", + "description": "Aprašymas", + "label": "Etiketė", + "events": "Įvykiai", + "details": "Informacija", + "copyId": "Kopijuoti įrenginio ID", + "copyAccessToken": "Kopijuoti prieigos raktą", + "copy-mqtt-authentication": "Kopijuoti MQTT autentifikacijos duomenis", + "idCopiedMessage": "Įrenginio ID nukopijuotas į iškarpinę.", + "accessTokenCopiedMessage": "Įrenginio prieigos raktas nukopijuotas į iškarpinę.", + "mqtt-authentication-copied-message": "Įrenginio MQTT autentifikacijos duomenys nukopijuoti į iškarpinę.", + "assignedToCustomer": "Priskirtas klientui", + "unable-delete-device-alias-title": "Nepavyko panaikinti įrenginio pseudonimo", + "unable-delete-device-alias-text": "Įrenginio pseudonimo '{{deviceAlias}}' panaikinti nepavyko, nes jis naudojamas šiuose valdikliuose:
{{widgetsList}}", + "is-gateway": "Yra šliuzas (Gateway)", + "overwrite-activity-time": "Perrašyti aktyvumo laiką prijungtam įrenginiui", + "device-filter": "Įrenginių filtras", + "device-filter-title": "Įrenginių filtras", + "filter-title": "Filtras", + "device-state": "Įrenginio būsena", + "state": "Būsena", + "any": "Visos", + "active": "Aktyvus", + "inactive": "Neaktyvus", + "public": "Viešas", + "device-public": "Įrenginys yra viešas", + "select-device": "Pasirinkite įrenginį", + "import": "Importuoti įrenginį", + "device-file": "Įrenginio failas", + "search": "Įrenginių paieška", + "selected-devices": "Pasirinkta { count, plural, =1 {1 įrenginys} other {# įrenginiai} }", + "device-configuration": "Įrenginio konfigūracija", + "transport-configuration": "Transporto konfigūracija", + "wizard": { + "device-details": "Informacija apie įrenginį" + }, + "unassign-devices-from-edge-title": "Ar tikrai norite atsieti { count, plural, =1 {1 įrenginį} other {# įrenginius} } nuo Edge?", + "unassign-devices-from-edge-text": "Po patvirtinimo visi pasirinkti įrenginiai bus atsieti ir nebebus pasiekiami per Edge.", + "time": "Laikas", + "connectivity": { + "check-connectivity": "Patikrinti ryšį", + "device-created-check-connectivity": "Įrenginys sukurtas. Patikrinkime ryšį!", + "loading-check-connectivity-command": "Įkeliamos ryšio tikrinimo komandos...", + "use-following-instructions": "Naudokite šias instrukcijas, kad išsiųstumėte telemetriją įrenginio vardu naudodami komandų eilutę (shell).", + "execute-following-command": "Vykdykite šią komandą", + "install-curl-windows": "Nuo Windows 10 versijos 17063, cURL įrankis prieinamas pagal numatymą.", + "install-curl-macos": "Nuo Mac OS X 10.2 (Jaguar) versijos, cURL įrankis prieinamas pagal numatymą.", + "install-mqtt-windows": "Naudokite instrukcijas, kad atsisiųstumėte, įdiegtumėte, sukonfigūruotumėte ir paleistumėte „mosquitto_pub“ įrankį.", + "install-coap-client": "Naudokite instrukcijas, kad atsisiųstumėte, įdiegtumėte, sukonfigūruotumėte ir paleistumėte „coap-client“ įrankį.", + "install-necessary-client-tools": "Įdiekite būtinus kliento įrankius", + "mqtts-x509-command": "Naudokite šią dokumentaciją, kad prijungtumėte įrenginį per MQTT su X.509 autorizacija.", + "coaps-x509-command": "Naudokite šią dokumentaciją, kad prijungtumėte įrenginį per CoAP (DTLS) su X.509 autorizacija.", + "snmp-command": "Naudokite šią dokumentaciją, kad prijungtumėte įrenginį per SNMP protokolą.", + "sparkplug-command": "Naudokite šią dokumentaciją, kad prijungtumėte įrenginį per MQTT Sparkplug protokolą.", + "lwm2m-command": "Naudokite šią dokumentaciją, kad prijungtumėte įrenginį per LwM2M protokolą." + } + }, + "dynamic-form": { + "property": { + "properties": "Savybės", + "property": "Savybė", + "id": "Id", + "name": "Pavadinimas", + "type": "Tipas", + "type-text": "Tekstas", + "type-password": "Slaptažodis", + "type-textarea": "Teksto sritis", + "type-number": "Skaičius", + "type-switch": "Perjungiklis", + "type-select": "Pasirinkimas", + "type-radios": "Žymimieji mygtukai", + "type-datetime": "Data / Laikas", + "type-image": "Paveikslėlis", + "type-javascript": "JavaScript", + "type-json": "JSON", + "type-html": "HTML", + "type-css": "CSS", + "type-markdown": "Markdown", + "type-color": "Spalva", + "type-color-settings": "Spalvų nustatymai", + "type-font": "Šriftas", + "type-units": "Vienetai", + "type-icon": "Piktograma", + "type-fieldset": "Lauko rinkinys (fieldset)", + "type-array": "Masyvas", + "type-html-section": "HTML sekcija", + "group-title": "Grupės pavadinimas", + "no-properties": "Savybės nesukonfigūruotos", + "add-property": "Pridėti savybę", + "property-settings": "Savybės nustatymai", + "remove-property": "Pašalinti savybę", + "default-value": "Numatytoji reikšmė", + "value-required": "Reikšmė būtina", + "number-settings": "Skaičiaus nustatymai", + "min": "Min", + "max": "Maks", + "step": "Žingsnis", + "selected-options-limit": "Pasirinktų parinkčių limitas", + "advanced-ui-settings": "Išplėstiniai UI nustatymai", + "disable-on-property": "Išjungti pagal savybę", + "disable-on-property-none": "Nėra (laukas visada įjungtas)", + "display-condition-function": "Rodymo sąlygos funkcija", + "sub-label": "Papildoma etiketė", + "vertical-divider-after": "Vertikalus skirtukas po elemento", + "input-field-suffix": "Įvesties lauko sufiksas", + "property-row-classes": "Savybės eilutės CSS klasės", + "property-field-classes": "Savybės lauko CSS klasės", + "not-unique-property-ids-error": "Savybių ID turi būti unikalūs!", + "enable-multiple-select": "Įjungti daugybinį pasirinkimą", + "allow-empty-select-option": "Leisti tuščią pasirinkimo reikšmę", + "select-options": "Pasirinkimo parinktys", + "not-unique-select-option-value-error": "Pasirinkimo reikšmės turi būti unikalios!", + "value": "Reikšmė", + "label": "Etiketė", + "add-option": "Pridėti parinktį", + "no-options": "Parinkčių nėra", + "remove-option": "Pašalinti parinktį", + "textarea-rows": "Teksto srities eilučių skaičius", + "help-id": "Pagalbos ID", + "buttons-direction": "Mygtukų išdėstymo kryptis", + "direction-row": "Eilutėje", + "direction-column": "Stulpelyje", + "radio-button-options": "Žymimųjų mygtukų parinktys", + "datetime-type": "Datos/laiko lauko tipas", + "datetime-type-date": "Data", + "datetime-type-time": "Laikas", + "datetime-type-datetime": "Data ir laikas", + "enable-clear-button": "Įjungti išvalymo mygtuką", + "html-section-settings": "HTML sekcijos nustatymai", + "html-section-classes": "HTML sekcijos CSS klasės", + "html-section-content": "HTML sekcijos turinys", + "array-item": "Masyvo elementas", + "item-type": "Elemento tipas", + "item-name": "Elemento pavadinimas", + "no-items": "Elementų nėra", + "support-unit-conversion": "Palaikyti vienetų konvertavimą" + }, + "clear-form": "Išvalyti formą", + "clear-form-prompt": "Ar tikrai norite pašalinti visas formos savybes?", + "import-form": "Importuoti formą iš JSON", + "export-form": "Eksportuoti formą į JSON", + "json-file": "JSON failas", + "json-content": "JSON turinys", + "invalid-form-json-file-error": "Nepavyko importuoti formos iš JSON: neteisinga formos JSON duomenų struktūra." + }, + "asset-profile": { + "asset-profile": "Turto profilis", + "asset-profiles": "Turto profiliai", + "all-asset-profiles": "Visi turto profiliai", + "add": "Pridėti turto profilį", + "edit": "Redaguoti turto profilį", + "asset-profile-details": "Turto profilio informacija", + "no-asset-profiles-text": "Turto profilių nerasta", + "search": "Ieškoti turto profilių", + "selected-asset-profiles": "{ count, plural, =1 {1 turto profilis} other {# turto profiliai} } pasirinkta", + "no-asset-profiles-matching": "Turto profilio, atitinkančio '{{entity}}', nerasta.", + "asset-profile-required": "Turto profilis būtinas.", + "idCopiedMessage": "Turto profilio ID nukopijuotas į iškarpinę", + "set-default": "Nustatyti kaip numatytąjį turto profilį", + "delete": "Pašalinti turto profilį", + "copyId": "Kopijuoti turto profilio ID", + "name-max-length": "Pavadinimas turi būti trumpesnis nei 256 simboliai.", + "new-device-profile-name": "Turto profilio pavadinimas", + "new-device-profile-name-required": "Turto profilio pavadinimas būtinas.", + "name": "Pavadinimas", + "name-required": "Pavadinimas būtinas.", + "image": "Turto profilio paveikslėlis", + "description": "Aprašymas", + "default": "Numatytasis", + "default-rule-chain": "Numatytoji taisyklių grandinė", + "default-edge-rule-chain": "Numatytoji Edge taisyklių grandinė", + "default-edge-rule-chain-hint": "Naudojama Edge aplinkoje apdoroti gaunamus duomenis turtui, kuris priklauso šiam profiliui.", + "mobile-dashboard": "Mobilusis skydelis", + "mobile-dashboard-hint": "Naudojamas mobiliojoje programėlėje kaip turto informacijos skydelis.", + "select-queue-hint": "Pasirinkite iš išskleidžiamojo sąrašo.", + "delete-asset-profile-title": "Ar tikrai norite pašalinti turto profilį '{{assetProfileName}}'?", + "delete-asset-profile-text": "Būkite atsargūs, po patvirtinimo turto profilis ir visi su juo susiję duomenys bus negrįžtamai pašalinti.", + "delete-asset-profiles-title": "Ar tikrai norite pašalinti { count, plural, =1 {1 turto profilį} other {# turto profilius} }?", + "delete-asset-profiles-text": "Būkite atsargūs, po patvirtinimo visi pasirinkti turto profiliai ir susiję duomenys bus negrįžtamai pašalinti.", + "set-default-asset-profile-title": "Ar tikrai norite nustatyti turto profilį '{{assetProfileName}}' kaip numatytąjį?", + "set-default-asset-profile-text": "Po patvirtinimo šis turto profilis bus pažymėtas kaip numatytasis ir bus naudojamas naujiems turtams, kuriems nenurodytas profilis.", + "no-asset-profiles-found": "Turto profilių nerasta.", + "create-new-asset-profile": "Sukurti naują!", + "create-asset-profile": "Sukurti naują turto profilį", + "import": "Importuoti turto profilį", + "export": "Eksportuoti turto profilį", + "export-failed-error": "Nepavyko eksportuoti turto profilio: {{error}}", + "asset-profile-file": "Turto profilio failas", + "invalid-asset-profile-file-error": "Nepavyko importuoti turto profilio: neteisinga duomenų struktūra." + }, + "device-profile": { + "device-profile": "Įrenginio profilis", + "device-profiles": "Įrenginių profiliai", + "all-device-profiles": "Visi įrenginių profiliai", + "add": "Pridėti įrenginio profilį", + "edit": "Redaguoti įrenginio profilį", + "device-profile-details": "Įrenginio profilio informacija", + "no-device-profiles-text": "Įrenginių profilių nerasta", + "search": "Ieškoti įrenginių profilių", + "selected-device-profiles": "{ count, plural, =1 {1 įrenginio profilis} other {# įrenginių profiliai} } pasirinkta", + "no-device-profiles-matching": "Įrenginio profilio, atitinkančio '{{entity}}', nerasta.", + "device-profile-required": "Įrenginio profilis būtinas.", + "idCopiedMessage": "Įrenginio profilio ID nukopijuotas į iškarpinę", + "set-default": "Nustatyti kaip numatytąjį įrenginio profilį", + "delete": "Pašalinti įrenginio profilį", + "copyId": "Kopijuoti įrenginio profilio ID", + "name-max-length": "Pavadinimas turi būti trumpesnis nei 256 simboliai.", + "name": "Pavadinimas", + "name-required": "Pavadinimas būtinas.", + "type": "Profilio tipas", + "type-required": "Profilio tipas būtinas.", + "type-default": "Numatytasis", + "image": "Įrenginio profilio paveikslėlis", + "transport-type": "Perdavimo tipas", + "transport-type-required": "Perdavimo tipas būtinas.", + "transport-type-default": "Numatytasis", + "transport-type-default-hint": "Palaiko pagrindinius MQTT, HTTP ir CoAP perdavimo tipus.", + "transport-type-mqtt": "MQTT", + "transport-type-mqtt-hint": "Įjungia išplėstinius MQTT perdavimo nustatymus.", + "transport-type-coap": "CoAP", + "transport-type-coap-hint": "Įjungia išplėstinius CoAP perdavimo nustatymus.", + "transport-type-lwm2m": "LWM2M", + "transport-type-lwm2m-hint": "LWM2M perdavimo tipas.", + "transport-type-snmp": "SNMP", + "transport-type-snmp-hint": "Nustatykite SNMP perdavimo konfigūraciją.", + "transport-type-http": "HTTP", + "description": "Aprašymas", + "default": "Numatytasis", + "profile-configuration": "Profilio konfigūracija", + "transport-configuration": "Perdavimo konfigūracija", + "default-rule-chain": "Numatytoji taisyklių grandinė", + "default-edge-rule-chain": "Numatytoji Edge taisyklių grandinė", + "default-edge-rule-chain-hint": "Naudojama Edge aplinkoje apdoroti duomenis, gaunamus iš įrenginių, naudojančių šį profilį.", + "mobile-dashboard": "Mobilusis skydelis", + "mobile-dashboard-hint": "Naudojamas mobiliojoje programėlėje kaip įrenginio informacijos skydelis.", + "select-queue-hint": "Pasirinkite iš išskleidžiamojo sąrašo.", + "delete-device-profile-title": "Ar tikrai norite pašalinti įrenginio profilį '{{deviceProfileName}}'?", + "delete-device-profile-text": "Būkite atsargūs, po patvirtinimo įrenginio profilis ir visi susiję duomenys, įskaitant OTA atnaujinimus, bus negrįžtamai pašalinti.", + "delete-device-profiles-title": "Ar tikrai norite pašalinti { count, plural, =1 {1 įrenginio profilį} other {# įrenginių profilius} }?", + "delete-device-profiles-text": "Būkite atsargūs, po patvirtinimo visi pasirinkti įrenginių profiliai ir susiję duomenys, įskaitant OTA atnaujinimus, bus negrįžtamai pašalinti.", + "set-default-device-profile-title": "Ar tikrai norite nustatyti įrenginio profilį '{{deviceProfileName}}' kaip numatytąjį?", + "set-default-device-profile-text": "Po patvirtinimo šis įrenginio profilis bus pažymėtas kaip numatytasis ir bus naudojamas naujiems įrenginiams, kuriems profilis nenurodytas.", + "no-device-profiles-found": "Įrenginių profilių nerasta.", + "create-new-device-profile": "Sukurti naują!", + "mqtt-device-topic-filters": "MQTT įrenginių temų filtrai", + "mqtt-device-topic-filters-unique": "MQTT įrenginių temų filtrai turi būti unikalūs.", + "mqtt-device-topic-filters-spark-plug": "MQTT Sparkplug B Edge of Network (EoN) mazgas.", + "mqtt-device-topic-filters-spark-plug-hint": "Leidžia prisijungimus iš EoN mazgų, naudojančių Sparkplug B formatą ir temų struktūrą.", + "mqtt-device-topic-filters-spark-plug-attribute-metric-names": "SparkPlug metrikos, saugomos kaip atributai.", + "mqtt-device-topic-filters-spark-plug-attribute-metric-names-hint": "SparkPlug metrikų pavadinimai, kurie bus saugomi kaip įrenginio atributai. Visos kitos metrikos bus saugomos kaip telemetrijos duomenys.", + "mqtt-device-payload-type": "MQTT įrenginio duomenų formatas", + "mqtt-device-payload-type-json": "JSON", + "mqtt-device-payload-type-proto": "Protobuf", + "mqtt-enable-compatibility-with-json-payload-format": "Įjungti suderinamumą su kitais duomenų formatais.", + "mqtt-enable-compatibility-with-json-payload-format-hint": "Įjungus šią parinktį, platforma pagal nutylėjimą naudos Protobuf formatą. Jei analizė nepavyks, bus naudojamas JSON. Naudinga pereinant nuo JSON prie Protobuf atnaujinant programinę įrangą. Rekomenduojama išjungti, kai visi įrenginiai bus atnaujinti.", + "mqtt-use-json-format-for-default-downlink-topics": "Naudoti JSON formatą numatytosioms atsiuntimo temoms", + "mqtt-use-json-format-for-default-downlink-topics-hint": "Kai įjungta, platforma naudos JSON formatą siųsdama atributus ir RPC per temas v1/devices/me/.... Tai neturi įtakos naujoms (v2) temoms.", + "mqtt-send-ack-on-validation-exception": "Siųsti PUBACK, kai PUBLISH žinutės validacija nesėkminga", + "mqtt-send-ack-on-validation-exception-hint": "Pagal numatymą platforma nutraukia MQTT sesiją, kai žinutės validacija nesėkminga. Įjungus šią parinktį, vietoj to bus siunčiamas patvirtinimas.", + "mqtt-protocol-version": "Protokolo versija", + "snmp-add-mapping": "Pridėti SNMP atvaizdavimą", + "snmp-mapping-not-configured": "OID atvaizdavimas į telemetriją/atributus nesukonfigūruotas", + "snmp-timseries-or-attribute-name": "Telemetrijos/atributo pavadinimas atvaizdavimui", + "snmp-timseries-or-attribute-type": "Telemetrijos/atributo tipas atvaizdavimui", + "snmp-method-pdu-type-get-request": "GetRequest", + "snmp-method-pdu-type-get-next-request": "GetNextRequest", + "snmp-oid": "OID", + "transport-device-payload-type-json": "JSON", + "transport-device-payload-type-proto": "Protobuf", + "mqtt-payload-type-required": "Duomenų formatas būtinas.", + "coap-device-type": "CoAP įrenginio tipas", + "coap-device-payload-type": "CoAP įrenginio duomenų formatas", + "coap-device-type-required": "CoAP įrenginio tipas būtinas.", + "coap-device-type-default": "Numatytasis", + "coap-device-type-efento": "Efento NB-IoT", + "support-level-wildcards": "Palaikomi vieno lygmens [+] ir kelių lygių [#] pakaitos simboliai.", + "telemetry-topic-filter": "Telemetrijos temų filtras", + "telemetry-topic-filter-required": "Telemetrijos temų filtras būtinas.", + "attributes-topic-filter": "Atributų publikavimo temų filtras", + "attributes-subscribe-topic-filter": "Atributų prenumeratos temų filtras", + "attributes-topic-filter-required": "Atributų publikavimo temų filtras būtinas.", + "attributes-subscribe-topic-filter-required": "Atributų prenumeratos tema būtina.", + "telemetry-proto-schema": "Telemetrijos Protobuf schema", + "telemetry-proto-schema-required": "Telemetrijos Protobuf schema būtina.", + "attributes-proto-schema": "Atributų Protobuf schema", + "attributes-proto-schema-required": "Atributų Protobuf schema būtina.", + "rpc-response-proto-schema": "RPC atsakymo Protobuf schema", + "rpc-response-proto-schema-required": "RPC atsakymo Protobuf schema būtina.", + "rpc-response-topic-filter": "RPC atsakymo temų filtras", + "rpc-response-topic-filter-required": "RPC atsakymo temų filtras būtinas.", + "rpc-request-proto-schema": "RPC užklausos Protobuf schema", + "rpc-request-proto-schema-required": "RPC užklausos Protobuf schema būtina.", + "rpc-request-proto-schema-hint": "RPC užklausos žinutėje visada turi būti laukeliai: string method = 1; int32 requestId = 2; ir params = 3 (bet kokio tipo).", + "not-valid-pattern-topic-filter": "Netinkamas temų filtro šablonas.", + "not-valid-single-character": "Netinkamas vieno lygmens pakaitos simbolio naudojimas.", + "not-valid-multi-character": "Netinkamas kelių lygių pakaitos simbolio naudojimas.", + "single-level-wildcards-hint": "[+] galima naudoti bet kuriame temų filtro lygyje, pvz. v1/devices/+/telemetry.", + "multi-level-wildcards-hint": "[#] turi būti paskutinis simbolis, pvz. # arba v1/devices/me/#.", + "alarm-rules": "Įspėjimų taisyklės", + "alarm-rules-with-count": "Įspėjimų taisyklės ({{count}})", + "no-alarm-rules": "Įspėjimų taisyklių nesukonfigūruota.", + "add-alarm-rule": "Pridėti įspėjimo taisyklę", + "edit-alarm-rule": "Redaguoti įspėjimo taisyklę", + "alarm-type": "Įspėjimo tipas", + "alarm-type-required": "Įspėjimo tipas būtinas.", + "alarm-type-unique": "Įspėjimo tipas turi būti unikalus šiame profilyje.", + "alarm-type-max-length": "Įspėjimo tipo pavadinimas turi būti trumpesnis nei 256 simboliai.", + "create-alarm-pattern": "Sukurti {{alarmType}} įspėjimą", + "create-alarm-rules": "Sukurti įspėjimo taisykles", + "no-create-alarm-rules": "Sukūrimo sąlygų nėra.", + "add-create-alarm-rule-prompt": "Pridėkite įspėjimo sukūrimo sąlygą", + "clear-alarm-rule": "Išvalyti įspėjimo taisyklę", + "no-clear-alarm-rule": "Nėra išvalymo sąlygų", + "add-create-alarm-rule": "Pridėti sukūrimo sąlygą", + "add-clear-alarm-rule": "Pridėti išvalymo sąlygą", + "select-alarm-severity": "Pasirinkite įspėjimo rimtumą", + "alarm-severity-required": "Įspėjimo rimtumas būtinas.", + "condition-duration": "Sąlygos trukmė", + "condition-duration-value": "Trukmės reikšmė", + "condition-duration-time-unit": "Laiko vienetas", + "condition-duration-value-range": "Trukmės reikšmė turi būti nuo 1 iki 2147483647.", + "condition-duration-value-pattern": "Trukmės reikšmė turi būti sveikasis skaičius.", + "condition-duration-value-required": "Trukmės reikšmė būtina.", + "condition-duration-time-unit-required": "Laiko vienetas būtinas.", + "advanced-settings": "Išplėstiniai nustatymai", + "alarm-rule-additional-info": "Papildoma informacija", + "edit-alarm-rule-additional-info": "Redaguoti papildomą informaciją", + "alarm-rule-additional-info-placeholder": "Pateikite komentarus ar pastabas, kurios bus rodomos įspėjimo informacijos skiltyje „Papildoma informacija“.", + "alarm-rule-additional-info-hint": "Patarimas: naudokite ${keyName} norėdami įtraukti atributų ar telemetrijos reikšmes.", + "alarm-rule-mobile-dashboard": "Mobilusis įspėjimų skydelis", + "alarm-rule-mobile-dashboard-hint": "Naudojamas mobiliojoje programėlėje kaip įspėjimo detalių skydelis.", + "alarm-rule-no-mobile-dashboard": "Skydelis nepasirinktas.", + "propagate-alarm": "Platinti įspėjimą susijusiems subjektams", + "alarm-rule-relation-types-list": "Ryšių tipai, kuriems platinti įspėjimą", + "alarm-rule-relation-types-list-hint": "Jei nenurodyta, įspėjimai bus platinami be filtravimo pagal ryšių tipą.", + "propagate-alarm-to-owner": "Platinti įspėjimą subjekto savininkui (klientui ar nuomininkui)", + "propagate-alarm-to-tenant": "Platinti įspėjimą nuomininkui", + "alarm-rule-condition": "Įspėjimo sąlyga", + "enter-alarm-rule-condition-prompt": "Pridėkite įspėjimo sąlygą", + "edit-alarm-rule-condition": "Redaguoti įspėjimo sąlygą", + "device-provisioning": "Įrenginių paruošimas (provisioning)", + "provision-strategy": "Paruošimo strategija", + "provision-strategy-required": "Paruošimo strategija būtina.", + "provision-strategy-disabled": "Išjungta", + "provision-strategy-created-new": "Leisti kurti naujus įrenginius", + "provision-strategy-check-pre-provisioned": "Tikrinti iš anksto paruoštus įrenginius", + "provision-device-key": "Įrenginio paruošimo raktas", + "provision-device-key-required": "Įrenginio paruošimo raktas būtinas.", + "copy-provision-key": "Kopijuoti paruošimo raktą", + "provision-key-copied-message": "Paruošimo raktas nukopijuotas į iškarpinę.", + "provision-device-secret": "Įrenginio paruošimo slaptas kodas", + "provision-device-secret-required": "Įrenginio paruošimo slaptas kodas būtinas.", + "copy-provision-secret": "Kopijuoti slaptą kodą", + "provision-secret-copied-message": "Slaptas kodas nukopijuotas į iškarpinę.", + "provision-strategy-x509": { + "certificate-chain": "X509 sertifikatų grandinė", + "certificate-chain-hint": "X.509 strategija naudojama įrenginiams paruošti naudojant dvipusį TLS ryšį ir kliento sertifikatus.", + "allow-create-new-devices": "Leisti kurti naujus įrenginius", + "allow-create-new-devices-hint": "Jei pažymėta, nauji įrenginiai bus kuriami, o kliento sertifikatas naudojamas kaip įrenginio įgaliojimai.", + "certificate-value": "Sertifikatas PEM formatu", + "certificate-value-required": "Sertifikatas PEM formatu būtinas.", + "cn-regex-variable": "CN reguliariosios išraiškos kintamasis", + "cn-regex-variable-required": "CN reguliariosios išraiškos kintamasis būtinas.", + "cn-regex-variable-hint": "Naudojamas įrenginio pavadinimui gauti iš X509 sertifikato 'Common Name' lauko." + }, + "condition": "Sąlyga", + "condition-type": "Sąlygos tipas", + "condition-type-simple": "Paprasta", + "condition-type-duration": "Trukmės", + "condition-during": "Per {{during}}", + "condition-during-dynamic": "Per „{{attribute}}“ ({{during}})", + "condition-type-repeating": "Pasikartojanti", + "condition-type-required": "Sąlygos tipas būtinas.", + "condition-repeating-value": "Įvykių skaičius", + "condition-repeating-value-range": "Įvykių skaičius turi būti nuo 1 iki 2147483647.", + "condition-repeating-value-pattern": "Įvykių skaičius turi būti sveikasis skaičius.", + "condition-repeating-value-required": "Įvykių skaičius būtinas.", + "condition-repeat-times": "Kartojasi { count, plural, =1 {1 kartą} other {# kartus} }", + "condition-repeat-times-dynamic": "Kartojasi „{attribute}“ ({ count, plural, =1 {1 kartą} other {# kartus} })", + "schedule-type": "Tvarkaraščio tipas", + "schedule-type-required": "Tvarkaraščio tipas būtinas.", + "schedule": "Tvarkaraštis", + "edit-schedule": "Redaguoti įspėjimo tvarkaraštį", + "schedule-any-time": "Aktyvus visą laiką", + "schedule-specific-time": "Aktyvus tam tikru laiku", + "schedule-custom": "Pasirinktinis", + "schedule-day": { + "monday": "Pirmadienis", + "tuesday": "Antradienis", + "wednesday": "Trečiadienis", + "thursday": "Ketvirtadienis", + "friday": "Penktadienis", + "saturday": "Šeštadienis", + "sunday": "Sekmadienis" + }, + "schedule-days": "Dienos", + "schedule-time": "Laikas", + "schedule-time-from": "Nuo", + "schedule-time-to": "Iki", + "schedule-days-of-week-required": "Reikia pasirinkti bent vieną savaitės dieną.", + "create-device-profile": "Sukurti naują įrenginio profilį", + "import": "Importuoti įrenginio profilį", + "export": "Eksportuoti įrenginio profilį", + "export-failed-error": "Nepavyko eksportuoti įrenginio profilio: {{error}}", + "device-profile-file": "Įrenginio profilio failas", + "invalid-device-profile-file-error": "Nepavyko importuoti įrenginio profilio: neteisinga profilio duomenų struktūra.", + "power-saving-mode": "Energijos taupymo režimas", + "power-saving-mode-type": { + "default": "Naudoti įrenginio profilio energijos taupymo režimą", + "psm": "Power Saving Mode (PSM)", + "drx": "Discontinuous Reception (DRX)", + "edrx": "Extended Discontinuous Reception (eDRX)" + }, + "edrx-cycle": "eDRX ciklas", + "edrx-cycle-required": "eDRX ciklas būtinas.", + "edrx-cycle-pattern": "eDRX ciklas turi būti teigiamas sveikasis skaičius.", + "edrx-cycle-min": "Minimalus eDRX ciklo skaičius – {{ min }} sekundžių.", + "paging-transmission-window": "Puslapiavimo perdavimo langas", + "paging-transmission-window-required": "Puslapiavimo perdavimo langas būtinas.", + "paging-transmission-window-pattern": "Puslapiavimo perdavimo langas turi būti teigiamas sveikasis skaičius.", + "paging-transmission-window-min": "Minimalus puslapiavimo perdavimo langas – {{ min }} sekundžių.", + "psm-activity-timer": "PSM aktyvumo laikmatis", + "psm-activity-timer-required": "PSM aktyvumo laikmatis būtinas.", + "psm-activity-timer-pattern": "PSM aktyvumo laikmatis turi būti teigiamas sveikasis skaičius.", + "psm-activity-timer-min": "Minimalus PSM aktyvumo laikmatis – {{ min }} sekundžių.", + "lwm2m": { + "object-list": "Objektų sąrašas", + "object-list-empty": "Objektai nepasirinkti.", + "no-objects-found": "Objektų nerasta.", + "no-objects-matching": "Objektų, atitinkančių '{{object}}', nerasta.", + "model-tab": "LWM2M modelis", + "add-new-instances": "Pridėti naujus egzempliorius", + "instances-list": "Egzempliorių sąrašas", + "instances-list-required": "Egzempliorių sąrašas būtinas.", + "instance-id-pattern": "Egzemplioriaus ID turi būti teigiamas sveikasis skaičius.", + "instance-id-max": "Didžiausia egzemplioriaus ID reikšmė – {{max}}.", + "instance": "Egzempliorius", + "resource-label": "#ID Išteklius (Resource name)", + "observe-label": "Stebėjimas", + "attribute-label": "Atributas", + "telemetry-label": "Telemetrija", + "edit-observe-select": "Norėdami redaguoti stebėjimą, pasirinkite telemetriją arba atributą", + "edit-attributes-select": "Norėdami redaguoti atributus, pasirinkite telemetriją arba atributą", + "no-attributes-set": "Atributai nenustatyti", + "key-name": "Rakto pavadinimas", + "key-name-required": "Rakto pavadinimas būtinas.", + "attribute-name": "Atributo pavadinimas", + "attribute-name-required": "Atributo pavadinimas būtinas.", + "attribute-value": "Atributo reikšmė", + "attribute-value-required": "Atributo reikšmė būtina.", + "attribute-value-pattern": "Atributo reikšmė turi būti teigiamas sveikasis skaičius.", + "edit-attributes": "Redaguoti atributus: {{ name }}", + "view-attributes": "Peržiūrėti atributus: {{ name }}", + "add-attribute": "Pridėti atributą", + "edit-attribute": "Redaguoti atributą", + "view-attribute": "Peržiūrėti atributą", + "remove-attribute": "Pašalinti atributą", + "delete-server-text": "Būkite atsargūs – po patvirtinimo serverio konfigūracija bus negrįžtamai prarasta.", + "delete-server-title": "Ar tikrai norite pašalinti serverį?", + "mode": "Saugumo konfigūracijos režimas", + "bootstrap-tab": "Bootstrap", + "bootstrap-server-legend": "Bootstrap Server (Trumpasis ID...)", + "lwm2m-server-legend": "LwM2M Server (Trumpasis ID...)", + "server": "Serveris", + "short-id": "Trumpasis serverio ID", + "short-id-tooltip": "Trumpasis serverio ID naudojamas LwM2M serverio egzemplioriaus susiejimui.\nŠis identifikatorius unikalus kiekvienam LwM2M klientui.\nReikšmė privaloma, kai Bootstrap-Server parametras yra 'false'.\nVertės ID:0 ir ID:65535 negali būti naudojamos LwM2M serverio identifikavimui.", + "short-id-tooltip-bootstrap": "Trumpasis serverio ID naudojamas LwM2M serverio egzemplioriaus susiejimui.\nPrivaloma reikšmė, kai Bootstrap-Server parametras yra 'false'.", + "short-id-required": "Trumpasis serverio ID būtinas.", + "short-id-range": "Trumpasis serverio ID turi būti tarp {{ min }} ir {{ max }}.", + "short-id-pattern": "Trumpasis serverio ID turi būti teigiamas sveikasis skaičius.", + "lifetime": "Kliento registracijos trukmė", + "lifetime-required": "Kliento registracijos trukmė būtina.", + "lifetime-pattern": "Kliento registracijos trukmė turi būti teigiamas sveikasis skaičius.", + "default-min-period": "Minimalus laikotarpis tarp dviejų pranešimų (s)", + "default-min-period-tooltip": "Numatytoji vertė, kurią LwM2M klientas turėtų naudoti minimaliam stebėjimo laikotarpiui, jei parametras nenurodytas.", + "default-min-period-required": "Minimalus laikotarpis būtinas.", + "default-min-period-pattern": "Minimalus laikotarpis turi būti teigiamas sveikasis skaičius.", + "notification-storing": "Pranešimų saugojimas, kai įrenginys išjungtas arba neprisijungęs", + "binding": "Susiejimas (Binding)", + "binding-type": { + "u": "U: Klientas pasiekiamas per UDP ryšį bet kuriuo metu.", + "m": "M: Klientas pasiekiamas per MQTT ryšį bet kuriuo metu.", + "h": "H: Klientas pasiekiamas per HTTP ryšį bet kuriuo metu.", + "t": "T: Klientas pasiekiamas per TCP ryšį bet kuriuo metu.", + "s": "S: Klientas pasiekiamas per SMS ryšį bet kuriuo metu.", + "n": "N: Klientas turi siųsti atsakymą naudodamas Non-IP ryšį (palaikoma nuo LWM2M 1.1).", + "uq": "UQ: UDP ryšys eilės režimu (nepalaikoma nuo LWM2M 1.1).", + "uqs": "UQS: aktyvus tiek UDP, tiek SMS ryšys; UDP eilės režimu, SMS standartiniu režimu (nepalaikoma nuo LWM2M 1.1).", + "tq": "TQ: TCP ryšys eilės režimu (nepalaikoma nuo LWM2M 1.1).", + "tqs": "TQS: aktyvus tiek TCP, tiek SMS ryšys; TCP eilės režimu, SMS standartiniu režimu (nepalaikoma nuo LWM2M 1.1).", + "sq": "SQ: SMS ryšys eilės režimu (nepalaikoma nuo LWM2M 1.1)." + }, + "binding-tooltip": "Tai yra sąrašas iš LwM2M serverio objekto „binding“ ištekliaus - /1/x/7.\nNurodo palaikomus ryšio (binding) režimus LwM2M kliente.\nŠi reikšmė TURĖTŲ sutapti su „Supported Binding and Modes“ ištekliaus reikšme įrenginio objekte (/3/0/16).\nNors palaikomi keli transportavimo protokolai, visos sesijos metu galima naudoti tik vieną ryšio būdą.\nPavyzdžiui, kai palaikomi UDP ir SMS, LwM2M klientas ir serveris gali naudoti tik vieną — arba UDP, arba SMS — visos sesijos metu.", + "bootstrap-server": "Bootstrap serveris", + "lwm2m-server": "LwM2M serveris", + "include-bootstrap-server": "Įtraukti Bootstrap serverio atnaujinimus", + "bootstrap-update-title": "Bootstrap serveris jau sukonfigūruotas. Ar tikrai norite pašalinti atnaujinimus?", + "bootstrap-update-text": "Būkite atsargūs — po patvirtinimo Bootstrap serverio konfigūracija bus negrįžtamai prarasta.", + "server-host": "Serverio adresas (Host)", + "server-host-required": "Serverio adresas būtinas.", + "server-port": "Prievadas (Port)", + "server-port-required": "Prievadas būtinas.", + "server-port-pattern": "Prievadas turi būti teigiamas sveikasis skaičius.", + "server-port-range": "Prievadas turi būti tarp 1 ir 65535.", + "server-public-key": "Serverio viešasis raktas", + "server-public-key-required": "Serverio viešasis raktas būtinas.", + "client-hold-off-time": "Kliento atidėjimo laikas (Hold Off Time)", + "client-hold-off-time-required": "Kliento atidėjimo laikas būtinas.", + "client-hold-off-time-pattern": "Kliento atidėjimo laikas turi būti teigiamas sveikasis skaičius.", + "client-hold-off-time-tooltip": "Naudojamas tik su Bootstrap serveriu – nurodo laukimo laiką prieš registraciją.", + "account-after-timeout": "Sąskaita po pasibaigusio laiko (Account after timeout)", + "account-after-timeout-required": "„Account after timeout“ reikšmė būtina.", + "account-after-timeout-pattern": "„Account after timeout“ turi būti teigiamas sveikasis skaičius.", + "account-after-timeout-tooltip": "Bootstrap serverio „Account after timeout“ reikšmė, apibrėžianti veiksmą po nurodyto laiko.", + "server-type": "Serverio tipas", + "add-new-server-title": "Pridėti naują serverio konfigūraciją", + "add-server-config": "Pridėti serverio konfigūraciją", + "add-lwm2m-server-config": "Pridėti LwM2M serverį", + "no-config-servers": "Serverių konfigūracijų nėra", + "others-tab": "Kiti nustatymai", + "ota-update": "OTA atnaujinimas", + "use-object-19-for-ota-update": "Naudoti objektą 19 OTA failo metaduomenims (kontrolinė suma, dydis, versija, pavadinimas)", + "use-object-19-for-ota-update-hint": "Naudokite išteklių ObjectId = 19 OTA atnaujinimams: Firmware → InstanceId = 65534, Software → InstanceId = 65535. Duomenų formatas – JSON, užkoduotas Base64 formatu. JSON faile pateikiama OTA metainformacija: „Checksum“ (SHA256). Papildomi laukai: „Title“ (pavadinimas), „Version“ (versija), „File Name“ (failo pavadinimas), „File Size“ (dydis baitais).", + "client-strategy": "Kliento strategija jungiantis", + "client-strategy-label": "Strategija", + "client-strategy-only-observe": "Tik „Observe“ užklausos klientui po pradinio prisijungimo", + "client-strategy-read-all": "Perskaityti visus išteklius ir siųsti „Observe“ užklausas po registracijos", + "fw-update": "Programinės aparatinės įrangos (Firmware) atnaujinimas", + "fw-update-strategy": "Firmware atnaujinimo strategija", + "fw-update-strategy-data": "Įkelti firmware kaip dvejetainį failą naudojant objektą 19 ir išteklių 0 (Data)", + "fw-update-strategy-package": "Įkelti firmware kaip dvejetainį failą naudojant objektą 5 ir išteklių 0 (Package)", + "fw-update-strategy-package-uri": "Automatiškai sugeneruoti unikalų CoAP URL firmware parsisiuntimui ir naudoti objektą 5 bei išteklių 1 (Package URI)", + "sw-update": "Programinės įrangos (Software) atnaujinimas", + "sw-update-strategy": "Software atnaujinimo strategija", + "sw-update-strategy-package": "Įkelti dvejetainį failą naudojant objektą 9 ir išteklių 2 (Package)", + "sw-update-strategy-package-uri": "Automatiškai sugeneruoti unikalų CoAP URL programos parsisiuntimui ir naudoti objektą 9 bei išteklių 3 (Package URI)", + "fw-update-resource": "Firmware atnaujinimo CoAP išteklius", + "fw-update-resource-required": "Firmware atnaujinimo CoAP išteklius būtinas.", + "sw-update-resource": "Software atnaujinimo CoAP išteklius", + "sw-update-resource-required": "Software atnaujinimo CoAP išteklius būtinas.", + "config-json-tab": "JSON konfigūracijos profilis", + "attributes-name": { + "min-period": "Minimalus periodas", + "max-period": "Maksimalus periodas", + "greater-than": "Didesnis nei", + "less-than": "Mažesnis nei", + "step": "Žingsnis", + "min-evaluation-period": "Minimalus vertinimo periodas", + "max-evaluation-period": "Maksimalus vertinimo periodas" + }, + "default-object-id": "Numatytoji Objekto Versija (Atributas)", + "default-object-id-ver": { + "v1-0": "1.0", + "v1-1": "1.1", + "v1-2": "1.2" + }, + "observe-strategy": { + "observe-strategy": "Stebėjimo strategija", + "single": "Atskiras", + "single-description": "Vienas stebėjimo užklausimas vienam ištekliui (didesnis tikslumas, daugiau tinklo srauto)", + "composite-all": "Bendras (visi ištekliai)", + "composite-all-description": "Visi ištekliai stebimi naudojant vieną bendrą stebėjimo užklausą (efektyviau, bet mažiau lankstu)", + "composite-by-object": "Pagal objektus", + "composite-by-object-description": "Ištekliai grupuojami pagal objektų tipus ir stebimi naudojant atskiras bendras stebėjimo užklausas (subalansuotas metodas)" + } + }, + "snmp": { + "add-communication-config": "Pridėti ryšio konfigūraciją", + "add-mapping": "Pridėti susiejimą", + "authentication-passphrase": "Autentifikacijos slaptažodis", + "authentication-passphrase-required": "Autentifikacijos slaptažodis būtinas.", + "authentication-protocol": "Autentifikacijos protokolas", + "authentication-protocol-required": "Autentifikacijos protokolas būtinas.", + "communication-configs": "Ryšio konfigūracijos", + "community": "Bendruomenės eilutė (Community string)", + "community-required": "Bendruomenės eilutė būtina.", + "context-name": "Konteksto pavadinimas", + "data-key": "Duomenų raktas", + "data-key-required": "Duomenų raktas būtinas.", + "data-type": "Duomenų tipas", + "data-type-required": "Duomenų tipas būtinas.", + "engine-id": "Variklio ID (Engine ID)", + "host": "Serveris / įrenginys (Host)", + "host-required": "Serverio / įrenginio pavadinimas būtinas.", + "oid": "OID (Objekto identifikatorius)", + "oid-pattern": "Neteisingas OID formatas.", + "oid-required": "OID būtinas.", + "please-add-communication-config": "Pridėkite ryšio konfigūraciją.", + "please-add-mapping-config": "Pridėkite susiejimo konfigūraciją.", + "port": "Prievadas (Port)", + "port-format": "Neteisingas prievado formatas.", + "port-required": "Prievadas būtinas.", + "privacy-passphrase": "Privatumo slaptažodis", + "privacy-passphrase-required": "Privatumo slaptažodis būtinas.", + "privacy-protocol": "Privatumo protokolas", + "privacy-protocol-required": "Privatumo protokolas būtinas.", + "protocol-version": "Protokolo versija", + "protocol-version-required": "Protokolo versija būtina.", + "querying-frequency": "Užklausų dažnis, ms", + "querying-frequency-invalid-format": "Užklausų dažnis turi būti teigiamas sveikasis skaičius.", + "querying-frequency-required": "Užklausų dažnis būtinas.", + "retries": "Bandymų skaičius (Retries)", + "retries-invalid-format": "Bandymų skaičius turi būti teigiamas sveikasis skaičius.", + "retries-required": "Bandymų skaičius būtinas.", + "scope": "Apimtis (Scope)", + "scope-required": "Apimtis būtina.", + "security-name": "Saugos pavadinimas", + "security-name-required": "Saugos pavadinimas būtinas.", + "timeout-ms": "Laiko limitas, ms", + "timeout-ms-invalid-format": "Laiko limitas turi būti teigiamas sveikasis skaičius.", + "timeout-ms-required": "Laiko limitas būtinas.", + "user-name": "Vartotojo vardas", + "user-name-required": "Vartotojo vardas būtinas." + } + }, + "dialog": { + "close": "Uždaryti dialogo langą", + "error-message-title": "Klaidos pranešimas:", + "error-details-title": "Informacija apie klaidą" + }, + "direction": { + "column": "Stulpelis", + "row": "Eilutė" + }, + "edge": { + "edge": "Edge įrenginys", + "edge-instances": "Edge instancijos", + "instances": "Instancijos", + "edge-file": "Edge failas", + "name-max-length": "Pavadinimas negali viršyti 256 simbolių.", + "label-max-length": "Etiketė negali viršyti 256 simbolių.", + "type-max-length": "Tipas negali viršyti 256 simbolių.", + "management": "Edge valdymas", + "no-edges-matching": "Edge įrenginių, atitinkančių '{{entity}}', nerasta.", + "add": "Pridėti Edge įrenginį", + "no-edges-text": "Edge įrenginių nerasta.", + "edge-details": "Edge įrenginio informacija", + "add-edge-text": "Pridėti naują Edge įrenginį", + "delete": "Panaikinti Edge įrenginį", + "delete-edge-title": "Ar tikrai norite panaikinti Edge įrenginį '{{edgeName}}'?", + "delete-edge-text": "Po patvirtinimo Edge įrenginys ir visa su juo susijusi informacija bus negrįžtamai panaikinta.", + "delete-edges-title": "Ar tikrai norite panaikinti { count, plural, =1 {1 Edge įrenginį} other {# Edge įrenginius} }?", + "delete-edges-text": "Po patvirtinimo visi pasirinkti Edge įrenginiai ir jų duomenys bus negrįžtamai panaikinti.", + "name": "Pavadinimas", + "name-starts-with": "Edge įrenginio pavadinimas prasideda", + "name-required": "Pavadinimas būtinas.", + "description": "Aprašymas", + "details": "Išsami informacija", + "events": "Įvykiai", + "copy-id": "Kopijuoti Edge ID", + "id-copied-message": "Edge ID nukopijuotas į iškarpinę", + "sync": "Sinchronizuoti Edge", + "edge-required": "Edge būtinas.", + "edge-type": "Edge tipas", + "edge-type-required": "Edge tipas būtinas.", + "event-action": "Įvykio veiksmas", + "entity-id": "Subjekto ID", + "select-edge-type": "Pasirinkite Edge tipą", + "assign-to-customer": "Priskirti klientui", + "assign-to-customer-text": "Pasirinkite klientą, kuriam norite priskirti Edge įrenginį (-ius)", + "assign-edge-to-customer": "Priskirti Edge įrenginį (-ius) klientui", + "assign-edge-to-customer-text": "Pasirinkite Edge įrenginius, kuriuos norite priskirti klientui", + "assignedToCustomer": "Priskirta klientui", + "edge-public": "Edge yra viešas", + "assigned-to-customer": "Priskirta: {{customerTitle}}", + "unassign-from-customer": "Atsieti nuo kliento", + "unassign-edge-title": "Ar tikrai norite atsieti Edge '{{edgeName}}'?", + "unassign-edge-text": "Po patvirtinimo Edge įrenginys bus atsietas ir nepasiekiamas klientui.", + "unassign-edges-title": "Ar tikrai norite atsieti { count, plural, =1 {1 Edge įrenginį} other {# Edge įrenginius} }?", + "unassign-edges-text": "Po patvirtinimo visi pasirinkti Edge įrenginiai bus atsieti nuo kliento.", + "make-public": "Padaryti Edge viešu", + "make-public-edge-title": "Ar tikrai norite Edge '{{edgeName}}' padaryti viešu?", + "make-public-edge-text": "Po patvirtinimo Edge ir visi jo duomenys bus prieinami kitiems vartotojams.", + "make-private": "Padaryti Edge privačiu", + "public": "Viešas", + "make-private-edge-title": "Ar tikrai norite Edge '{{edgeName}}' padaryti privačiu?", + "make-private-edge-text": "Po patvirtinimo Edge ir jo duomenys taps privatūs ir nepasiekiami kitiems vartotojams.", + "import": "Importuoti Edge", + "install-connect-instructions": "Diegimo ir prijungimo instrukcijos", + "install-connect-instructions-edge-created": "Edge sukurtas! Peržiūrėkite diegimo ir prijungimo instrukcijas.", + "loading-edge-instructions": "Įkeliamos Edge instrukcijos...", + "label": "Etiketė", + "load-entity-error": "Nepavyko įkelti duomenų. Subjektas buvo panaikintas.", + "assign-new-edge": "Priskirti naują Edge", + "unassign-from-edge": "Atsieti nuo Edge", + "edge-key": "Edge raktas", + "copy-edge-key": "Kopijuoti Edge raktą", + "edge-key-copied-message": "Edge raktas nukopijuotas į iškarpinę", + "edge-secret": "Edge slaptas raktas", + "copy-edge-secret": "Kopijuoti Edge slaptą raktą", + "edge-secret-copied-message": "Edge slaptas raktas nukopijuotas į iškarpinę", + "manage-assets": "Valdyti turtą (assets)", + "manage-devices": "Valdyti įrenginius", + "manage-entity-views": "Valdyti subjekto rodinius", + "manage-dashboards": "Valdyti skydelius", + "manage-rulechains": "Valdyti taisyklių grandines (rule chains)", + "assets": "Edge turtas", + "devices": "Edge įrenginiai", + "entity-views": "Edge subjekto rodiniai", + "dashboard": "Edge skydelis", + "dashboards": "Edge skydeliai", + "rulechain-templates": "Taisyklių grandinių šablonai", + "edge-rulechain-templates": "Edge taisyklių grandinių šablonai", + "rulechains": "Edge taisyklių grandinės", + "search": "Ieškoti Edge įrenginių", + "selected-edges": "Pasirinkta { count, plural, =1 {1 Edge įrenginys} other {# Edge įrenginiai} }", + "any-edge": "Bet kuris Edge įrenginys", + "no-edge-types-matching": "Edge tipų, atitinkančių '{{entitySubtype}}', nerasta.", + "edge-type-list-empty": "Edge tipai nepasirinkti.", + "edge-types": "Edge tipai", + "enter-edge-type": "Įveskite Edge tipą", + "deployed": "Įdiegtas", + "pending": "Laukia", + "downlinks": "Downlink ryšiai", + "no-downlinks-prompt": "Downlink ryšių nerasta.", + "sync-process-started-successfully": "Sinchronizacija sėkmingai pradėta!", + "missing-related-rule-chains-title": "Edge trūksta susijusių taisyklių grandinių", + "missing-related-rule-chains-text": "Edge priskirtos taisyklių grandinės naudoja mazgus, nukreipiančius į kitų grandinių žinutes, kurios nėra priskirtos šiam Edge.

Trūkstamų grandinių sąrašas:
{{missingRuleChains}}", + "widget-datasource-error": "Šis valdiklis palaiko tik EDGE subjekto duomenų šaltinius", + "upgrade-instructions": "Atnaujinimo instrukcijos.", + "connected": "Prisijungęs", + "disconnected": "Atsijungęs" + }, + "edge-event": { + "type-dashboard": "Skydelis", + "type-asset": "Turtas (Asset)", + "type-device": "Įrenginys", + "type-device-profile": "Įrenginio profilis", + "type-asset-profile": "Turto profilis", + "type-entity-view": "Subjekto rodinys", + "type-alarm": "Signalizacija (Alarm)", + "type-rule-chain": "Taisyklių grandinė (Rule Chain)", + "type-rule-chain-metadata": "Taisyklių grandinės metaduomenys", + "type-edge": "Edge įrenginys", + "type-user": "Vartotojas", + "type-tenant": "Nuomininkas (Tenant)", + "type-tenant-profile": "Nuomininko profilis", + "type-customer": "Klientas", + "type-relation": "Ryšys (Relation)", + "type-widgets-bundle": "Valdiklių paketas (Widgets Bundle)", + "type-widgets-type": "Valdiklio tipas (Widget Type)", + "type-admin-settings": "Administratoriaus nustatymai", + "type-ota-package": "OTA paketas (Over-The-Air)", + "type-queue": "Eilė (Queue)", + "action-type-added": "Pridėta", + "action-type-deleted": "Panaikinta", + "action-type-updated": "Atnaujinta", + "action-type-post-attributes": "Atributai įkelti", + "action-type-attributes-updated": "Atributai atnaujinti", + "action-type-attributes-deleted": "Atributai ištrinti", + "action-type-timeseries-updated": "Telemetrija atnaujinta", + "action-type-credentials-updated": "Įgaliojimai atnaujinti", + "action-type-assigned-to-customer": "Priskirta klientui", + "action-type-unassigned-from-customer": "Atsieta nuo kliento", + "action-type-relation-add-or-update": "Ryšys pridėtas arba atnaujintas", + "action-type-relation-deleted": "Ryšys panaikintas", + "action-type-rpc-call": "RPC iškvietimas", + "action-type-alarm-ack": "Signalizacija patvirtinta", + "action-type-alarm-clear": "Signalizacija išvalyta", + "action-type-alarm-assigned": "Signalizacija priskirta", + "action-type-alarm-unassigned": "Signalizacija atsieta", + "action-type-assigned-to-edge": "Priskirta Edge įrenginiui", + "action-type-unassigned-from-edge": "Atsieta nuo Edge įrenginio", + "action-type-credentials-request": "Įgaliojimų užklausa", + "action-type-entity-merge-request": "Subjektų sujungimo užklausa" + }, + "error": { + "unable-to-connect": "Nepavyksta prisijungti prie serverio! Patikrinkite interneto ryšį.", + "unhandled-error-code": "Neapdorotos klaidos kodas: {{errorCode}}", + "unknown-error": "Nežinoma klaida" + }, + "entity": { + "entity": "Subjektas", + "entities": "Subjektai", + "entities-count": "Subjektų kiekis", + "alarms-count": "Įspėjimų kiekis", + "aliases": "Subjektų pseudonimai", + "aliases-short": "Pseudonimai", + "entity-alias": "Subjekto pseudonimas", + "unable-delete-entity-alias-title": "Subjekto pseudonimo panaikinti nepavyko", + "unable-delete-entity-alias-text": "Subjekto pseudonimas '{{entityAlias}}' negali būti panaikintas, nes jis naudojamas šiuose valdikliuose:
{{widgetsList}}", + "duplicate-alias-error": "Pseudonimas '{{alias}}' dubliuojasi.
Subjektų pseudonimai skydelyje negali kartotis.", + "missing-entity-filter-error": "Trūksta pseudonimo '{{alias}}' filtro.", + "configure-alias": "Konfigūruoti pseudonimą '{{alias}}'", + "alias": "Pseudonimas", + "alias-required": "Subjekto pseudonimas būtinas.", + "remove-alias": "Pašalinti subjekto pseudonimą", + "add-alias": "Pridėti subjekto pseudonimą", + "edit-alias": "Redaguoti subjekto pseudonimą", + "entity-list": "Subjektų sąrašas", + "entity-type": "Subjekto tipas", + "entity-types": "Subjektų tipai", + "entity-type-list": "Subjektų tipų sąrašas", + "any-entity": "Bet kuris subjektas", + "add-entity-type": "Pridėti subjekto tipą", + "enter-entity-type": "Įveskite subjekto tipą", + "no-entities-matching": "Subjektų, atitinkančių '{{entity}}', nėra.", + "no-entities-text": "Subjektų nerasta", + "no-entity-types-matching": "Subjektų tipų, atitinkančių '{{entityType}}', nėra.", + "name-starts-with": "Pavadinimas prasideda", + "help-text": "Naudokite simbolį '%' pagal paieškos poreikį: '%subjekto_pavadinimo_fragmentas%', '%subjekto_pavadinimo_pabaiga', 'subjekto_pavadinimo_pradžia%'.", + "use-entity-name-filter": "Naudoti filtrą", + "entity-list-empty": "Subjektai nepasirinkti.", + "entity-type-list-required": "Bent vienas subjekto tipas turi būti pasirinktas.", + "entity-name-filter-required": "Subjekto pavadinimo filtras būtinas.", + "entity-name-filter-no-entity-matched": "Subjektų, kurių pavadinimas prasideda '{{entity}}', nėra.", + "all-subtypes": "Visi", + "select-entities": "Pasirinkite subjektus", + "no-aliases-found": "Pseudonimų nėra.", + "no-alias-matching": "Pseudonimo '{{alias}}' nėra.", + "create-new-alias": "Sukurti naują!", + "create-new": "Sukurti naują", + "key": "Raktas", + "key-name": "Rakto pavadinimas", + "no-keys-found": "Raktų nėra.", + "no-key-matching": "Rakto '{{key}}' nėra.", + "create-new-key": "Sukurti naują!", + "type": "Tipas", + "type-required": "Subjekto tipas būtinas.", + "type-device": "Įrenginys", + "type-devices": "Įrenginiai", + "list-of-devices": "{ count, plural, =1 {Vienas įrenginys} other {# įrenginių sąrašas} }", + "device-name-starts-with": "Įrenginiai, kurių pavadinimas prasideda '{{prefix}}'", + "type-device-profile": "Įrenginio profilis", + "type-device-profiles": "Įrenginių profiliai", + "clear-selected-profiles": "Išvalyti pasirinktus profilius", + "list-of-device-profiles": "{ count, plural, =1 {Vienas įrenginio profilis} other {# įrenginių profilių sąrašas} }", + "device-profile-name-starts-with": "Įrenginių profiliai, kurių pavadinimai prasideda '{{prefix}}'", + "type-asset-profile": "Turto profilis", + "type-asset-profiles": "Turto profiliai", + "list-of-asset-profiles": "{ count, plural, =1 {Vienas turto profilis} other {# turto profilių sąrašas} }", + "asset-profile-name-starts-with": "Turto profiliai, kurių pavadinimai prasideda '{{prefix}}'", + "type-asset": "Turtas", + "type-assets": "Turtai", + "list-of-assets": "{ count, plural, =1 {Vienas turtas} other {# turto sąrašas} }", + "asset-name-starts-with": "Turtas, kurio pavadinimas prasideda '{{prefix}}'", + "type-entity-view": "Subjekto rodinys", + "type-entity-views": "Subjektų rodiniai", + "list-of-entity-views": "{ count, plural, =1 {Vienas subjekto rodinys} other {# subjektų rodinių sąrašas} }", + "entity-view-name-starts-with": "Subjektų rodiniai, kurių pavadinimai prasideda '{{prefix}}'", + "type-rule": "Taisyklė", + "type-rules": "Taisyklės", + "list-of-rules": "{ count, plural, =1 {Viena taisyklė} other {# taisyklių sąrašas} }", + "rule-name-starts-with": "Taisyklės, kurių pavadinimai prasideda '{{prefix}}'", + "type-plugin": "Papildinys", + "type-plugins": "Papildiniai", + "list-of-plugins": "{ count, plural, =1 {Vienas papildinys} other {# papildinių sąrašas} }", + "plugin-name-starts-with": "Papildiniai, kurių pavadinimai prasideda '{{prefix}}'", + "type-tenant": "Valdytojas", + "type-tenants": "Valdytojai", + "list-of-tenants": "{ count, plural, =1 {Vienas valdytojas} other {# valdytojų sąrašas} }", + "tenant-name-starts-with": "Valdytojai, kurių pavadinimai prasideda '{{prefix}}'", + "type-tenant-profile": "Valdytojo profilis", + "type-tenant-profiles": "Valdytojo profiliai", + "list-of-tenant-profiles": "{ count, plural, =1 {Vienas valdytojo profilis} other {# valdytojo profilių sąrašas} }", + "tenant-profile-name-starts-with": "Valdytojo profiliai, kurių pavadinimai prasideda '{{prefix}}'", + "type-customer": "Klientas", + "type-customers": "Klientai", + "list-of-customers": "{ count, plural, =1 {Vienas klientas} other {# klientų sąrašas} }", + "customer-name-starts-with": "Klientai, kurių pavadinimai prasideda '{{prefix}}'", + "type-user": "Vartotojas", + "type-users": "Vartotojai", + "list-of-users": "{ count, plural, =1 {Vienas vartotojas} other {# vartotojų sąrašas} }", + "user-name-starts-with": "Vartotojai, kurių pavadinimai prasideda '{{prefix}}'", + "type-dashboard": "Skydelis", + "type-dashboards": "Skydeliai", + "list-of-dashboards": "{ count, plural, =1 {Vienas skydelis} other {# skydelių sąrašas} }", + "dashboard-name-starts-with": "Skydeliai, kurių pavadinimai prasideda '{{prefix}}'", + "type-alarm": "Įspėjimas", + "type-alarms": "Įspėjimai", + "list-of-alarms": "{ count, plural, =1 {Vienas įspėjimas} other {# įspėjimų sąrašas} }", + "alarm-name-starts-with": "Įspėjimai, kurių pavadinimai prasideda '{{prefix}}'", + "type-rulechain": "Taisyklių grandinė", + "type-rulechains": "Taisyklių grandinės", + "list-of-rulechains": "{ count, plural, =1 {Viena taisyklių grandinė} other {# taisyklių grandinių sąrašas} }", + "rulechain-name-starts-with": "Taisyklių grandinės, kurių pavadinimai prasideda '{{prefix}}'", + "type-rulenode": "Taisyklės mazgas", + "type-rulenodes": "Taisyklių mazgai", + "list-of-rulenodes": "{ count, plural, =1 {Vienas taisyklės mazgas} other {# taisyklių mazgų sąrašas} }", + "rulenode-name-starts-with": "Taisyklių mazgai, kurių pavadinimai prasideda '{{prefix}}'", + "type-current-customer": "Dabartinis klientas", + "type-current-tenant": "Dabartinis valdytojas", + "type-current-user": "Dabartinis vartotojas", + "type-current-user-owner": "Dabartinio vartotojo savininkas", + "type-calculated-field": "Apskaičiuotas laukas", + "type-calculated-fields": "Apskaičiuoti laukai", + "type-ai-model": "DI modelis", + "type-ai-models": "DI modeliai", + "type-widgets-bundle": "Valdiklių rinkinys", + "type-widgets-bundles": "Valdiklių rinkiniai", + "list-of-widgets-bundles": "{ count, plural, =1 {Vienas valdiklių rinkinys} other {# valdiklių rinkinių sąrašas} }", + "type-widget": "Valdiklis", + "type-widgets": "Valdikliai", + "list-of-widgets": "{ count, plural, =1 {Vienas valdiklis} other {# valdiklių sąrašas} }", + "search": "Subjektų paieška", + "selected-entities": "Pasirinkta { count, plural, =1 {1 subjektas} other {# subjektai} }", + "entity-name": "Subjekto pavadinimas", + "entity-label": "Subjekto etiketė", + "details": "Informacija apie subjektą", + "no-entities-prompt": "Subjektų nėra", + "no-data": "Nėra duomenų atvaizdavimui", + "columns-to-display": "Rodomi stulpeliai", + "type-api-usage-state": "API naudojimo būsena", + "type-edge": "Edge", + "type-edges": "Edge įrenginiai", + "list-of-edges": "{ count, plural, =1 {Vienas Edge} other {# Edge sąrašas} }", + "edge-name-starts-with": "Edge, kurių pavadinimai prasideda '{{prefix}}'", + "version-conflict": { + "message": "Ar norite perrašyti esamą versiją, ar atmesti pakeitimus ir įkelti naujausią versiją?", + "link": "Savo {{entityType}} versiją galite atsisiųsti naudojantis šia", + "overwrite": "Perrašyti versiją", + "discard": "Atmesti pakeitimus" + }, + "type-tb-resource": "Išteklius", + "type-tb-resources": "Ištekliai", + "list-of-tb-resources": "{ count, plural, =1 {Vienas išteklius} other {# išteklių sąrašas} }", + "type-ota-package": "OTA paketas", + "type-ota-packages": "OTA paketai", + "list-of-ota-packages": "{ count, plural, =1 {Vienas OTA paketas} other {# OTA paketų sąrašas} }", + "type-rpc": "RPC", + "type-queue": "Eilė", + "type-queue-stats": "Eilės statistika", + "type-queues-stats": "Eilių statistika", + "type-notification": "Pranešimas", + "type-notification-rule": "Pranešimo taisyklė", + "type-notification-rules": "Pranešimų taisyklės", + "list-of-notification-rules": "{ count, plural, =1 {Viena pranešimo taisyklė} other {# pranešimų taisyklių sąrašas} }", + "type-notification-target": "Pranešimo gavėjas", + "type-notification-targets": "Pranešimų gavėjai", + "list-of-notification-targets": "{ count, plural, =1 {Vienas pranešimo gavėjas} other {# pranešimų gavėjų sąrašas} }", + "type-notification-request": "Pranešimo užklausa", + "type-notification-template": "Pranešimo šablonas", + "type-notification-templates": "Pranešimų šablonai", + "list-of-notification-templates": "{ count, plural, =1 {Vienas pranešimo šablonas} other {# pranešimų šablonų sąrašas} }", + "link": "nuoroda", + "type-oauth2-client": "OAuth 2.0 klientas", + "type-oauth2-clients": "OAuth 2.0 klientai", + "list-of-oauth2-clients": "{ count, plural, =1 {Vienas OAuth 2.0 klientas} other {# OAuth 2.0 klientų sąrašas} }", + "type-domain": "Domenas", + "type-domains": "Domenai", + "list-of-domains": "{ count, plural, =1 {Vienas domenas} other {# domenų sąrašas} }", + "type-mobile-app": "Mobilioji programa", + "type-mobile-apps": "Mobiliosios programos", + "list-of-mobile-apps": "{ count, plural, =1 {Viena mobilioji programa} other {# mobiliųjų programų sąrašas} }", + "type-mobile-app-bundle": "Mobiliųjų programų rinkinys", + "type-mobile-app-bundles": "Mobiliųjų programų rinkiniai", + "list-of-mobile-app-bundles": "{ count, plural, =1 {Vienas mobiliųjų programų rinkinys} other {# mobiliųjų programų rinkinių sąrašas} }" + }, + "entity-field": { + "created-time": "Sukūrimo laikas", + "name": "Pavadinimas", + "type": "Tipas", + "first-name": "Vardas", + "last-name": "Pavardė", + "email": "El. paštas", + "title": "Pavadinimas", + "country": "Šalis", + "state": "Rajonas", + "city": "Miestas", + "address": "Adresas", + "address2": "Adresas 2", + "zip": "Pašto kodas", + "phone": "Telefonas", + "label": "Etiketė", + "queue-name": "Eilės pavadinimas", + "service-id": "Paslaugos ID", + "owner-name": "Savininko vardas", + "owner-type": "Savininko tipas" + }, + "entity-view": { + "entity-view": "Subjektų rodiniai", + "entity-view-required": "Subjeto rodinys būtinas.", + "entity-views": "Subjektų rodiniai", + "management": "Subjektų rodinių valdymas", + "view-entity-views": "Peržiūrėti subjektų rodinius", + "entity-view-alias": "Subjektų rodinio pseudonimas", + "aliases": "Subjektų rodinio pseudonimai", + "no-alias-matching": "'{{alias}}' nerastas.", + "no-aliases-found": "Pseudonimų nėra.", + "no-key-matching": "'{{key}}' nerastas.", + "no-keys-found": "Raktų nėra.", + "create-new-alias": "Sukurti naują!", + "create-new-key": "Sukurti naują!", + "duplicate-alias-error": "'{{alias}}' dubliuojasi.
Įrenginio pseudonimai skydelyje turi būti unikalūs.", + "configure-alias": "Konfigūruoti '{{alias}}' pseudonimą", + "no-entity-views-matching": "Subjektų rodinių, atitinkančių '{{entity}}' nėra.", + "public": "Viešas", + "alias": "Pseudonimas", + "alias-required": "Subjekto rodinio pseudonimas būtinas.", + "remove-alias": "Panaikinti subjekto rodinio pseudonimą", + "add-alias": "Pridėti subjekto rodinio pseudonimą", + "name-starts-with": "Subjekto rodinio pavadinimas prasideda", + "help-text": "Naudokite '%' simbolį pagal tai, kaip norite ieškoti: '%subjekto_rodinio_pavadinimo_fragmentas%', '%subjekto_rodinio_pavadinimo_pabaiga', 'subjekto_rodinio_pavadinimo_pradžia%'.", + "entity-view-list": "Subjektų rodinių sąrašas", + "use-entity-view-name-filter": "Naudoti filtrą", + "entity-view-list-empty": "Subjektai nepasirinkti.", + "entity-view-name-filter-required": "Subjekto rodinio pavadinimo filtras būtinas.", + "entity-view-name-filter-no-entity-view-matched": "Subjektų rodinių, kurių pavadinimai prasideda '{{entityView}}' nėra.", + "add": "Pridėti subjektų rodinį", + "entity-view-public": "Subjektų rodnys yra viešas", + "assign-to-customer": "Priskirti klientui", + "assign-entity-view-to-customer": "Subjektų rodinį (-ius) priskirti klientui", + "assign-entity-view-to-customer-text": "Pasirinkite subjektų rodinius, kuriuos norite priskirti klientui", + "no-entity-views-text": "Subjektų rodinių nėra", + "assign-to-customer-text": "Pasirinkite klientą, kuriam priskirti subjektų rodinį (-ius)", + "entity-view-details": "Informacija apie subjektų rodinį", + "add-entity-view-text": "Pridėti naują subjektų rodinį", + "delete": "Panikinti subjektų rodinį", + "assign-entity-views": "Priskirti subjektų rodinius", + "assign-entity-views-text": "Priskirti { count, plural, =1 {1 subjektų rodinį} other {# subjektų rodinius} } klientui", + "delete-entity-views": "Panaikinti subjektų rodinius", + "make-public": "Subjektų rodinį padaryti viešu", + "make-private": "Subjektų rodinį padaryti privačiu", + "unassign-from-customer": "Atsieti nuo kliento", + "unassign-entity-views": "Atsieti subjektų rodinius", + "unassign-entity-views-action-title": "Atsieti { count, plural, =1 {1 subjektų rodinį} other {# subjektų rodinius} } nuo kliento", + "assign-new-entity-view": "Priskirti naują subjektų rodinį", + "delete-entity-view-title": "Ar tikrai norite panaikinti subjektų rodinį '{{entityViewName}}'?", + "delete-entity-view-text": "Būkite dėmesingi, po patvirtinimo, subjektų rodinys ir visa su juo susijusi informacija bus panaikinta ir jų atkurti nebegalėsite.", + "delete-entity-views-title": "Ar tikrai norite panaikinti { count, plural, =1 {1 subketų rodinį} other {# subjektų rodinius} }?", + "delete-entity-views-action-title": "Panaikinti { count, plural, =1 {1 subjektų rodinį} other {# subjektų rodinius} }", + "delete-entity-views-text": "Būkite dėmesingi, po patvirtinimo, visi pasirinkti subjektų rodiniai ir visa su jais susijusi informacija bus panaikinta ir jų atkurti nebegalėsite.", + "make-public-entity-view-title": "Ar tikrai norite subjektų rodinį '{{entityViewName}}' padaryti viešu?", + "make-public-entity-view-text": "Po patvirtinimo subjektų rodinys ir visa su juo susijusi informacija taps vieša ir matoma kitiems vartotojams.", + "make-private-entity-view-title": "Ar tikrai norite subjektų rodinį '{{entityViewName}}' padaryti privačiu?", + "make-private-entity-view-text": "Po patvirtinimo subjektų rodinys ir visa su juo susijusi informacija taps privati ir kiti vartotojai jų nebematys.", + "unassign-entity-view-title": "Ar tikrai norite atsieti subjektų rodinį '{{entityViewName}}'?", + "unassign-entity-view-text": "Po patvirtinimo subjektų rodinys bus atsietas ir klientas jo nebematys.", + "unassign-entity-view": "Atsieti subjektų rodinį", + "unassign-entity-views-title": "Ar tikrai norite atsieti { count, plural, =1 {1 subjektų rodinį} other {# subjektų rodinius} }?", + "unassign-entity-views-text": "Po patvirtinimo visi pasirinkti subjektų rodiniai bus atsieti ir klientas jų nebematys.", + "entity-view-type": "Subjektų rodinio tipas", + "entity-view-type-required": "Subjektų rodinio tipas būtinas.", + "select-entity-view-type": "Pasirinkite subjektų rodinio tipą", + "enter-entity-view-type": "Įveskite subjektų rodinio tipą", + "any-entity-view": "Bet kuris subjektų tipas", + "no-entity-view-types-matching": "Subjektų rodinių, atitinkančių '{{entitySubtype}}' nėra.", + "entity-view-type-list-empty": "Subjektų tipai nepasirinkti.", + "entity-view-types": "Subjektų rodinio tipai", + "created-time": "Sukūrimo laikas", + "name": "Pavadinimas", + "name-required": "Pavadinimas būtinas.", + "name-max-length": "Pavadinimas negali viršyti 256 simbolių", + "type-max-length": "Rodinio tipas negali viršyti 256 simbolių", + "description": "Aprašymas", + "events": "Įvykiai", + "details": "Informacija", + "copyId": "Kopijuoti subjekto rodinio Id", + "idCopiedMessage": "Subjektų rodinio Id nukopjuotas į iškarpinę", + "assignedToCustomer": "Priskirtas klientui", + "unable-entity-view-device-alias-title": "Subjektų rodinio pseudonimo ištrinti nepavyko", + "unable-entity-view-device-alias-text": "Įrenginio pseudonimas '{{entityViewAlias}}' Negali būti ištrintas, nes jis naudojamas valdikliuose:
{{widgetsList}}", + "select-entity-view": "Pasirinkti subjektų rodinį", + "start-ts": "Pradžios laikas", + "end-ts": "Pabaigos laikas", + "date-limits": "Datos limitas", + "client-attributes": "Kliento atributai", + "shared-attributes": "Bendrinami atributai", + "server-attributes": "Serverio atributai", + "timeseries": "Telemetrija", + "client-attributes-placeholder": "Kliento atributai", + "shared-attributes-placeholder": "Bendrinami atributai", + "server-attributes-placeholder": "Serverio atributai", + "timeseries-placeholder": "Telemetrija", + "target-entity": "Tikslinis subjektas", + "attributes-propagation": "Atributų paplitimas", + "attributes-propagation-hint": "Subjektų rodinys automatikškai kopijuos nurodytus atributus iš tikslinio subjekto kiekvieną kartą, kai išsaugosite ar atnaujinsite šį rodinį. Norint išsaugoti sistemos spartą, tikslinio subjekto atributai neperkeliami į subjektų rodinį kiekvieną kartą kai jie pasikeičia. Tačiau jūs galite įjungti automatinį atributų reikšmių perdavimą, taisyklių grandinėje sukonfigūravę \"kopijuoti į vaizdą\" taisyklę ir \"Pateikti atributus\" bei \"Atributai atnaujinti\" žinutes nukreipę į naują taisyklę.", + "timeseries-data": "Temetrijos duomenys", + "timeseries-data-hint": "Sukonfigūruokite tikslinio objekto telemetrijos duomenų raktus, kurie bus pasiekiami objekto rodinyje. Šios telemetrijos duomenys yra tik skaitomi.", + "search": "Subjektų rodinių paieška", + "selected-entity-views": "Pasirinkta { count, plural, =1 {1 subjektų rodinys} other {# subjektų rodiniai} }", + "assign-entity-view-to-edge": "Priskirti subjekto rodinį (-ius) „Edge“ sistemai", + "assign-entity-view-to-edge-text": "Pasirinkite subjekto rodinius, kuriuos norite priskirti „Edge“ sistemai", + "unassign-entity-view-from-edge-title": "Ar tikrai norite atsieti subjekto rodinį '{{entityViewName}}' nuo „Edge“?", + "unassign-entity-view-from-edge-text": "Po patvirtinimo subjekto rodinys bus atsietas ir nebebus pasiekiamas per „Edge“.", + "unassign-entity-views-from-edge-action-title": "Atsieti { count, plural, =1 {1 subjekto rodinį} other {# subjekto rodinius} } nuo „Edge“", + "unassign-entity-view-from-edge": "Atsieti subjekto rodinį", + "unassign-entity-views-from-edge-title": "Ar tikrai norite atsieti { count, plural, =1 {1 subjekto rodinį} other {# subjekto rodinius} }?", + "unassign-entity-views-from-edge-text": "Po patvirtinimo visi pasirinkti subjekto rodiniai bus atsieti ir nebebus pasiekiami per „Edge“." + }, + "event": { + "event-type": "Įvykio tipas", + "events-filter": "Įvykių filtras", + "clean-events": "Išvalyti įvykius", + "type-error": "Klaida", + "type-lc-event": "Gyvavimo ciklo įvykis", + "type-stats": "Statistika", + "type-debug-rule-node": "Derinimas (Rule Node)", + "type-debug-rule-chain": "Derinimas (Rule Chain)", + "type-debug-calculated-field": "Derinimas (Calculated Field)", + "arguments": "Argumentai", + "result": "Rezultatas", + "no-events-prompt": "Įvykių nėra", + "error": "Klaida", + "alarm": "Įspėjimas", + "event-time": "Įvykio laikas", + "server": "Serveris", + "body": "Turinys", + "method": "Metodas", + "type": "Tipas", + "metadata": "Metaduomenys", + "message": "Pranešimas", + "message-id": "Pranešimo ID", + "copy-message-id": "Kopijuoti pranešimo ID", + "message-type": "Pranešimo tipas", + "data-type": "Duomenų tipas", + "relation-type": "Ryšio tipas", + "data": "Duomenys", + "event": "Įvykis", + "status": "Būsena", + "success": "Sėkmingas", + "failed": "Nepavyko", + "messages-processed": "Apdoroti pranešimai", + "max-messages-processed": "Maks. apdorotų pranešimų", + "min-messages-processed": "Min. apdorotų pranešimų", + "errors-occurred": "Įvyko klaidų", + "max-errors-occurred": "Maks. klaidų", + "min-errors-occurred": "Min. klaidų", + "min-value": "Mažiausia leistina reikšmė yra 0.", + "all-events": "Visi", + "has-error": "Turi klaidą", + "entity-id": "Subjekto ID", + "copy-entity-id": "Kopijuoti subjekto ID", + "entity-type": "Subjekto tipas", + "clear-filter": "Išvalyti filtrą", + "clear-request-title": "Išvalyti visus įvykius", + "clear-request-text": "Ar tikrai norite išvalyti visus įvykius?", + "started": "Pradėta", + "updated": "Atnaujinta", + "stopped": "Sustabdyta" + }, + "extension": { + "extensions": "Plėtiniai", + "selected-extensions": "Pasirinkta { count, plural, =1 {1 plėtinys} other {# plėtiniai} }", + "type": "Tipas", + "key": "Raktas", + "value": "Reikšmė", + "id": "Id", + "extension-id": "Plėtinio ID", + "extension-type": "Plėtinio tipas", + "transformer-json": "JSON *", + "unique-id-required": "Dabartinis plėtinio ID jau egzistuoja.", + "delete": "Pašalinti plėtinį", + "add": "Pridėti plėtinį", + "edit": "Redaguoti plėtinį", + "delete-extension-title": "Ar tikrai norite pašalinti plėtinį '{{extensionId}}'?", + "delete-extension-text": "Būkite atsargūs — po patvirtinimo šis plėtinys ir visi susiję duomenys bus negrįžtamai pašalinti.", + "delete-extensions-title": "Ar tikrai norite pašalinti { count, plural, =1 {1 plėtinį} other {# plėtinius} }?", + "delete-extensions-text": "Būkite atsargūs — po patvirtinimo visi pasirinkti plėtiniai bus pašalinti.", + "converters": "Keitikliai", + "converter-id": "Keitiklio ID", + "configuration": "Konfigūracija", + "converter-configurations": "Keitiklio konfigūracijos", + "token": "Saugos raktas", + "add-converter": "Pridėti keitiklį", + "add-config": "Pridėti keitiklio konfigūraciją", + "device-name-expression": "Įrenginio pavadinimo išraiška", + "device-type-expression": "Įrenginio tipo išraiška", + "custom": "Tinkintas", + "to-double": "Konvertuoti į Double", + "transformer": "Transformatorius", + "json-required": "Reikalingas transformatoriaus JSON.", + "json-parse": "Nepavyko apdoroti transformatoriaus JSON.", + "attributes": "Atributai", + "add-attribute": "Pridėti atributą", + "add-map": "Pridėti susiejimo elementą", + "timeseries": "Telemetrija", + "add-timeseries": "Pridėti telemetriją", + "field-required": "Laukas būtinas.", + "brokers": "Tarpiniai serveriai", + "add-broker": "Pridėti tarpinį serverį", + "host": "Serveris", + "port": "Prievadas", + "port-range": "Prievadas turi būti tarp 1 ir 65535.", + "ssl": "SSL", + "credentials": "Įgaliojimai", + "username": "Vartotojo vardas", + "password": "Slaptažodis", + "retry-interval": "Kartojimo intervalas (ms)", + "anonymous": "Anoniminis", + "basic": "Paprastas (Basic)", + "pem": "PEM", + "ca-cert": "CA sertifikato failas *", + "private-key": "Privataus rakto failas *", + "cert": "Sertifikato failas *", + "no-file": "Failas nepasirinktas.", + "drop-file": "Įmeskite failą arba spustelėkite, kad pasirinktumėte įkėlimui.", + "mapping": "Susiejimas", + "topic-filter": "Temos filtras", + "converter-type": "Keitiklio tipas", + "converter-json": "JSON", + "json-name-expression": "Įrenginio pavadinimo JSON išraiška", + "topic-name-expression": "Įrenginio pavadinimo temos išraiška", + "json-type-expression": "Įrenginio tipo JSON išraiška", + "topic-type-expression": "Įrenginio tipo temos išraiška", + "attribute-key-expression": "Atributo rakto išraiška", + "attr-json-key-expression": "Atributo rakto JSON išraiška", + "attr-topic-key-expression": "Atributo rakto temos išraiška", + "request-id-expression": "Užklausos ID išraiška", + "request-id-json-expression": "Užklausos ID JSON išraiška", + "request-id-topic-expression": "Užklausos ID temos išraiška", + "response-topic-expression": "Atsakymo temos išraiška", + "value-expression": "Reikšmės išraiška", + "topic": "Tema", + "timeout": "Laiko limitas (ms)", + "converter-json-required": "Keitiklio JSON yra būtinas.", + "converter-json-parse": "Nepavyko apdoroti keitiklio JSON.", + "filter-expression": "Filtro išraiška", + "connect-requests": "Prisijungimo užklausos", + "add-connect-request": "Pridėti prisijungimo užklausą", + "disconnect-requests": "Atsijungimo užklausos", + "add-disconnect-request": "Pridėti atsijungimo užklausą", + "attribute-requests": "Atributų užklausos", + "add-attribute-request": "Pridėti atributo užklausą", + "attribute-updates": "Atributų atnaujinimai", + "add-attribute-update": "Pridėti atributo atnaujinimą", + "server-side-rpc": "Serverio pusės RPC", + "add-server-side-rpc-request": "Pridėti serverio pusės RPC užklausą", + "device-name-filter": "Įrenginio pavadinimo filtras", + "attribute-filter": "Atributų filtras", + "method-filter": "Metodo filtras", + "request-topic-expression": "Užklausos temos išraiška", + "response-timeout": "Atsakymo laukimo limitas (ms)", + "topic-expression": "Temos išraiška", + "client-scope": "Kliento sritis", + "add-device": "Pridėti įrenginį", + "opc-server": "Serveriai", + "opc-add-server": "Pridėti serverį", + "opc-add-server-prompt": "Prašome pridėti serverį", + "opc-application-name": "Programos pavadinimas", + "opc-application-uri": "Programos URI", + "opc-scan-period-in-seconds": "Skenavimo periodas (s)", + "opc-security": "Saugumas", + "opc-identity": "Tapatybė", + "opc-keystore": "Raktinė (Keystore)", + "opc-type": "Tipas", + "opc-keystore-type": "Raktinės tipas", + "opc-keystore-location": "Vieta *", + "opc-keystore-password": "Slaptažodis", + "opc-keystore-alias": "Aliasas", + "opc-keystore-key-password": "Rakto slaptažodis", + "opc-device-node-pattern": "Įrenginio mazgo šablonas", + "opc-device-name-pattern": "Įrenginio pavadinimo šablonas", + "modbus-server": "Serveriai / vergai", + "modbus-add-server": "Pridėti serverį / vergą", + "modbus-add-server-prompt": "Prašome pridėti serverį / vergą", + "modbus-transport": "Transportas", + "modbus-tcp-reconnect": "Automatiškai prisijungti iš naujo", + "modbus-rtu-over-tcp": "RTU per TCP", + "modbus-port-name": "Serijinio prievado pavadinimas", + "modbus-encoding": "Kodavimas", + "modbus-parity": "Paritetas", + "modbus-baudrate": "Perdavimo greitis (baud)", + "modbus-databits": "Duomenų bitai", + "modbus-stopbits": "Stop bitai", + "modbus-databits-range": "Duomenų bitai turi būti nuo 7 iki 8.", + "modbus-stopbits-range": "Stop bitai turi būti nuo 1 iki 2.", + "modbus-unit-id": "Vieneto ID", + "modbus-unit-id-range": "Vieneto ID turi būti nuo 1 iki 247.", + "modbus-device-name": "Įrenginio pavadinimas", + "modbus-poll-period": "Užklausos periodas (ms)", + "modbus-attributes-poll-period": "Atributų užklausos periodas (ms)", + "modbus-timeseries-poll-period": "Telemetrijos užklausos periodas (ms)", + "modbus-poll-period-range": "Užklausos periodas turi būti teigiama reikšmė.", + "modbus-tag": "Žyma", + "modbus-function": "Funkcija", + "modbus-register-address": "Registrų adresas", + "modbus-register-address-range": "Registrų adresas turi būti nuo 0 iki 65535.", + "modbus-register-bit-index": "Bito indeksas", + "modbus-register-bit-index-range": "Bito indeksas turi būti nuo 0 iki 15.", + "modbus-register-count": "Registrų skaičius", + "modbus-register-count-range": "Registrų skaičius turi būti teigiama reikšmė.", + "modbus-byte-order": "Baitų tvarka", + "sync": { + "status": "Būsena", + "sync": "Sinchronizuota", + "not-sync": "Nesinchronizuota", + "last-sync-time": "Paskutinio sinchronizavimo laikas", + "not-available": "Nėra duomenų" + }, + "export-extensions-configuration": "Eksportuoti plėtinių konfigūraciją", + "import-extensions-configuration": "Importuoti plėtinių konfigūraciją", + "import-extensions": "Importuoti plėtinius", + "import-extension": "Importuoti plėtinį", + "export-extension": "Eksportuoti plėtinį", + "file": "Plėtinių failas", + "invalid-file-error": "Neteisingas plėtinio failas" + }, + "feature": { + "advanced-features": "Išplėstinės funkcijos" + }, + "filter": { + "add": "Pridėti filtrą", + "edit": "Redaguoti filtrą", + "name": "Filtro pavadinimas", + "name-required": "Filtro pavadinimas būtinas.", + "duplicate-filter": "Toks filtro pavadinimas jau egzistuoja.", + "filters": "Filtrai", + "unable-delete-filter-title": "Nepavyko ištrinti filtro", + "unable-delete-filter-text": "Filtras '{{filter}}' negali būti ištrintas, nes jis naudojamas šiuose valdikliuose:
{{widgetsList}}", + "duplicate-filter-error": "Rastas pasikartojantis filtras '{{filter}}'.
Filtrų pavadinimai skydelyje turi būti unikalūs.", + "missing-key-filters-error": "Trūksta pagrindinio filtro '{{filter}}'.", + "filter": "Filtras", + "editable": "Redaguojamas", + "editable-hint": "Leisti vartotojui pakeisti filtro reikšmę skydelyje.", + "no-filters-found": "Filtrų nerasta.", + "no-filter-text": "Filtras nenurodytas", + "add-filter-prompt": "Pridėkite filtrą", + "no-filter-matching": "Filtras '{{filter}}' nerastas.", + "create-new-filter": "Sukurti naują!", + "create-new": "Sukurti naują", + "filter-required": "Filtras būtinas.", + "operation": { + "operation": "Operacija", + "equal": "lygu", + "not-equal": "nelygu", + "starts-with": "prasideda nuo", + "ends-with": "baigiasi", + "contains": "turi reikšmę", + "not-contains": "neturi reikšmės", + "greater": "didesnis nei", + "less": "mažesnis nei", + "greater-or-equal": "didesnis arba lygus", + "less-or-equal": "mažesnis arba lygus", + "and": "ir", + "or": "arba", + "in": "yra sąraše", + "not-in": "nėra sąraše" + }, + "ignore-case": "Nepaisyti raidžių dydžio", + "value": "Reikšmė", + "remove-filter": "Pašalinti filtrą", + "duplicate-filter-action": "Dubliuoti filtrą", + "preview": "Filtro peržiūra", + "no-filters": "Filtrai nesukonfigūruoti", + "add-filter": "Pridėti filtrą", + "add-complex-filter": "Pridėti sudėtingą filtrą", + "add-complex": "Pridėti sudėtingą", + "complex-filter": "Sudėtingas filtras", + "edit-complex-filter": "Redaguoti sudėtingą filtrą", + "edit-filter-user-params": "Redaguoti filtro naudotojo parametrus", + "filter-user-params": "Filtro naudotojo parametrai", + "user-parameters": "Naudotojo parametrai", + "display-label": "Rodoma etiketė", + "custom-label": "Pasirinktinė etiketė", + "custom-label-hint": "Įjunkite, jei norite nustatyti savo etiketę filtrui. Išjungus, etiketė bus sugeneruota automatiškai.", + "order-priority": "Lauko tvarkos prioritetas", + "key-filter": "Raktinis filtras", + "key-filters": "Raktiniai filtrai", + "key-name": "Rakto pavadinimas", + "key-name-required": "Rakto pavadinimas būtinas.", + "key-type": { + "key-type": "Rakto tipas", + "attribute": "Atributas", + "timeseries": "Telemetrija", + "entity-field": "Subjekto laukas", + "constant": "Konstanta", + "client-attribute": "Kliento atributas", + "server-attribute": "Serverio atributas", + "shared-attribute": "Bendrinamas atributas" + }, + "value-type": { + "value-type": "Reikšmės tipas", + "string": "Tekstas", + "numeric": "Skaitinė", + "boolean": "Loginė (taip/ne)", + "date-time": "Data/laikas" + }, + "value-type-required": "Rakto reikšmės tipas būtinas.", + "key-value-type-change-title": "Ar tikrai norite pakeisti rakto reikšmės tipą?", + "key-value-type-change-message": "Patvirtinus naują reikšmės tipą, visi įvesti rakto filtrai bus pašalinti.", + "no-key-filters": "Rakto filtrai nesukonfigūruoti", + "add-key-filter": "Pridėti rakto filtrą", + "remove-key-filter": "Pašalinti rakto filtrą", + "edit-key-filter": "Redaguoti rakto filtrą", + "date": "Data", + "time": "Laikas", + "current-tenant": "Dabartinis valdytojas", + "current-customer": "Dabartinis klientas", + "current-user": "Dabartinis vartotojas", + "current-device": "Dabartinis įrenginys", + "default-value": "Numatytoji reikšmė", + "default-comma-separated-values": "Numatytosios reikšmės, atskirtos kableliais", + "dynamic-source-type": "Dinaminio šaltinio tipas", + "dynamic-value": "Dinaminė reikšmė", + "no-dynamic-value": "Nėra dinaminės reikšmės", + "source-attribute": "Šaltinio atributas", + "switch-to-dynamic-value": "Perjungti į dinaminę reikšmę", + "switch-to-default-value": "Perjungti į numatytąją reikšmę", + "inherit-owner": "Paveldėti iš savininko", + "source-attribute-not-set": "Jei šaltinio atributas nenustatytas", + "unit": "Vienetas" + }, + "fullscreen": { + "expand": "Rodyti per visą ekraną", + "exit": "Išjungti rodymą per visą ekraną", + "toggle": "Rodyti per visą ekraną", + "fullscreen": "Rodyti per visą ekraną" + }, + "function": { + "function": "Funkcija" + }, + "gateway": { + "gateway-name": "Šliuzo pavadinimas", + "gateway-name-required": "Šliuzo pavadinimas būtinas.", + "gateways": "Šliuzai", + "create-new-gateway": "Sukurti naują šliuzą", + "create-new-gateway-text": "Ar tikrai norite sukurti naują šliuzą pavadinimu: '{{gatewayName}}'?", + "launch-command": "Paleidimo komanda", + "no-gateway-found": "Šliuzų nerasta.", + "no-gateway-matching": "'{{item}}' nerasta." + }, + "grid": { + "delete-item-title": "Ar tikrai norite pašalinti šį elementą?", + "delete-item-text": "Būkite dėmesingi, po patvirtinimo šio elemento ir visos su juo susijusios informacijos atkurti nebegalėsite.", + "delete-items-title": "Ar tikrai norite pašalinti { count, plural, =1 {1 elementą} other {# elementus} }?", + "delete-items-action-title": "Panaikinti { count, plural, =1 {1 elementą} other {# elementus} }", + "delete-items-text": "Būkite dėmesingi, po patvirtinimo visi pasirinkti elementai ir su jais susijusi informacija bus pašalinti ir jų atkurti nebegalėsite.", + "add-item-text": "Pridėti naują elementą", + "no-items-text": "Elementų nėra", + "item-details": "Informacija apie elementą", + "delete-item": "Panaikinti elementą", + "delete-items": "Panaikinti elmentus", + "scroll-to-top": "Slinkti į viršų" + }, + "help": { + "goto-help-page": "Pagalba", + "show-help": "Pagalba" + }, + "home": { + "home": "Pagrindinis", + "profile": "Profilis", + "logout": "Atsijungti", + "menu": "Meniu", + "avatar": "Paveiksliukas", + "open-user-menu": "Atverti vartoto meniu" + }, + "file-input": { + "browse-file": "Pasirinkti failą", + "browse-files": "Pasirinkti failus" + }, + "image": { + "gallery": "Paveikslėlių galerija", + "search": "Ieškoti paveikslėlio", + "selected-images": "{ count, plural, =1 {1 paveikslėlis} other {# paveikslėliai} } pasirinkta", + "created-time": "Sukūrimo laikas", + "name": "Pavadinimas", + "name-required": "Pavadinimas būtinas.", + "resolution": "Raiška", + "size": "Dydis", + "system": "Sistema", + "download-image": "Atsisiųsti paveikslėlį", + "export-image": "Eksportuoti paveikslėlį į JSON", + "import-image": "Importuoti paveikslėlį iš JSON", + "upload-image": "Įkelti paveikslėlį", + "edit-image": "Redaguoti paveikslėlį", + "image-details": "Paveikslėlio informacija", + "no-images": "Paveikslėlių nerasta", + "delete-image": "Pašalinti paveikslėlį", + "delete-image-title": "Ar tikrai norite pašalinti paveikslėlį '{{imageTitle}}'?", + "delete-image-text": "Būkite dėmesingi — po patvirtinimo paveikslėlio atkurti nebus įmanoma.", + "delete-images-title": "Ar tikrai norite pašalinti { count, plural, =1 {1 paveikslėlį} other {# paveikslėlius} }?", + "delete-images-text": "Būkite dėmesingi — po patvirtinimo visi pasirinkti paveikslėliai bus pašalinti, o susiję duomenys taps negrąžinami.", + "list-mode": "Sąrašo rodinys", + "grid-mode": "Tinklelio rodinys", + "image-preview": "Paveikslėlio peržiūra", + "update-image": "Atnaujinti paveikslėlį", + "export-failed-error": "Nepavyko eksportuoti paveikslėlio: {{error}}", + "image-json-file": "Paveikslėlio JSON failas", + "invalid-image-json-file-error": "Nepavyko importuoti paveikslėlio iš JSON: neteisinga JSON duomenų struktūra.", + "image-is-in-use": "Paveikslėlis naudojamas kituose subjektuose", + "images-are-in-use": "Paveikslėliai naudojami kituose subjektuose", + "image-is-in-use-text": "Paveikslėlis '{{title}}' nebuvo ištrintas, nes jis naudojamas šiuose subjektuose:", + "images-are-in-use-text": "Ne visi paveikslėliai buvo ištrinti, nes jie naudojami kituose subjektuose.
Galite peržiūrėti susijusius subjektus spustelėję Nuorodos mygtuką atitinkamoje eilutėje.
Jei vis tiek norite ištrinti šiuos paveikslėlius, pasirinkite juos ir spustelėkite Ištrinti pasirinktus.", + "delete-image-in-use-text": "Jei vis tiek norite ištrinti paveikslėlį, spustelėkite Ištrinti vis tiek.", + "system-entities": "Sistemos subjektai:", + "entities": "Subjektai:", + "references": "Nuorodos", + "include-system-images": "Įtraukti sistemos paveikslėlius", + "clear-image": "Išvalyti paveikslėlį", + "no-image": "Nėra paveikslėlio", + "no-image-selected": "Nepasirinktas paveikslėlis", + "browse-from-gallery": "Pasirinkti iš galerijos", + "set-link": "Nustatyti nuorodą", + "image-link": "Paveikslėlio nuoroda", + "link": "Nuoroda", + "copy-image-link": "Kopijuoti paveikslėlio nuorodą", + "embed-image": "Įterpti paveikslėlį", + "embed-to-html": "Įterpti į HTML", + "embed-to-html-hint": "Ši funkcija leis nuorodą pasiekti neautorizuotiems naudotojams.", + "embed-to-html-text": "Naudodami šį kodo fragmentą galite įterpti paveikslėlį į HTML pagrįstus komponentus.
Tokie komponentai apima HTML kortelių valdiklius, langelių turinio funkcijas ir pan.", + "embed-to-angular-template": "Įterpti į Angular HTML šabloną", + "embed-to-angular-template-text": "Naudodami šį kodo fragmentą galite įterpti paveikslėlį į Angular HTML šabloną, naudojamą komponentams.
Tokie komponentai apima Markdown valdiklį, HTML sekciją valdiklio redaktoriuje, pasirinktus veiksmus ir pan." + }, + "image-input": { + "drop-images-or": "Užvilkite paveikslėlį arba", + "drag-and-drop": "Užvilkite", + "or": "arba", + "browse": "Pasirinkite", + "no-images": "Paveikslėlis nepasirinktas", + "images": "paveikslėliai" + }, + "import": { + "no-file": "Nepasirinktas failas", + "drop-file": "Nuvilkite JSON failą arba spustelėkite, kad pasirinktumėte failą, kurį norite įkelti.", + "drop-json-file-or": "Nuvilkite JSON failą arba", + "drop-file-csv": "Nuvilkite CSV failą arba spustelėkite, kad pasirinktumėte failą, kurį norite įkelti.", + "drop-file-csv-or": "Nuvilkite CSV failą arba", + "column-value": "Reikšmė", + "column-title": "Pavadinimas", + "column-example": "Duomenų pavyzdys", + "column-key": "Atributo/telemetrijos raktas", + "credentials": "Įgaliojimai", + "csv-delimiter": "CSV skyriklis", + "csv-first-line-header": "Pirmoje eilutėje stulpelių pavadinimai", + "csv-update-data": "Atnaujinti artibutą/telemetriją", + "details": "Informacija", + "import-csv-number-columns-error": "Faile turi būti bent du stulpeliai", + "import-csv-invalid-format-error": "Neteisingas failo formatas. Elutė: '{{line}}'", + "column-type": { + "name": "Pavadinimas", + "type": "Tipas", + "label": "Etiketė", + "column-type": "Stulpelio tipas", + "client-attribute": "Kliento atributas", + "shared-attribute": "Bendrinamas atributas", + "server-attribute": "Serverio atributas", + "timeseries": "Telemetrija", + "entity-field": "Subjekto laukas", + "access-token": "Prieigos raktas", + "x509": "X.509", + "mqtt": { + "client-id": "MQTT kliento ID", + "user-name": "MQTT vartotojo vardas", + "password": "MQTT slaptažodis" + }, + "lwm2m": { + "client-endpoint": "LwM2M kliento galinio taško pavadinimas", + "security-config-mode": "LwM2M saugumo konfigūracijos režimas", + "client-identity": "LwM2M kliento identifikatorius", + "client-key": "LwM2M kliento raktas", + "client-cert": "LwM2M kliento viešasis raktas", + "bootstrap-server-security-mode": "LwM2M pradinio serverio (bootstrap) saugumo režimas", + "bootstrap-server-secret-key": "LwM2M pradinio serverio slaptasis raktas", + "bootstrap-server-public-key-id": "LwM2M pradinio serverio viešasis raktas arba ID", + "lwm2m-server-security-mode": "LwM2M serverio saugumo režimas", + "lwm2m-server-secret-key": "LwM2M serverio slaptasis raktas", + "lwm2m-server-public-key-id": "LwM2M serverio viešasis raktas arba ID" + }, + "snmp": { + "host": "SNMP serveris (hostas)", + "port": "SNMP prievadas (portas)", + "version": "SNMP versija (v1, v2c arba v3)", + "community-string": "SNMP bendruomenės eilutė" + }, + "isgateway": "Yra šliuzas", + "activity-time-from-gateway-device": "Aktyvumo laikas iš šliuzo įrenginio", + "description": "Aprašymas", + "routing-key": "Šliuzo raktas", + "secret": "Šliuzo slaptas raktas" + }, + "stepper-text": { + "select-file": "Pasirinkite failą", + "configuration": "Importo konfigūracija", + "column-type": "Pasirinkite stulpelių tipus", + "creat-entities": "Sukurti naujus subjektus" + }, + "message": { + "create-entities": "Sukurti {{count}} nauji subjektai.", + "update-entities": "Atnaujinti {{count}} subjektai.", + "error-entities": "Kuriant {{count}} subjektų įvyko klaidų." + } + }, + "scada": { + "symbols": "SCADA simboliai", + "search": "Ieškoti simbolio", + "selected-symbols": "{ count, plural, =1 {1 simbolis} other {# simboliai} } pasirinkta", + "download-symbol": "Atsisiųsti SCADA simbolį", + "export-symbol": "Eksportuoti SCADA simbolį į JSON", + "import-symbol": "Importuoti SCADA simbolį iš JSON", + "upload-symbol": "Įkelti SCADA simbolį", + "update-symbol": "Atnaujinti SCADA simbolį", + "edit-symbol": "Redaguoti SCADA simbolį", + "symbol-details": "SCADA simbolio informacija", + "mode-svg": "SVG", + "mode-xml": "XML", + "no-symbols": "Simbolių nerasta", + "show-hidden-elements": "Rodyti paslėptus elementus", + "hide-hidden-elements": "Slėpti paslėptus elementus", + "delete-symbol": "Ištrinti SCADA simbolį", + "delete-symbol-title": "Ar tikrai norite ištrinti SCADA simbolį '{{imageTitle}}'?", + "delete-symbol-text": "Būkite atsargūs — po patvirtinimo SCADA simbolis bus negrįžtamai pašalintas.", + "delete-symbols-title": "Ar tikrai norite ištrinti { count, plural, =1 {1 SCADA simbolį} other {# SCADA simbolius} }?", + "delete-symbols-text": "Būkite atsargūs — po patvirtinimo visi pasirinkti SCADA simboliai ir susiję duomenys bus negrįžtamai pašalinti.", + "include-system-symbols": "Įtraukti sistemos simbolius", + "symbol-preview": "Simbolio peržiūra", + "general": "Bendra informacija", + "tags": "Žymos", + "properties": "Savybės", + "title": "Pavadinimas", + "description": "Aprašymas", + "search-tags": "Ieškoti žymų", + "widget-size": "Valdiklio dydis", + "cols": "stulpeliai", + "rows": "eilutės", + "state-render-function": "Būsenos atvaizdavimo funkcija", + "preview": "Peržiūra", + "preview-widget-action-text": "Valdiklio veiksmas '{{type}}' sėkmingai įvykdytas!", + "no-symbol": "Nėra SCADA simbolio", + "no-symbol-selected": "Nepasirinktas SCADA simbolis", + "clear-symbol": "Išvalyti SCADA simbolį", + "browse-symbol-from-gallery": "Pasirinkti SCADA simbolį iš galerijos", + "zoom-in": "Priartinti", + "zoom-out": "Atitolinti", + "create-widget": "Sukurti valdiklį", + "create-widget-from-symbol": "Sukurti valdiklį iš SCADA simbolio", + "hidden": "paslėpta", + "tag": { + "tag": "Žyma", + "on-click-action": "Veiksmas paspaudus", + "no-tags": "Žymos nesukonfigūruotos", + "delete-tag-text": "Ar tikrai norite pašalinti žymą
{{tag}}{{elementType}} elemento?", + "update-tag": "Atnaujinti žymą", + "enter-tag": "Įveskite žymą", + "tag-settings": "Žymos nustatymai", + "remove-tag": "Pašalinti žymą", + "add-tag": "Pridėti žymą" + }, + "behavior": { + "behavior": "Elgsena", + "id": "ID", + "name": "Pavadinimas", + "type": "Tipas", + "no-behaviors": "Elgsenos nesukonfigūruotos", + "add-behavior": "Pridėti elgseną", + "type-action": "Veiksmas", + "type-value": "Reikšmė", + "type-widget-action": "Valdiklio veiksmas", + "behavior-settings": "Elgsenos nustatymai", + "remove-behavior": "Pašalinti elgseną", + "hint": "Patarimas", + "group-title": "Grupės pavadinimas", + "value-type": "Reikšmės tipas", + "default-value": "Numatytoji reikšmė", + "true-label": "Tiesa etiketė", + "false-label": "Netiesa etiketė", + "state-label": "Būsenos etiketė", + "default-payload": "Numatytasis krovinys", + "not-unique-behavior-ids-error": "Elgsenos ID turi būti unikalūs!", + "default-settings": "Numatytieji nustatymai" + }, + "symbol": { + "symbol": "SCADA simbolis", + "fluid-presence": "Skysčio buvimas", + "fluid-presence-hint": "Nurodo, ar vamzdyje yra skysčio.", + "fluid-present": "Skystis yra", + "present": "Yra", + "absent": "Nėra", + "flow-presence": "Srauto buvimas", + "flow-presence-hint": "Nurodo, ar vamzdyje teka skystis.", + "flow-present": "Srautas yra", + "flow-direction": "Srauto kryptis", + "flow-direction-hint": "Nurodo skysčio tekėjimo kryptį.", + "forward": "Pirmyn", + "reverse": "Atgal", + "flow-animation-speed": "Srauto animacijos greitis", + "flow-animation-speed-hint": "Reikšmė, nurodanti animacijos greitį. 1 – normalus greitis, 0 – be animacijos, < 1 – lėtesnė, > 1 – greitesnė animacija.", + "leak": "Nuotėkis", + "leak-hint": "Nurodo, ar yra nuotėkis vamzdyje.", + "leak-present": "Nuotėkis yra", + "fluid-color": "Skysčio spalva", + "pipe-color": "Vamzdžio spalva", + "horizontal-pipe": "Horizontalus vamzdis", + "vertical-pipe": "Vertikalus vamzdis", + "horizontal-fluid-color": "Horizontalaus skysčio spalva", + "vertical-fluid-color": "Vertikalaus skysčio spalva", + "left-pipe": "Kairysis vamzdis", + "right-pipe": "Dešinysis vamzdis", + "top-pipe": "Viršutinis vamzdis", + "bottom-pipe": "Apatinis vamzdis", + "left-fluid-color": "Kairiojo skysčio spalva", + "right-fluid-color": "Dešiniojo skysčio spalva", + "top-fluid-color": "Viršutinio skysčio spalva", + "bottom-fluid-color": "Apatinio skysčio spalva", + "display": "Ekranas", + "display-format": "Ekrano formatas", + "value": "Reikšmė", + "decimals": "Skaitmenys po kablelio", + "units": "Vienetai", + "flow-meter-value-hint": "Reikšmė rodoma srauto matuoklyje", + "value-hint": "Reikšmė, nurodanti dabartinį dydį", + "running": "Veikia", + "running-hint": "Nurodo, ar komponentas veikia.", + "warning-state": "Įspėjimo būsena", + "warning": "Įspėjimas", + "warning-click": "Įspėjimo paspaudimas", + "warning-state-hint": "Nurodo, ar komponentas yra įspėjimo būsenoje.", + "critical-state": "Kritinė būsena", + "critical": "Kritinis", + "critical-click": "Kritinio paspaudimas", + "critical-state-hint": "Nurodo, ar komponentas yra kritinėje būsenoje.", + "critical-state-animation": "Kritinės būsenos animacija", + "critical-state-animation-hint": "Įjungia mirksėjimo animaciją, kai komponentas yra kritinėje būsenoje.", + "warning-critical-state-animation": "Įspėjimo/kritinės būsenos animacija", + "warning-critical-state-animation-hint": "Įjungia mirksėjimo animaciją, kai komponentas yra įspėjimo ar kritinėje būsenoje.", + "animation": "Animacija", + "broken": "Sugedęs", + "broken-hint": "Nurodo, ar komponentas sugedęs.", + "on-display-click": "Paspaudus ekraną", + "on-display-click-hint": "Veiksmas, atliekamas paspaudus ekraną.", + "pipe": "Vamzdis", + "default-border-color": "Numatytoji rėmelio spalva", + "active-border-color": "Aktyvaus rėmelio spalva", + "warning-border-color": "Įspėjimo rėmelio spalva", + "critical-border-color": "Kritinio rėmelio spalva", + "background-color": "Fono spalva", + "rotation-animation-speed": "Sukimosi animacijos greitis", + "rotation-animation-speed-hint": "Reikšmė, nurodanti sukimosi animacijos greitį. 1 – normalus, 0 – be animacijos, < 1 – lėtesnė, > 1 – greitesnė animacija.", + "on-click": "Paspaudus", + "on-click-hint": "Veiksmas, atliekamas paspaudus komponentą.", + "connectors-positions": "Jungčių pozicijos", + "right-connector": "Dešinė jungtis", + "right-top-connector": "Dešinysis viršutinis jungtuvas.", + "right-bottom-connector": "Dešinysis apatinis jungtuvas.", + "left-connector": "Kairė jungtis", + "left-top-connector": "Kairysis viršutinis jungtuvas.", + "left-bottom-connector": "Kairysis apatinis jungtuvas.", + "top-left-connector": "Kairysis viršutinis jungtuvas.", + "top-right-connector": "Dešinysis viršutinis jungtuvas.", + "top-connector": "Viršutinė jungtis", + "bottom-connector": "Apatinė jungtis", + "running-color": "Veikimo spalva", + "stopped-color": "Sustojimo spalva", + "stopped": "Sustojęs", + "warning-color": "Įspėjimo spalva", + "critical-color": "Kritinė spalva", + "opened": "Atidaryta", + "opened-hint": "Nurodo, ar komponentas atidarytas.", + "open": "Atidaryti", + "open-hint": "Veiksmas, atliekamas vartotojui spustelėjus, kad atidarytų komponentą.", + "close": "Uždaryti", + "close-hint": "Veiksmas, atliekamas vartotojui spustelėjus komponento uždarymą.", + "close-state-animation": "Uždarytos būsenos animacija.", + "close-state-animation-hint": "Ar įjungti mirksinčią animaciją, kai komponentas yra uždarytos būsenos.", + "opened-color": "Atidarytos būsenos spalva.", + "closed-color": "Uždarytos būsenos spalva.", + "opened-rotation-angle": "Atidarytos būsenos pasukimo kampas.", + "closed-rotation-angle": "Uždarytos būsenos pasukimo kampas.", + "tank-capacity": "Talpyklos talpa", + "tank-capacity-hint": "Slankiojo kablelio reikšmė, nurodanti bendrą bako talpą.", + "current-volume": "Dabartinis tūris", + "current-volume-hint": "Slankiojo kablelio reikšmė, nurodanti šiuo metu užimtą tūrį.", + "tank-color": "Talpyklos spalva", + "value-box": "Reikšmės langelis.", + "value-text": "Reikšmės tekstas.", + "scale": "Skalė", + "transparent-mode": "Permatomas režimas.", + "major-ticks": "Pagrindiniai žymekliai.", + "intervals": "Intervalai.", + "major-ticks-color": "Pagrindinių žymeklių spalva.", + "normal": "Normalu", + "minor-ticks": "Smulkieji žymekliai.", + "minor-ticks-color": "Smulkiųjų žymeklių spalva.", + "temperature": "Temperatūra", + "temperature-hint": "Slankiojo kablelio reikšmė, nurodanti dabartinę temperatūrą.", + "update-temperature": "Atnaujinti temperatūrą.", + "update-temperature-hint": "Veiksmas, atliekamas vartotojui spustelėjus, kad pakeistų dabartinę temperatūrą.", + "run": "Paleisti", + "run-hint": "Veiksmas, atliekamas vartotojui spustelėjus, kad paleistų komponentą.", + "stop": "Sustabdyti", + "stop-hint": "Veiksmas, atliekamas vartotojui spustelėjus, kad sustabdytų komponentą.", + "temperature-step": "Temperatūros žingsnio padidinimas.", + "heat-pump-color": "Šilumos siurblio spalva.", + "power-button-background": "Maitinimo mygtuko fonas.", + "value-box-background": "Value box background", + "value-units": "Reikšmės vienetai.", + "enable-units-scale": "Įjungti vienetus skalėje.", + "filtration-mode": "Filtravimo režimas.", + "filtration-mode-hint": "Sveikasis skaičius, nurodantis dabartinį filtravimo režimą.", + "filtration-mode-update": "Filtravimo režimo atnaujinimo būsena.", + "filtration-mode-update-hint": "Veiksmas, atliekamas vartotojui spustelėjus, kad pakeistų dabartinį filtravimo režimą.", + "filter-mode": "Filtras.", + "waste-mode": "Atliekos.", + "backwash-mode": "Atbulinis plovimas.", + "recirculate-mode": "Recirkuliacija.", + "rinse-mode": "Skalavimas.", + "closed-mode": "Uždaryta.", + "sand-filter-color": "Smėlio filtro spalva.", + "mode-box-background": "Režimo langelio fonas.", + "border-color": "Kraštinės spalva.", + "label-color": "Etiketės spalva", + "water-leak-hint": "Nurodo, ar yra nutekėjimas.", + "default-color": "Numatytoji spalva.", + "leak-color": "Nutekėjimo spalva.", + "full-value": "Pilna reikšmė.", + "full-value-hint": "Slankiojo kablelio reikšmė, nurodanti pilną reikšmę.", + "label": "Etiketė", + "icon": "Ikona", + "button-color": "Mygtuko spalva.", + "on-label": "„Įjungta“ žymės tekstas.", + "off-label": "„Išjungta“ žymės tekstas.", + "arrow-presence": "Rodyklės buvimas.", + "arrow-presence-hint": "Nurodo, ar jungtyje yra rodyklė.", + "arrow-present": "Rodyklė yra.", + "arrow-direction": "Srauto kryptis.", + "arrow-direction-hint": "Nurodo srauto kryptį.", + "flow-animation": "Srauto buvimas.", + "flow-animation-hint": "Nurodo, ar jungtyje teka skystis.", + "flow": "Srautas.", + "flow-line": "Linija.", + "flow-line-style": "Linijos stilius.", + "flow-style-hint": "Nustatykite brūkšnio ir tarpo reikšmes taip, kad jų suma būtų daloma iš 100 be liekanos, kad animacija būtų idealiai sinchronizuota.", + "flow-dash-cap": "Brūkšnio galas.", + "dash-cap-butt": "Galinė briauna.", + "dash-cap-round": "Apvalus.", + "dash-cap-square": "Kvadratinis.", + "dash": "Brūkšnys.", + "gap": "Tarpas.", + "main-line": "Pagrindinė linija.", + "line": "Linija", + "line-color": "Linijos spalva", + "arrow-color": "Rodyklės spalva.", + "target-value": "Tikslo reikšmė.", + "target-value-hint": "Nurodo tikslo tašką skalėje.", + "min-max-value": "Minimali ir maksimali reikšmė.", + "min-value": "Min.", + "max-value": "Maks.", + "progress-bar": "Eigos juosta.", + "progress-arrow": "Eigos rodyklė.", + "warning-scale-color": "Įspėjimo skalės spalva.", + "critical-scale-color": "Kritinės skalės spalva.", + "scale-color": "Skalės spalva.", + "target": "Tikslas.", + "high-warning-state": "Aukšto įspėjimo būsena.", + "show-high-warning-scale": "Rodyti aukšto įspėjimo skalės reikšmę.", + "high-warning-scale": "Aukšto įspėjimo skalė.", + "high-warning-state-hint": "Slankiojo kablelio reikšmė, nurodanti aukšto įspėjimo diapazoną iki aukštos kritinės arba didžiausios reikšmės.", + "low-warning-state": "Žemo įspėjimo būsena.", + "show-low-warning-scale": "Rodyti žemo įspėjimo skalės reikšmę.", + "low-warning-scale": "Žemo įspėjimo skalė.", + "low-warning-state-hint": "Slankiojo kablelio reikšmė, nurodanti žemo įspėjimo diapazoną iki žemos kritinės arba minimalios reikšmės.", + "high-critical-state": "Aukšta kritinė būsena.", + "show-high-critical-scale": "Rodyti aukštos kritinės skalės reikšmę.", + "high-critical-scale": "Aukšta kritinė skalė.", + "high-critical-state-hint": "Slankiojo kablelio reikšmė, nurodanti aukštą kritinį diapazoną iki didžiausios skalės reikšmės.", + "low-critical-state": "Žemos kritinės būsenos reikšmė.", + "show-low-critical-scale": "Rodyti žemos kritinės būsenos reikšmę.", + "low-critical-scale": "Žema kritinė būsena.", + "low-critical-state-hint": "Slankiojo kablelio reikšmė, nurodanti žemos kritinės reikšmės diapazoną iki minimalios skalės reikšmės.", + "filter-color": "Filtro spalva", + "colors": "Spalvos", + "indicator-colors": "Indikatorių spalvos", + "enabled": "Įjungta", + "disabled": "Išjungta", + "on": "Įjungta", + "off": "Išjungta", + "on-off-state": "Įjungimo/Išjungimo būsena.", + "on-off-state-hint": "Nurodo, ar komponentas yra įjungtos, ar išjungtos būsenos.", + "on-update-state": "Įjungimo atnaujinimo būsena.", + "on-update-state-hint": "Veiksmas, atliekamas vartotojui spustelėjus, kad atnaujintų būseną į „Įjungta“.", + "off-update-state": "Išjungimo atnaujinimo būsena.", + "off-update-state-hint": "Veiksmas, atliekamas vartotojui spustelėjus, kad atnaujintų būseną į „Išjungta“.", + "voltage": "Įtampa", + "input-voltage": "Įėjimo įtampa.", + "input-voltage-hint": "Slankiojo kablelio reikšmė, nurodanti įėjimo įtampos dydį.", + "output-voltage": "Išėjimo įtampa.", + "output-voltage-hint": "Slankiojo kablelio reikšmė, nurodanti išėjimo įtampos dydį.", + "first-phase-voltage": "Pirmosios fazės įtampa.", + "second-phase-voltage": "Antrosios fazės įtampa.", + "third-phase-voltage": "Trečiosios fazės įtampa.", + "phase-voltage-hint": "Slankiojo kablelio reikšmė, nurodanti dabartinės fazės įtampos dydį.", + "voltage-hint": "Slankiojo kablelio reikšmė, nurodanti dabartinę įtampą.", + "current-voltage-color": "Dabartinės įtampos spalva.", + "phase-indicator-color": "Fazės indikatoriaus spalva.", + "measured": "Išmatuota.", + "measured-hint": "Slankiojo kablelio reikšmė, nurodanti energijos suvartojimą kilovatvalandėmis.", + "day-rate": "Dienos tarifas.", + "night-rate": "Naktinis tarifas.", + "off-peak-rate": "Ne piko tarifas.", + "peak-rate": "Piko tarifas.", + "export-rate": "Eksporto tarifas.", + "operating-mode": "Veikimo režimas.", + "bypass-mode": "Apeiti.", + "operating-mode-hint": "Sveikasis skaičius, nurodantis dabartinį veikimo režimą (0 – IŠJUNGTA, 1 – ĮJUNGTA, 2 – APEINIMAS).", + "connected": "Prijungta", + "connected-hint": "Nurodo, ar komponentas yra prijungtos būsenos.", + "disconnected": "Atjungta", + "indicator": "Indikatorius", + "operation-mode": "Veikimo režimas", + "operation-mode-hint": "Nurodo, ar keitiklis veikia tinklo (Mains), ar inverterio (Inverter) režimu.", + "operation-mode-indicators-color": "Veikimo režimo indikatorių spalva.", + "mains-on-mode": "Tinklas įjungtas.", + "inverter-on-mode": "Keitiklis įjungtas.", + "charging-mode": "Įkrovimo režimas", + "charging-mode-hint": "Sveikasis skaičius, nurodantis dabartinį įkrovimo režimą (1 – Greitas įkrovimas, 2 – Sugėrimas, 3 – Palaikomasis įkrovimas).", + "charging-mode-indicators-color": "Įkrovimo režimo indikatorių spalva.", + "inverter-faults": "Gedimai.", + "inverter-fault-indicators-color": "Gedimo indikatorių spalva.", + "overload-fault": "Perkrova", + "overload-fault-hint": "Nurodo, ar keitiklis yra perkrovos būsenoje.", + "low-battery-fault": "Silpna baterija", + "low-battery-fault-hint": "Nurodo, ar akumuliatorius yra per daug išsikrovęs.", + "temperature-fault": "Temperatūra", + "temperature-fault-hint": "Nurodo, ar keitiklyje yra aukšta temperatūra.", + "triangle": "Trikampis.", + "socket": "Lizdas.", + "left-button": "Kairysis mygtukas.", + "right-button": "Dešinysis mygtukas.", + "alarm-colors": "Aliarmo spalvos", + "hook-color": "Kabliuko spalva" + } + }, + "item": { + "selected": "Pasirinkta" + }, + "js-func": { + "no-return-error": "Funkcija privalo grąžinti reikšmę!", + "return-type-mismatch": "Funkcijos grąžinama reikšmė privalo būti '{{type}}' tipo!", + "tidy": "Sutvarkyti", + "mini": "Sumažinti", + "modules": "Moduliai", + "remove-module": "Pašalinti modulį", + "no-modules": "Modulių nesukonfigūruota", + "add-module": "Pridėti modulį", + "module-alias": "Pseudonimas", + "invalid-module-alias-name": "Neteisingas pseudonimo pavadinimas", + "module-resource": "JS modulio šaltinis", + "not-unique-module-aliases-error": "Modulių pseudonimai turi būti unikalūs!", + "show-module-info": "Rodyti modulio informaciją", + "show-module-source-code": "Rodyti modulio pirminį kodą", + "module-members": "Modulio nariai", + "module-no-members": "Modulis neturi eksportuotų narių", + "module-load-error": "Modulio įkėlimo klaida", + "source-code": "Pirminis kodas", + "source-code-load-error": "Pirminio kodo įkėlimo klaida", + "no-js-module-text": "JS modulių nerasta", + "no-js-module-matching": "Nerasta JS modulių, atitinkančių '{{module}}'." + }, + "key-val": { + "key": "Raktas", + "value": "Reikšmė", + "remove-entry": "Panaiknti įrašą", + "add-entry": "Pridėti įrašą", + "no-data": "Įrašų nėra" + }, + "layout": { + "layout": "Maketas", + "layouts": "Maketai", + "manage": "Valdyti maketus", + "settings": "Maketų nustatymai", + "color": "Spalva", + "main": "Pagrindinis", + "right": "Į dešinę", + "left": "Į kairę", + "select": "Pasirinkti maketą", + "percentage-width": "Procentinis plotis (%)", + "fixed-width": "Fiksuotas plotis (px)", + "left-width": "Kairysis stulpelis (%)", + "right-width": "Dešinysis stulpelis (%)", + "pick-fixed-side": "Fiksuota pusė: ", + "layout-fixed-width": "Fiksuotas plotis (px)", + "value-min-error": "Reikšmė turi būti dedesnė nei {{min}}{{unit}}", + "value-max-error": "Reikšmė turi būti mažesnė nei {{max}}{{unit}}", + "layout-fixed-width-required": "Fiksuotas plotis būtinas", + "right-width-percentage-required": "Dešinės pusės procentas būtinas", + "left-width-percentage-required": "kairės pusės procentas būtinas", + "divider": "Daliklis", + "right-side": "Dešinės pusės maketas", + "left-side": "Kairės pusės maketas", + "add-new-breakpoint": "Pridėti naują pertraukos tašką", + "breakpoint": "Pertraukos taškas", + "breakpoints": "Pertraukos taškai", + "copy-from": "Kopijuoti iš", + "size": "Dydis", + "delete-breakpoint-title": "Ar tikrai norite ištrinti pertraukos tašką '{{name}}'?", + "delete-breakpoint-text": "Atkreipkite dėmesį, kad po patvirtinimo pertraukos taškas bus negrįžtamai pašalintas, o nustatymai bus atkurti pagal numatytąjį pertraukos tašką." + }, + "legend": { + "direction": "Elementų išdėstymo kryptis", + "position": "Legendos pozicija", + "show-values": "Rodyti reikšmes", + "min-option": "Min", + "max-option": "Max", + "average-option": "Vidurkis", + "total-option": "Viso", + "latest-option": "Naujausi", + "sort-legend": "Legendoje rodyti duomenų raktus", + "show-max": "Rodyti didžiausią reišmę", + "show-min": "Rodyti mažiausią reikšmę", + "show-avg": "Rodyti vidutinę reikšmę", + "show-total": "Rodyti suminę rekšmę", + "show-latest": "Rodyti naujausią reikšmę", + "settings": "Legendos nustatymai", + "min": "Min", + "max": "Max", + "avg": "Vidurkis", + "total": "Viso", + "latest": "Naujausia", + "Min": "Min", + "Max": "Max", + "Avg": "Vid.", + "Total": "Viso", + "Latest": "Vėliausia", + "comparison-time-ago": { + "previousInterval": "(ankstesnis intervalas)", + "customInterval": "(pasirinktinis intervalas)", + "days": "(prieš dieną)", + "weeks": "(prieš savaitę)", + "months": "(prieš mėnesį)", + "years": "(prieš metus)" + }, + "column-title": "Stulpelio pavadinimas", + "label": "Etiketė", + "value": "Reikšmė" + }, + "login": { + "login": "Prisijungti", + "request-password-reset": "Prašyti slaptažodžio atstatymo", + "reset-password": "Atstatyti slaptažodį", + "create-password": "Sukurti slaptažodį", + "two-factor-authentication": "Dviejų veiksnių autentifikavimas", + "passwords-mismatch-error": "Įvesti slaptažodžiai turi sutapti!", + "password-again": "Pakartokite slaptažodį", + "sign-in": "Prisijungti", + "username": "Vartotojo vardas (el. paštas)", + "remember-me": "Prisiminti mane", + "forgot-password": "Pamiršote slaptažodį?", + "password-reset": "Slaptažodis atstatytas", + "expired-password-reset-message": "Jūsų slaptažodžio galiojimas baigėsi! Nustatykite naują slaptažodį.", + "new-password": "Naujas slaptažodis", + "new-password-again": "Pakartokite naują slaptažodį", + "password-link-sent-message": "Atstatymo nuoroda išsiųsta", + "email": "El. paštas", + "invalid-email-format": "Neteisingas el. pašto formatas.", + "login-with": "Prisijungti kaip {{name}}", + "or": "arba", + "error": "Prisijungimo klaida", + "verify-your-identity": "Patvirtinkite savo tapatybę", + "select-way-to-verify": "Pasirinkite tapatybės patvirtinimo būdą", + "resend-code": "Siųsti kodą iš naujo", + "resend-code-wait": "Galima siųsti iš naujo po { time, plural, =1 {1 sekundės} other {# sekundžių} }", + "try-another-way": "Bandykite kitu būdu", + "totp-auth-description": "Įveskite saugos kodą iš autentifikavimo programėlės.", + "totp-auth-placeholder": "Kodas", + "sms-auth-description": "Saugos kodas išsiųstas į jūsų telefoną adresu {{contact}}.", + "sms-auth-placeholder": "SMS kodas", + "email-auth-description": "Saugos kodas išsiųstas į jūsų el. paštą adresu {{contact}}.", + "email-auth-placeholder": "El. pašto kodas", + "backup-code-auth-description": "Įveskite vieną iš atsarginių kodų.", + "backup-code-auth-placeholder": "Atsarginis kodas", + "activation-link-expired": "Aktyvavimo nuorodos galiojimas baigėsi", + "activation-link-expired-message": "Profilio aktyvavimo nuoroda nebegalioja. Galite grįžti į prisijungimo puslapį ir gauti naują el. laišką.", + "reset-password-link-expired": "Slaptažodžio atstatymo nuoroda nebegalioja", + "reset-password-link-expired-message": "Slaptažodžio atstatymo nuoroda nebegalioja. Galite grįžti į prisijungimo puslapį ir gauti naują el. laišką." + }, + "mobile": { + "add-application": "Pridėti programėlę", + "app-id": "Programėlės svetainės asociacijos ID", + "app-id-required": "Programėlės svetainės asociacijos ID yra būtinas", + "app-id-pattern": "Neteisingas programėlės svetainės asociacijos ID formatas", + "app-store-link": "App Store nuoroda", + "app-store-link-required": "App Store nuoroda yra būtina", + "application-details": "Programėlės informacija", + "application-package": "Programėlės paketas", + "application-secret": "Programėlės slaptas raktas", + "application-secret-required": "Programėlės slaptas raktas yra būtinas", + "application": "Programėlė", + "applications": "Programėlės", + "copy-app-id": "Kopijuoti programėlės ID", + "copy-app-store-link": "Kopijuoti App Store nuorodą", + "copy-application-package": "Kopijuoti programėlės paketą", + "copy-application-secret": "Kopijuoti programėlės slaptą raktą", + "copy-google-play-link": "Kopijuoti Google Play nuorodą", + "copy-sha256-certificate-fingerprints": "Kopijuoti SHA256 sertifikato atspaudus", + "delete-application": "Ištrinti programėlę", + "delete-application-button-text": "Suprantu pasekmes, ištrinti programėlę", + "delete-application-text": "Šio veiksmo atšaukti nebus galima. Tai visam laikui ištrins jūsų programėlę.
Jei nenorite jos ištrinti visam laikui, galite laikinai ją sustabdyti.
Norėdami vis tiek ištrinti programėlę, įveskite patvirtinimo frazę \"{{phrase}}\".", + "delete-application-title-short": "Ar tikrai norite ištrinti programėlę '{{name}}'?", + "delete-application-text-short": "Būkite atsargūs – po patvirtinimo programėlė ir visi susiję duomenys bus negrįžtamai pašalinti.", + "delete-application-phrase": "ištrinti programėlę", + "delete-applications-bundle-text": "Būkite atsargūs – po patvirtinimo mobilusis paketas ir visi susiję duomenys bus negrįžtamai pašalinti.", + "delete-applications-bundle-title": "Ar tikrai norite ištrinti mobilųjį paketą '{{bundleName}}'?", + "generate-application-secret": "Generuoti programėlės slaptą raktą", + "google-play-link": "Google Play nuoroda", + "google-play-link-required": "Google Play nuoroda yra būtina", + "latest-version": "Naujausia versija", + "min-version": "Minimali versija", + "invalid-version-pattern": "Neteisingas versijos formatas. Naudokite formatą: major.minor.patch (pvz., 1.0.0).", + "mobile-center": "Mobilusis centras", + "mobile-package": "Programėlės paketas", + "mobile-package-max-length": "Programėlės pavadinimas turi būti trumpesnis nei 256 simboliai", + "mobile-package-required": "Programėlės paketas yra būtinas", + "mobile-package-pattern": "Neteisingas programėlės paketo formatas", + "mobile-package-title": "Programėlės pavadinimas", + "mobile-package-title-max-length": "Programėlės pavadinimas turi būti trumpesnis nei 256 simboliai", + "no-application": "Programėlių nerasta", + "no-bundles": "Paketų nerasta", + "platform-type": "Platformos tipas", + "search-application": "Ieškoti programėlių", + "search-bundles": "Ieškoti paketų", + "set": "Nustatyti", + "sha256-certificate-fingerprints": "SHA256 sertifikato atspaudai", + "sha256-certificate-fingerprints-required": "SHA256 sertifikato atspaudai yra būtini", + "sha256-certificate-fingerprints-pattern": "Neteisingas SHA256 sertifikato atspaudo formatas", + "show-hidden-pages": "Rodyti paslėptus puslapius", + "status": "Būsena", + "status-type": { + "deprecated": "Nebenaudojama", + "draft": "Juodraštis", + "published": "Paskelbta", + "suspended": "Sustabdyta" + }, + "store-information": "Parduotuvės informacija", + "version-information": "Versijos informacija", + "min-version-release-notes": "Minimalios versijos išleidimo pastabos", + "latest-version-release-notes": "Naujausios versijos išleidimo pastabos", + "bundle": "Paketas", + "bundles": "Paketai", + "add-bundle": "Pridėti paketą", + "title": "Pavadinimas", + "title-required": "Pavadinimas būtinas", + "title-cannot-contain-only-spaces": "Pavadinimas negali būti tik iš tarpų", + "title-max-length": "Pavadinimas turi būti trumpesnis nei 256 simboliai", + "oauth-clients": "OAuth 2.0 klientai", + "android-app": "Android programa", + "android-application": "Android aplikacija", + "ios-app": "iOS programa", + "ios-application": "iOS aplikacija", + "invalid-store-link": "Neteisinga parduotuvės nuoroda", + "enable-oauth": "Įjungti OAuth 2.0", + "enable-self-registration": "Įjungti savarankišką registraciją", + "edit-bundle": "Redaguoti paketą", + "description": "Aprašymas", + "basic-settings": "Pagrindiniai nustatymai", + "no-application-matching": "Nerasta programų, atitinkančių '{{entity}}'.", + "no-bundle-matching": "Nerasta paketų, atitinkančių '{{entity}}'.", + "application-required": "Programa būtina.", + "bundle-required": "Paketas būtinas.", + "no-application-text": "Programų nerasta", + "no-bundle-text": "Paketų nerasta", + "layout": "Išdėstymas", + "pages": "Puslapiai", + "hide-all-pages": "Slėpti visus puslapius", + "reset-to-default-pages": "Atstatyti numatytuosius puslapius", + "add-specific-page": "Pridėti konkretų puslapį", + "visible": "Matomas", + "hidden": "Paslėptas", + "reset-to-page-default": "Atstatyti puslapį į numatytąją būseną", + "mobile-599": "Mobilus (maks. 599px)", + "tablet-959": "Planšetė (maks. 959px)", + "max-element-number": "Maksimalus elementų skaičius", + "page-name": "Puslapio pavadinimas", + "page-name-required": "Puslapio pavadinimas būtinas.", + "page-name-cannot-contain-only-spaces": "Puslapio pavadinimas negali būti tik iš tarpų.", + "page-name-max-length": "Puslapio pavadinimas turi būti trumpesnis nei 256 simboliai", + "page-type": "Puslapio tipas", + "pages-types": { + "dashboard": "Valdymo skydas", + "web-view": "Žiniatinklio peržiūra", + "custom": "Pasirinktinis" + }, + "url": "URL", + "invalid-url-format": "Neteisingas URL formatas", + "path": "Kelias", + "invalid-path-format": "Neteisingas kelio formatas", + "custom-page": "Pasirinktinis puslapis", + "edit-page": "Redaguoti puslapį", + "edit-custom-page": "Redaguoti pasirinktą puslapį", + "delete-page": "Ištrinti puslapį", + "qr-code-widget": "QR kodo valdiklis", + "type-here": "Įveskite čia", + "configuration-dialog": "Konfigūracijos dialogas", + "configuration-app": "Konfigūracijos programa", + "configuration-step": { + "prepare-environment-title": "Paruošti kūrimo aplinką", + "prepare-environment-text": "Flutter ThingsBoard mobiliajai programai reikalingas Flutter SDK. Vadovaukitės instrukcijomis, kad nustatytumėte Flutter SDK.", + "get-source-code-title": "Gauti programos išeities kodą", + "get-source-code-text": "Galite gauti Flutter ThingsBoard mobiliosios programos išeities kodą, klonuodami jį iš GitHub saugyklos:", + "configure-app-settings-title": "Sukonfigūruoti programos nustatymus", + "configure-app-settings-text": "Atsisiųskite konfigūracijos failą ir įdėkite jį į projekto, kurį klonavote ankstesniame žingsnyje, šakninį katalogą.", + "download-file": "Atsisiųsti failą", + "run-app-title": "Paleisti programą", + "run-app-text": "Paleiskite programą kaip aprašyta jūsų IDE.\nJei naudojate terminalą, paleiskite programą naudodami šią komandą:", + "more-information": "Išsami informacija pateikta mūsų „Pradžios vadove“.", + "getting-started": "Pradžios vadovas" + } + }, + "notification": { + "action-button": "Veiksmo mygtukas", + "action-type": "Veiksmo tipas", + "active": "Aktyvus", + "add-notification-recipients-group": "Pridėti pranešimų gavėjų grupę", + "add-notification-template": "Pridėti pranešimo šabloną", + "add-recipient": "Pridėti gavėją", + "add-recipients": "Pridėti gavėjus", + "add-rule": "Pridėti taisyklę", + "add-stage": "Pridėti etapą", + "add-template": "Pridėti šabloną", + "after": "Po", + "alarm-assignment-trigger-settings": "Aliarmo priskyrimo trigerio nustatymai", + "alarm-comment-trigger-settings": "Aliarmo komentaro trigerio nustatymai", + "alarm-trigger-settings": "Aliarmo trigerio nustatymai", + "all": "Visi", + "api-feature-hint": "Jei laukas tuščias, trigeris bus taikomas visoms API funkcijoms", + "api-usage-trigger-settings": "API naudojimo trigerio nustatymai", + "new-platform-version-trigger-settings": "Naujos platformos versijos trigerio nustatymai", + "rate-limits-trigger-settings": "Viršytų užklausų ribų trigerio nustatymai", + "task-processing-failure-trigger-settings": "Užduočių apdorojimo klaidų trigerio nustatymai", + "resources-shortage-trigger-settings": "Išteklių trūkumo trigerio nustatymai", + "at-least-one-should-be-selected": "Reikia pasirinkti bent vieną", + "basic-settings": "Pagrindiniai nustatymai", + "button-text": "Mygtuko tekstas", + "button-text-required": "Mygtuko tekstas yra privalomas", + "button-text-max-length": "Mygtuko tekstas turi būti trumpesnis nei {{ length }} simbolių", + "compose": "Sukurti", + "conversation": "Pokalbis", + "conversation-required": "Pokalbis yra privalomas", + "copy-notification-template": "Kopijuoti pranešimo šabloną", + "copy-rule": "Kopijuoti taisyklę", + "copy-template": "Kopijuoti šabloną", + "create-new": "Sukurti naują", + "created": "Sukurta", + "customize-messages": "Tinkinti pranešimus", + "cpu-threshold": "CPU riba", + "delete-notification-text": "Būkite atsargūs – po patvirtinimo pranešimas taps neatstatomas.", + "delete-notification-title": "Ar tikrai norite ištrinti pranešimą?", + "delete-notifications-text": "Būkite atsargūs – po patvirtinimo pranešimai taps neatstatomi.", + "delete-notifications-title": "Ar tikrai norite ištrinti { count, plural, =1 {1 pranešimą} other {# pranešimus} }?", + "delete-recipient-text": "Būkite atsargūs – po patvirtinimo gavėjas taps neatstatomas.", + "delete-recipient-title": "Ar tikrai norite ištrinti gavėją '{{recipientName}}'?", + "delete-recipients-text": "Būkite atsargūs – po patvirtinimo gavėjai taps neatstatomi.", + "delete-recipients-title": "Ar tikrai norite ištrinti { count, plural, =1 {1 gavėją} other {# gavėjus} }?", + "delete-request-text": "Būkite atsargūs – po patvirtinimo užklausa taps neatstatoma.", + "delete-request-title": "Ar tikrai norite ištrinti užklausą?", + "delete-requests-text": "Būkite atsargūs – po patvirtinimo užklausos taps neatstatomos.", + "delete-requests-title": "Ar tikrai norite ištrinti { count, plural, =1 {1 užklausą} other {# užklausas} }?", + "delete-rule-text": "Būkite atsargūs – po patvirtinimo taisyklė taps neatstatoma.", + "delete-rule-title": "Ar tikrai norite ištrinti taisyklę '{{ruleName}}'?", + "delete-rules-text": "Būkite atsargūs – po patvirtinimo taisyklės taps neatstatomos.", + "delete-rules-title": "Ar tikrai norite ištrinti { count, plural, =1 {1 taisyklę} other {# taisykles} }?", + "delete-template-text": "Būkite atsargūs – po patvirtinimo šablonas taps neatstatomas.", + "delete-template-title": "Ar tikrai norite ištrinti šabloną '{{templateName}}'?", + "delete-templates-text": "Būkite atsargūs – po patvirtinimo šablonai taps neatstatomi.", + "delete-templates-title": "Ar tikrai norite ištrinti { count, plural, =1 {1 šabloną} other {# šablonus} }?", + "deleted": "Ištrinta", + "delivery-method": { + "delivery-method": "Pristatymo būdas", + "email": "El. paštas", + "email-preview": "El. pašto pranešimo peržiūra", + "slack": "Slack", + "slack-preview": "Slack pranešimo peržiūra", + "microsoft-teams": "Microsoft Teams", + "microsoft-teams-preview": "Microsoft Teams pranešimo peržiūra", + "sms": "SMS", + "sms-preview": "SMS pranešimo peržiūra", + "web": "Žiniatinklis", + "web-preview": "Žiniatinklio pranešimo peržiūra", + "mobile-app": "Mobilioji programėlė", + "mobile-app-preview": "Mobiliosios programėlės pranešimo peržiūra" + }, + "delivery-method-not-configure-click": "Pristatymo būdas nesukonfigūruotas. Spustelėkite, kad nustatytumėte.", + "delivery-method-not-configure-contact": "Pristatymo būdas nesukonfigūruotas. Susisiekite su sistemos administratoriumi.", + "delivery-methods": "Pristatymo būdai", + "description": "Aprašymas", + "device-activity-trigger-settings": "Įrenginio aktyvumo trigerio nustatymai", + "device-list-rule-hint": "Jei laukas tuščias, trigeris bus taikomas visiems įrenginiams", + "device-profiles-list-rule-hint": "Jei laukas tuščias, trigeris bus taikomas visiems įrenginių profiliams", + "disabled": "Išjungta", + "edge-trigger-settings": "Edge trigerio nustatymai", + "edge-list-rule-hint": "Jei laukas tuščias, trigeris bus taikomas visoms Edge instancijoms", + "edit-notification-recipients-group": "Redaguoti pranešimų gavėjų grupę", + "edit-notification-template": "Redaguoti pranešimo šabloną", + "edit-rule": "Redaguoti taisyklę", + "edit-template": "Redaguoti šabloną", + "enabled": "Įjungta", + "entities-limit-trigger-settings": "Objektų limito trigerio nustatymai", + "entity-action-trigger-settings": "Objekto veiksmo trigerio nustatymai", + "entity-type": "Objekto tipas", + "escalation-chain": "Eskalacijos grandinė", + "failed-send": "Siuntimo klaidos", + "fails": "{ count, plural, =1 {1 klaida} other {# klaidos} }", + "filter": "Filtras", + "first-recipient": "Pirmasis gavėjas", + "inactive": "Neaktyvus", + "inbox": "Gautieji", + "notification-inbox": "Pranešimai / Gautieji", + "input-field-support-templatization": "Įvesties laukas palaiko šablonizaciją.", + "input-fields-support-templatization": "Įvesties laukai palaiko šablonizaciją.", + "link": "Nuoroda", + "link-required": "Nuoroda yra privaloma", + "link-max-length": "Nuoroda turi būti ne ilgesnė kaip {{ length }} simbolių", + "link-type": { + "dashboard": "Atidaryti valdymo skydą", + "link": "Atidaryti URL nuorodą" + }, + "loading-notifications": "Įkeliami pranešimai...", + "management": "Pranešimų valdymas", + "mark-all-as-read": "Pažymėti visus kaip skaitytus", + "mark-as-read": "Pažymėti kaip skaitytą", + "message": "Žinutė", + "message-required": "Žinutė yra privaloma", + "message-max-length": "Žinutė turi būti ne ilgesnė kaip {{ length }} simbolių", + "name": "Pavadinimas", + "name-required": "Pavadinimas yra privalomas", + "new-notification": "Naujas pranešimas", + "no-inbox-notification": "Pranešimų nerasta", + "no-notification-request": "Pranešimo užklausų nėra", + "no-notification-templates": "Pranešimų šablonų nerasta", + "no-notifications-yet": "Kol kas pranešimų nėra", + "no-recipients-notification": "Nėra pranešimo gavėjų", + "no-recipients-matching": "Gavėjų atitinkančių '{{entity}}' nerasta.", + "no-recipients-text": "Gavėjų nerasta", + "no-rule": "Nėra sukonfigūruotos taisyklės", + "no-rules-notification": "Nėra pranešimų taisyklių", + "no-severity-found": "Prioritetų nerasta", + "no-severity-matching": "Prioritetas '{{severity}}' nerastas.", + "no-template-matching": "Resurso, atitinkančio '{{template}}', nerasta.", + "create-new-template": "Sukurti naują!", + "not-found-slack-recipient": "Slack gavėjas nerastas", + "notification": "Pranešimas", + "notification-center": "Pranešimų centras", + "notification-tap-action": "Veiksmas paspaudus pranešimą", + "notification-tap-action-hint": "Jei neįjungta, bus naudojamas numatytasis aliarmo prietaisų skydas", + "notify": "Pranešti", + "notify-again": "Pranešti dar kartą", + "notify-alarm-action": { + "acknowledged": "Aliarmas patvirtintas", + "assigned": "Aliarmas priskirtas", + "cleared": "Aliarmas išvalytas", + "created": "Aliarmas sukurtas", + "severity-changed": "Aliarmo prioritetas pakeistas", + "unassigned": "Aliarmas nepriskirtas" + }, + "notify-on": "Pranešti apie", + "notify-on-comment-update": "Pranešti apie komentaro atnaujinimą", + "notify-on-required": "„Pranešti apie“ yra privalomas", + "notify-on-unassign": "Pranešti apie nepriskyrimą", + "notify-only-user-comments": "Pranešti tik apie vartotojų komentarus", + "only-rule-chain-lifecycle-failures": "Tik taisyklių grandinės ciklo klaidos", + "only-rule-node-lifecycle-failures": "Tik taisyklių mazgų ciklo klaidos", + "platform-users": "Platformos vartotojai", + "ram-threshold": "RAM riba", + "rate-limits": "Naudojimo apribojimai", + "rate-limits-hint": "Jei laukas tuščias, trigeris bus taikomas visiems naudojimo apribojimams", + "recipient": "Gavėjas", + "recipient-group": "Gavėjų grupė", + "recipient-type": { + "affected-tenant-administrators": "Paveikti nuomininko administratoriai", + "affected-user": "Paveiktas vartotojas", + "all-users": "Visi vartotojai", + "customer-users": "Klientų vartotojai", + "system-administrators": "Sistemos administratoriai", + "tenant-administrators": "Nuomininko administratoriai", + "user-filters": "Vartotojų filtras", + "user-list": "Vartotojų sąrašas", + "users-entity-owner": "Subjekto savininko vartotojai" + }, + "recipients": "Gavėjai", + "notification-recipient": "Pranešimo gavėjas", + "notification-recipient-required": "Pranešimo gavėjas yra privalomas.", + "notification-recipients": "Pranešimai / Gavėjai", + "recipients-count": "{ count, plural, =1 {1 gavėjas} other {# gavėjai} }", + "recipients-required": "Gavėjai yra privalomi", + "refresh-allow-delivery-method": "Atnaujinti leidžiamą pristatymo metodą", + "request-search": "Užklausos paieška", + "request-status": { + "processing": "Vykdoma", + "scheduled": "Suplanuota", + "sent": "Išsiųsta" + }, + "review": "Peržiūra", + "rule": "Taisyklė", + "rule-chain-list-rule-hint": "Jei laukas tuščias, trigeris bus taikomas visoms taisyklių grandinėms", + "rule-engine-events-trigger-settings": "Taisyklių variklio įvykių trigerio nustatymai", + "rule-engine-filter": "Taisyklių variklio filtras", + "rule-name": "Taisyklės pavadinimas", + "rule-name-required": "Pavadinimas yra privalomas", + "rule-disable": "Išjungti pranešimų taisyklę", + "rule-enable": "Įjungti pranešimų taisyklę", + "rule-node-filter": "Taisyklių mazgo filtras", + "rules": "Taisyklės", + "notification-rules": "Pranešimai / Taisyklės", + "scheduler-later": "Suplanuoti vėlesniam laikui", + "search-notification": "Ieškoti pranešimų", + "search-recipients": "Ieškoti gavėjų", + "search-rules": "Ieškoti taisyklių", + "search-templates": "Ieškoti šablonų", + "see-documentation": "Peržiūrėti dokumentaciją", + "selected-notifications": "{ count, plural, =1 {1 pranešimas} other {# pranešimai} } pasirinkta", + "selected-recipients": "{ count, plural, =1 {1 gavėjas} other {# gavėjai} } pasirinkta", + "selected-requests": "{ count, plural, =1 {1 užklausa} other {# užklausos} } pasirinkta", + "selected-rules": "{ count, plural, =1 {1 taisyklė} other {# taisyklės} } pasirinkta", + "selected-template": "{ count, plural, =1 {1 šablonas} other {# šablonai} } pasirinkta", + "send-notification": "Siųsti pranešimą", + "sent": "Išsiųsta", + "setup": "Nustatymai", + "notification-sent": "Pranešimai / Išsiųsti", + "set-entity-from-notification": "Nustatyti objektą iš pranešimo į valdymo suvestinę", + "slack-chanel-type": "Slack kanalo tipas", + "slack-chanel-types": { + "direct": "Tiesioginė žinutė", + "private-channel": "Privatus kanalas", + "public-channel": "Viešas kanalas" + }, + "start-from-scratch": "Pradėti nuo pradžių", + "status": "Būsena", + "stop-escalation-alarm-status-become": "Sustabdyti eskalaciją, kai aliarmo būsena tampa:", + "storage-threshold": "Saugyklos riba", + "subject": "Tema", + "subject-required": "Tema yra privaloma", + "subject-max-length": "Temos ilgis turi būti ne didesnis nei {{ length }} simbolių", + "template": "Šablonas", + "template-name": "Šablono pavadinimas", + "template-required": "Šablonas yra privalomas", + "template-type": { + "alarm": "Aliarmas", + "alarm-assignment": "Aliarmo priskyrimas", + "alarm-comment": "Aliarmo komentaras", + "api-usage-limit": "API naudojimo limitas", + "device-activity": "Įrenginio aktyvumas", + "entities-limit": "Objektų limitas", + "entity-action": "Objekto veiksmas", + "general": "Bendras", + "rule-engine-lifecycle-event": "Taisyklių variklio gyvavimo ciklo įvykis", + "rule-node": "Taisyklių mazgas", + "new-platform-version": "Nauja platformos versija", + "rate-limits": "Viršytos normos ribos", + "edge-communication-failure": "Edge ryšio klaida", + "edge-connection": "Edge prisijungimas", + "task-processing-failure": "Užduoties apdorojimo klaida", + "resources-shortage": "Išteklių trūkumas" + }, + "templates": "Šablonai", + "notification-templates": "Pranešimai / Šablonai", + "tenant-profiles-list-rule-hint": "Jei laukas tuščias, trigeris bus taikomas visiems nuomininkų profiliams", + "tenants-list-rule-hint": "Jei laukas tuščias, trigeris bus taikomas visiems nuomininkams", + "threshold": "Riba", + "theme-color": "Temos spalva", + "time": "Laikas", + "track-rule-node-events": "Stebėti taisyklių mazgų įvykius", + "trigger": { + "alarm": "Aliarmas", + "alarm-assignment": "Aliarmo priskyrimas", + "alarm-comment": "Aliarmo komentaras", + "api-usage-limit": "API naudojimo limitas", + "device-activity": "Įrenginio aktyvumas", + "entities-limit": "Objektų limitas", + "entity-action": "Objekto veiksmas", + "rule-engine-lifecycle-event": "Taisyklių variklio gyvavimo ciklo įvykis", + "new-platform-version": "Nauja platformos versija", + "rate-limits": "Viršytos normos ribos", + "edge-connection": "Edge prisijungimas", + "edge-communication-failure": "Edge ryšio klaida", + "task-processing-failure": "Užduoties apdorojimo klaida", + "resources-shortage": "Išteklių trūkumas", + "trigger": "Trigeris", + "trigger-required": "Trigeris yra privalomas" + }, + "type": "Tipas", + "unread": "Neskaitytas", + "updated": "Atnaujintas", + "use-deprecated-webhook-connectors": "Naudoti pasenusius Webhook jungiklius", + "use-old-api": "Naudoti seną API", + "use-template": "Naudoti šabloną", + "view-all": "Peržiūrėti visus", + "warning": "Įspėjimas", + "webhook-url": "Webhook URL", + "webhook-url-required": "Webhook URL yra privalomas", + "workflow-url": "Darbo eigos URL", + "workflow-url-required": "Darbo eigos URL yra privalomas", + "channel-name": "Kanalas", + "channel-name-required": "Kanalas yra privalomas", + "settings": { + "notification-settings": "Pranešimų nustatymai", + "reset-all": "Atstatyti visus nustatymus", + "reset-all-title": "Ar tikrai norite atstatyti formą?", + "reset-all-text": "Po patvirtinimo nustatymų forma bus atstatyta į numatytąsias reikšmes ir išsaugota.", + "type": "Tipas", + "enable-all": "Įjungti visus", + "disable-all": "Išjungti visus", + "delivery-not-configured": "Pristatymo metodas nesukonfigūruotas" + } + }, + "ota-update": { + "add": "Pridėti paketą", + "assign-firmware": "Priskirta programinė aparatinė įranga", + "assign-firmware-required": "Priskirta programinė aparatinė įranga yra privaloma", + "assign-software": "Priskirta programinė įranga", + "assign-software-required": "Priskirta programinė įranga yra privaloma", + "auto-generate-checksum": "Automatiškai generuoti kontrolinę sumą", + "checksum": "Kontrolinė suma", + "checksum-hint": "Jei kontrolinė suma tuščia, ji bus sugeneruota automatiškai", + "checksum-algorithm": "Kontrolinės sumos algoritmas", + "checksum-copied-message": "Paketo kontrolinė suma nukopijuota į iškarpinę", + "change-firmware": "Programinės aparatinės įrangos pakeitimas gali sukelti { count, plural, =1 {1 įrenginio} other {# įrenginių} } atnaujinimą.", + "change-software": "Programinės įrangos pakeitimas gali sukelti { count, plural, =1 {1 įrenginio} other {# įrenginių} } atnaujinimą.", + "change-ota-setting-title": "Ar tikrai norite pakeisti OTA nustatymus?", + "chose-compatible-device-profile": "Įkeltas paketas bus pasiekiamas tik įrenginiams su pasirinktu profiliu.", + "chose-firmware-distributed-device": "Pasirinkite programinę aparatinę įrangą, kuri bus paskirstyta įrenginiams", + "chose-software-distributed-device": "Pasirinkite programinę įrangą, kuri bus paskirstyta įrenginiams", + "content-type": "Turinio tipas", + "copy-checksum": "Kopijuoti kontrolinę sumą", + "copy-direct-url": "Kopijuoti tiesioginį URL", + "copyId": "Kopijuoti paketo ID", + "copied": "Nukopijuota!", + "delete": "Ištrinti paketą", + "delete-ota-update-text": "Būkite atsargūs – po patvirtinimo OTA atnaujinimas bus negrįžtamai pašalintas.", + "delete-ota-update-title": "Ar tikrai norite ištrinti OTA atnaujinimą '{{title}}'?", + "delete-ota-updates-text": "Būkite atsargūs – po patvirtinimo visi pasirinkti OTA atnaujinimai bus pašalinti.", + "delete-ota-updates-title": "Ar tikrai norite ištrinti { count, plural, =1 {1 OTA atnaujinimą} other {# OTA atnaujinimus} }?", + "description": "Aprašymas", + "direct-url": "Tiesioginis URL", + "direct-url-copied-message": "Paketo tiesioginis URL nukopijuotas į iškarpinę", + "direct-url-required": "Tiesioginis URL yra privalomas", + "download": "Atsisiųsti paketą", + "drop-file": "Įmeskite paketo failą arba spustelėkite norėdami įkelti.", + "drop-package-file-or": "Nutempkite paketo failą arba", + "file-name": "Failo pavadinimas", + "file-size": "Failo dydis", + "file-size-bytes": "Failo dydis baitais", + "idCopiedMessage": "Paketo ID nukopijuotas į iškarpinę", + "no-firmware-matching": "Nerasta jokių suderinamų programinės aparatinės įrangos OTA atnaujinimo paketų, atitinkančių '{{entity}}'.", + "no-firmware-text": "Nėra suderinamų programinės aparatinės įrangos OTA atnaujinimo paketų.", + "no-packages-text": "Paketų nerasta", + "no-software-matching": "Nerasta jokių suderinamų programinės įrangos OTA atnaujinimo paketų, atitinkančių '{{entity}}'.", + "no-software-text": "Nėra suderinamų programinės įrangos OTA atnaujinimo paketų.", + "ota-update": "OTA atnaujinimas", + "ota-update-details": "OTA atnaujinimo informacija", + "ota-updates": "OTA atnaujinimai", + "package-file": "Paketo failas", + "package-type": "Paketo tipas", + "packages-repository": "Paketų saugykla", + "search": "Ieškoti paketų", + "selected-package": "{ count, plural, =1 {1 paketas} other {# paketai} } pasirinkta", + "title": "Pavadinimas", + "title-required": "Pavadinimas yra privalomas.", + "title-max-length": "Pavadinimas turi būti trumpesnis nei 256 simboliai", + "types": { + "firmware": "Programinė aparatinė įranga", + "software": "Programinė įranga" + }, + "upload-binary-file": "Įkelti dvejetainį failą", + "use-external-url": "Naudoti išorinį URL", + "version": "Versija", + "version-required": "Versija yra privaloma.", + "version-tag": "Versijos žyma", + "version-tag-hint": "Pasirinktinė žyma turi atitikti paketo versiją, kurią praneša jūsų įrenginys.", + "version-max-length": "Versija turi būti trumpesnė nei 256 simboliai", + "warning-after-save-no-edit": "Įkėlus paketą, pavadinimo, versijos, įrenginio profilio ir paketo tipo keisti nebegalėsite." + }, + "position": { + "top": "Viršus", + "bottom": "Apačia", + "left": "Kairioji pusė", + "right": "Dešinioji pusė" + }, + "profile": { + "profile": "Profilis", + "last-login-time": "Paskutinio prisijungimo laikas", + "change-password": "Pakeisti slaptažodį", + "current-password": "Dabartinis slaptažodis", + "copy-jwt-token": "Kopijuoti JWT raktą", + "jwt-token": "JWT raktas", + "token-valid-till": "Raktas galioja iki", + "tokenCopiedSuccessMessage": "JWT raktas nukopijuotas į iškarpinę", + "tokenCopiedWarnMessage": "JWT raktas nebegalioja! Atnaujinkite puslapį." + }, + "profiles": { + "profiles": "Profiliai" + }, + "security": { + "security": "Saugumas", + "general-settings": "Bendrieji saugumo nustatymai", + "access-token": "Prieigos raktas", + "access-token-required": "Prieigos raktas yra privalomas", + "clientId": "Kliento ID", + "clientId-required": "Kliento ID yra privalomas", + "username": "Vartotojo vardas", + "username-required": "Vartotojo vardas yra privalomas", + "ca-cert": "CA sertifikatas", + "2fa": { + "2fa": "Dviejų veiksnių autentifikavimas", + "2fa-description": "Dviejų veiksnių autentifikavimas apsaugo jūsų paskyrą nuo neteisėtos prieigos. Prisijungdami turėsite įvesti saugos kodą.", + "authenticate-with": "Galite autentifikuotis naudodami:", + "disable-2fa-provider-text": "Išjungus {{name}}, jūsų paskyra taps mažiau saugi.", + "disable-2fa-provider-title": "Ar tikrai norite išjungti {{name}}?", + "get-new-code": "Gauti naują kodą", + "main-2fa-method": "Naudoti kaip pagrindinį dviejų veiksnių autentifikavimo būdą", + "dialog": { + "activation-step-description-email": "Kitą kartą prisijungiant bus prašoma įvesti saugos kodą, kuris bus išsiųstas jūsų el. pašto adresu.", + "activation-step-description-sms": "Kitą kartą prisijungiant bus prašoma įvesti saugos kodą, kuris bus išsiųstas jūsų telefono numeriu.", + "activation-step-description-totp": "Kitą kartą prisijungiant turėsite pateikti dviejų veiksnių autentifikavimo kodą.", + "activation-step-label": "Aktyvacija", + "backup-code-description": "Atsispausdinkite atsarginius kodus, kad turėtumėte juos po ranka, kai reikės prisijungti prie paskyros. Kiekvienas atsarginis kodas gali būti naudojamas tik vieną kartą.", + "backup-code-warn": "Palikus šį puslapį, šie kodai nebebus rodomi. Išsaugokite juos saugiai.", + "download-txt": "Atsisiųsti (txt)", + "email-step-description": "Įveskite el. pašto adresą, kuris bus naudojamas kaip autentifikatorius.", + "email-step-label": "El. paštas", + "enable-email-title": "Įjungti el. pašto autentifikatorių", + "enable-sms-title": "Įjungti SMS autentifikatorių", + "enable-totp-title": "Įjungti autentifikavimo programėlę", + "enter-verification-code": "Įveskite 6 skaitmenų kodą", + "get-backup-code-title": "Gauti atsarginį kodą", + "next": "Toliau", + "scan-qr-code": "Nuskaitykite šį QR kodą naudodami autentifikavimo programėlę", + "send-code": "Siųsti kodą", + "sms-step-description": "Įveskite telefono numerį, kuris bus naudojamas kaip autentifikatorius.", + "sms-step-label": "Telefono numeris", + "success": "Sėkmingai!", + "totp-step-description-install": "Galite įdiegti tokias programėles kaip Google Authenticator, Authy arba Duo.", + "totp-step-description-open": "Atidarykite autentifikavimo programėlę savo telefone.", + "totp-step-label": "Gauti programėlę", + "verification-code": "6 skaitmenų kodas", + "verification-code-invalid": "Neteisingas kodo formatas", + "verification-code-incorrect": "Neteisingas patvirtinimo kodas", + "verification-code-many-request": "Per daug bandymų patikrinti kodą", + "verification-step-description": "Įveskite 6 skaitmenų kodą, kurį ką tik išsiuntėme adresu {{address}}", + "verification-step-label": "Patvirtinimas" + }, + "provider": { "email": "El. paštas", - "no-address": "Adresas nenurodytas", - "state-max-length": "Rajono pavadinimas negali viršyti 256 simbolių", - "phone-max-length": "Telefono numeris negali viršyti 256 simbolių", - "city-max-length": "Miesto pavadinimas negali viršyti 256 simbolių" - }, - "common": { - "username": "Vartoto vardas", - "password": "Slaptažodis", - "enter-username": "Įveskite vartotojo vardą", - "enter-password": "Įveskite slaptažodį", - "enter-search": "Įveskite paieškos kriterijus", - "created-time": "Sukūrimo laikas", - "loading": "Įkeliama...", - "proceed": "Tęsti", - "open-details-page": "Informacija", - "not-found": "Nerasta", - "documentation": "Dokumentacija" - }, - "converter": { - "converter": "Data converter", - "converters": "Data converters", - "select-converter": "Select data converter", - "no-converters-matching": "No data converters matching '{{entity}}' were found.", - "no-converters-found": "No data converters found.", - "converter-required": "Data converter is required", - "delete": "Delete converter", - "management": "Data converters management", - "add-converter-text": "Add new data converter", - "no-converters-text": "No data converters found", - "selected-converters": "{ count, plural, =1 {1 data converter} other {# data converters} } selected", - "delete-converter-title": "Are you sure you want to delete the data converter '{{converterName}}'?", - "delete-converter-text": "Be careful, after the confirmation the data converter and all related data will become unrecoverable.", - "delete-converters-title": "Are you sure you want to delete { count, plural, =1 {1 data converter} other {# data converters} }?", - "delete-converters-action-title": "Delete { count, plural, =1 {1 data converter} other {# data converters} }", - "delete-converters-text": "Be careful, after the confirmation all selected data converters will be removed and all related data will become unrecoverable.", - "events": "Events", - "add": "Add Data Converter", - "search": "Search data converters", - "converter-details": "Data converter details", - "details": "Details", - "copyId": "Copy converter Id", - "idCopiedMessage": "Converter Id has been copied to clipboard", - "debug-mode": "Debug mode", - "created-time": "Created time", - "name": "Name", - "name-required": "Name is required.", - "name-max-length": "Name should be less than 256", - "description": "Description", - "decoder": "Decoder", - "encoder": "Encoder", - "test-decoder-fuction": "Test decoder function", - "test-encoder-fuction": "Test encoder function", - "test-with-this-message": "{{test}} with this message", - "decoder-input-params": "Decoder input parameters", - "encoder-input-params": "Encoder input parameters", - "payload": "Payload", - "payload-content-type": "Payload content type", - "payload-content": "Payload content", - "message": "Message", - "message-type": "Message type", - "message-type-required": "Message type is required", - "test": "Test", - "metadata": "Metadata", - "metadata-required": "Metadata entries can't be empty.", - "integration-metadata": "Integration metadata", - "integration-metadata-required": "Integration metadata entries can't be empty.", - "output": "Output", - "import": "Import converter", - "export": "Export converter", - "export-failed-error": "Unable to export converter: {{error}}", - "create-new-converter": "Create new converter", - "converter-file": "Converter file", - "invalid-converter-file-error": "Unable to import converter: Invalid converter data structure.", - "type": "Type", - "type-required": "Type is required.", - "type-uplink": "Uplink", - "type-downlink": "Downlink", - "update-only-keys-list": "Update only keys list", - "update-only-keys-list-hint": "The values associated with the provided keys will be saved to the database only if they are different from the corresponding values in the previous converted message. This functionality applies to both attributes and telemetry in the converter output.", - "add-key": "Add key" - }, - "content-type": { - "json": "Json", - "text": "Text", - "binary": "Binary (Base64)" + "email-description": "Naudokite saugos kodą, išsiųstą į jūsų el. pašto adresą, kad autentifikuotumėtės.", + "email-hint": "Autentifikavimo kodai siunčiami el. paštu adresu {{ info }}", + "sms": "SMS", + "sms-description": "Naudokite savo telefoną autentifikacijai. Prisijungiant išsiųsime jums saugos kodą SMS žinute.", + "sms-hint": "Autentifikavimo kodai siunčiami SMS žinute numeriu {{ info }}", + "totp": "Autentifikavimo programėlė", + "totp-description": "Naudokite programėles, tokias kaip Google Authenticator, Authy ar Duo, savo telefone autentifikacijai. Jos generuos prisijungimo kodą.", + "totp-hint": "Autentifikavimo programėlė sukonfigūruota jūsų paskyrai", + "backup_code": "Atsarginis kodas", + "backup-code-description": "Šie vienkartiniai spausdinami kodai leidžia prisijungti, kai neturite prieigos prie telefono, pavyzdžiui, keliaujant.", + "backup-code-hint": "Šiuo metu aktyvūs {{ info }} vienkartinio naudojimo kodai" + } }, - "color": { - "color": "Color", - "color-picker": "Color picker", - "primary-colors": "Primary colors", - "accent-colors": "Accent colors", - "no-color-selected": "No color selected" - }, - "customer": { - "all": "Visi", - "all-customers": "Visi klientai", - "groups": "Grupės", - "shared": "Bendrinami", - "hierarchy": "Hierarchija", - "customer": "Klientas", - "customers": "Klientai", - "management": "Klientų valdymas", - "dashboard": "Klientų skydelis", - "dashboards": "Kliientų skydeliai", - "devices": "Kliento įrenginiai", - "entity-views": "Kliento subjektų rodiniai", - "assets": "Kliento turtas", - "public-dashboards": "Vieši skydeliai", - "public-devices": "Vieši įrenginiai", - "public-assets": "Viešas turtas", - "public-entity-views": "Vieši subjektų rodiniai", - "add": "Pridėti klientą", - "delete": "Pašalinti klientą", - "manage-customer-user-groups": "Kliento vartotojų grupės", - "manage-customer-groups": "Klientų grupės", - "manage-customer-device-groups": "Kliento įrenginių grupės", - "manage-customer-asset-groups": "Kliento turto grupės", - "manage-customer-entity-view-groups": "Kliento subjektų rodinių grupės", - "manage-customer-edge-groups": "Manage customer edge groups", - "manage-customer-dashboard-groups": "Kliento skydelių grupės", - "manage-customer-users": "Kliento vartotojai", - "manage-customers": "Klientai", - "manage-customer-devices": "Kliento įrenginiai", - "manage-customer-entity-views": "Kliento subjektų rodiniai", - "manage-customer-dashboards": "Kliento skydeliai", - "manage-public-devices": "Vieši įrenginiai", - "manage-public-dashboards": "Vieši skydeliai", - "manage-customer-assets": "Kliento turtas", - "manage-customer-edges": "Manage customer edges", - "manage-public-assets": "Viešas turtas", - "add-customer-text": "Pridėti naują klientą", - "no-customers-text": "Klientų nėra", - "customer-details": "Informacija apie klientą", - "delete-customer-title": "Ar tikrai norite pašalinti klientą '{{customerTitle}}'?", - "delete-customer-text": "Būkite dėmesingi, po patvirtinimo, kliento ir su juo susijusios informacijos atkurti nebegalėsite.", - "delete-customers-title": "Ar tikrai norite pašalinti { count, plural, =1 {1 klientą} other {# klientus} }?", - "delete-customers-action-title": "Pašalinti { count, plural, =1 {1 klientą} other {# klientus} }", - "delete-customers-text": "Būkite dėmesingi, po patvirtinimo, klientų ir su jais susijusios informacijos atkurti nebegalėsite.", - "manage-user-groups": "Vartotjų grupės", - "manage-asset-groups": "turto grupės", - "manage-device-groups": "Įrenginių grupės", - "manage-dashboard-groups": "Skydelių grupės", - "manage-entity-view-groups": "Subjektų rodinių grupės", - "manage-edge-groups": "Manage edge groups", - "manage-users": "Vartotojai", - "manage-assets": "Turtas", - "manage-devices": "Įrenginiai", - "manage-dashboards": "Skydeliai", - "manage-entity-views": "Subjektų rodiniai", - "title": "Pavadinimas", - "title-required": "Pavadinimas būtinas.", - "title-max-length": "Pavadinimas negali viršyti 256 simbolių", - "description": "Aprašymas", - "details": "Informacija", - "events": "Įvykiai", - "copyId": "Kopijuoti kliento Id", - "idCopiedMessage": "Kliento Id nukopijuotas į iškarpinę", - "select-customer": "Pasirinkti klientą", - "no-customers-matching": "Klientų, atitinkančių '{{entity}}' nėra.", - "customer-required": "Klientas būtinas", - "select-group-to-add": "Pasirinkite grupę, į kurią pridėti pažymėtus klientus", - "select-group-to-move": "Pasirinkite grupę, į kurią perkelti pažymėtus klientus", - "remove-customers-from-group": "Ar tikrai { count, plural, =1 {1 klientą} other {# klientus} } norite pašalinti iš grupės '{{entityGroup}}'?", - "group": "Klientų grupė", - "list-of-groups": "{ count, plural, =1 {Viena kliento grupė} other {Sąrašas # klientų grupių} }", - "group-name-starts-with": "Klientų grupės, kurios prasideda '{{prefix}}'", - "select-default-customer": "Pasirinkite numatytąjį klientą", - "default-customer": "Numatytasis klientas", - "default-customer-required": "Numatytasis klientas būtinas, norint suderinti prietaisų skydelį valdytojo lygiu", - "allow-white-labeling": "Leisti tinkinti aplikaciją", - "search": "Klientų paieška", - "selected-customers": "Pasirinkta { count, plural, =1 {1 klientas} other {# kientai} }", - "edges": "Customer edge instances", - "manage-edges": "Manage edges" - }, - "customers-hierarchy": { - "customers-hierarchy": "Klientų hierarchija", - "open-nav-tree": "Atverti navigacijos medį", - "return-to-top-level": "Grįžti į aukščiausią lygį" - }, - "custom-menu": { - "custom-menu": "Vartotojo meniu", - "custom-menu-hint": "Aprašykite pasirinktinį meniu JSON formoje. Šiame JSON nurodomas vartotojo meniu elementų sąrašas." - }, - "custom-translation": { - "custom-translation": "Vartotojo vertimai", - "translation-map": "Vertimų žemėlapis", - "key": "Vertimo raktas", - "import": "Importuoti vertimą", - "export": "Eksportuoti vertimą", - "export-data": "Eksportuoti vertimo duomenis", - "import-data": "Importuoti vertimo duomenis", - "translation-file": "Vertimų failas", - "invalid-translation-file-error": "Nepavyksta importuoti vertimo failo: Neteisinga duomenų struktūra.", - "custom-translation-hint": "Aprašykite vartotojo vertimą JSON formatu žemiau. Šis JSON perrašys standartinį vertimą. Paspaudę 'Parsisiųsti lokalės failą', gausite standartinio vertimo failą, kuriame galite surasti reikalingas raktų-reikšmių poros ir jas pakeisti savo JSON.", - "download-locale-file": "Parsisųsti lokalės failą" - }, - "date": { - "last-update-n-ago": "Last update N ago", - "last-update-n-ago-text": "Last update {{ agoText }}", - "custom-date": "Custom date", - "format": "Format", - "preview": "Preview" - }, - "datetime": { - "date-from": "Data nuo", - "time-from": "Laikas nuo", - "date-to": "Data iki", - "time-to": "Laikas iki" - }, - "dashboard": { - "all": "Visi", - "all-dashboards": "Visi skydeliai", - "groups": "Grupės", - "shared": "Bendrinami", - "dashboard": "Skydelis", - "dashboards": "Skydeliai", - "management": "Skydelių valdymas", - "view-dashboards": "Paržiūrėti skydelius", - "add": "Pridėti skydelį", - "assign-dashboard-to-customer": "Skydelį (-ius) priskirti klientui", - "assign-dashboard-to-customer-text": "Pasirinkite skydelius, kuriuos norite priskirti klientui", - "assign-to-customer-text": "Pasirinkite klientą, kuriam priskirti skydelį (-ius)", - "assign-to-customer": "Priskirti kientui", - "unassign-from-customer": "Atsieti nuo kliento", - "make-public": "Skydelį padaryti viešą", - "make-private": "Skydelį padaryti privatų", - "manage-assigned-customers": "Valdyti priskirtus klientus", - "assigned-customers": "Priskirti klientai", - "assign-to-customers": "Skydelį (-ius) priskirti klientams", - "assign-to-customers-text": "Pasirinkite klientus, kuriems priskirti skydelį (-ius)", - "unassign-from-customers": "Skydelį (-ius) atsieti nuo klientų", - "unassign-from-customers-text": "Pasirinkite klientus, kuriems atsieti skydelį (-ius)", - "no-dashboards-text": "Skydelių nėra", - "no-widgets": "Valdikliai nesukonfigūruoti", - "add-widget": "Pridėti naują valdiklį", - "add-widget-button-text": "Pridėt valdiklį", - "title": "Pavadinimas", - "image": "Skydelio paveiksliukas", - "mobile-app-settings": "Mobiliosios aplikacijos nustatymai", - "mobile-order": "Skydelio eilės tvarka mobiliojoje aplikacijoje", - "mobile-hide": "Mobiliojoje aplikacijoje skydelį paslėpti", - "update-image": "Atnaujinti skydelio paveiksliuką", - "take-screenshot": "Padaryti ekrano nuotrauką", - "select-widget-title": "Pasirinkite valdiklį", - "select-widget-value": "{{title}}: pasirinkite valdiklį", - "select-widget-subtitle": "Galimų valdiklių sąrašas", - "delete": "Pašalinti skydelį", - "title-required": "Pavadinimas būtinas.", - "title-max-length": "Pavadinimas negali viršyti 256 simbolių", - "description": "Aprašymas", - "details": "Informacija", - "dashboard-details": "Informacija", - "add-dashboard-text": "Pridėti naują skydelį", - "assign-dashboards": "Priskirti skydelius", - "assign-new-dashboard": "Priskirti naują skydelį", - "assign-dashboards-text": "Priskirti { count, plural, =1 {1 skydelį} other {# skydelius} } klientams", - "unassign-dashboards-action-text": "Atsieti { count, plural, =1 {1 skydelį} other {# skydelius} } nuo klientų", - "delete-dashboards": "Panaikinti skydelius", - "unassign-dashboards": "Atsieti skydelius", - "unassign-dashboards-action-title": "Atsieti { count, plural, =1 {1 skydelį} other {# skydelius} } nuo kliento", - "delete-dashboard-title": "Ar tikrai norite pašalinti skydelį '{{dashboardTitle}}'?", - "delete-dashboard-text": "Būkite dėmesingi, po patvirtinimo, skydelio ir su juo susijusios informacijos atkurti nebegalėsite.", - "delete-dashboards-title": "Ar tikrai norite pašalinti { count, plural, =1 {1 skydelį} other {# skydelius} }?", - "delete-dashboards-action-title": "Pašalinti { count, plural, =1 {1 skydelį} other {# skydelius} }", - "delete-dashboards-text": "Būkite dėmesingi, po patvirtinimo, pasirinkti skydeliai ir su jais susijusi informacija bus pašalinti ir jų atkurti nebegalėsite.", - "unassign-dashboard-title": "Ar tikrai norite atsieti skydelį '{{dashboardTitle}}'?", - "unassign-dashboard-text": "Po patvrtinimo skydelis bus atsietas ir klientas jo nebematys.", - "unassign-dashboard": "Atsieti skydelį", - "unassign-dashboards-title": "Ar tikrai norite atsieti { count, plural, =1 {1 skydelį} other {# skydelius} }?", - "unassign-dashboards-text": "Po patvirtinimo visi skydeliai bus atsieti ir klientas jų nebematys.", - "public-dashboard-title": "Skydelis dabar yra viešas", - "public-dashboard-text": "Skydelis {{dashboardTitle}} dabar yra viešas ir pasiekiamas per šią nuorodą:", - "public-dashboard-notice": "Pastaba: Įrenginiai turi būti vieši, jei norite matyti jų duomenis.", - "public-dashboard-link": "Vieša skydelio nuoroda", - "public-dashboard-link-text": "Viešą sydelį {{dashboardTitle}} galima atidaryti per šią nuorodą:", - "public-dashboard-link-notice": "Pastaba: Įrenginiai, turtas ir subjektai turi būti vieši, jei norite matyti jų duomenis.", - "make-private-dashboard-title": "Ar tikrai norite skydelį '{{dashboardTitle}}' padaryti privačiu?", - "make-private-dashboard-text": "Po patvirtinimo, skydelis taps privačiu ir jo nematys kiti vartotojai.", - "make-private-dashboard": "Skydelį padaryti privačiu", - "socialshare-text": "'{{dashboardTitle}}' powered by ThingsBoard", - "socialshare-title": "'{{dashboardTitle}}' powered by ThingsBoard", - "select-dashboard": "Pasirinkite skydelį", - "no-dashboards-matching": "Skydelio, atitinkančio '{{entity}}' nėra.", - "dashboard-required": "Skydelis būtinas.", - "select-existing": "Pasirinkite egzistuojantį skydelį", - "create-new": "Sukurti naują skydelį", - "new-dashboard-title": "Naujas skydelio pavadinimas", - "open-dashboard": "Atidaryti skydelį", - "set-background": "Nustatyti foną", - "background-color": "Fono spalva", - "background-image": "Fono paveikslėlis", - "background-size-mode": "Fono dydis", - "no-image": "Paveikslėlis nepasirinktas", - "empty-image": "Nėra paveikslėlio", - "drop-image": "Užvilkite paveikslėlį arba spustelėkite ir pasirinkite failą.", - "maximum-upload-file-size": "Maksimalus įkeliamo failo dydis: {{ size }}", - "cannot-upload-file": "Failo įkelti nepavyko", - "settings": "Nustatymai", - "columns-count": "Stulpelių skaičius", - "columns-count-required": "Stulpelių skaičius būtinas.", - "min-columns-count-message": "Minimalus stulpelių skaičius - 10.", - "max-columns-count-message": "Maksimalus stulpelių skaičius - 1000.", - "widgets-margins": "Paraštės tarp valdiklių dysis", - "margin-required": "Paraštės dydžio reikšmė būtina.", - "min-margin-message": "Minimali paraštės dydžio reikšmė - 0.", - "max-margin-message": "Maksimali paraštės dydžio reikšmė - 50.", - "horizontal-margin": "Horizontalios paraštės dydis", - "horizontal-margin-required": "Horizontalios paraštės dydžio reikšmė būtina.", - "min-horizontal-margin-message": "Minimali horizontalios paraštės dydžio reikšmė - 0", - "max-horizontal-margin-message": "Maksimali horizontalios paraštės dydžio reikšmė - 50.", - "vertical-margin": "Vertikalios paraštės dydis", - "vertical-margin-required": "Vertikalios paraštės dydžio reikšmė būtina.", - "min-vertical-margin-message": "Minimali vertikalios paraštės dydžio reikšmė - 0.", - "max-vertical-margin-message": "Maksimali vertikalios paraštės dydžio reikšmė - 50.", - "apply-outer-margin": "Taikyti paraštes maketo šonuose", - "autofill-height": "Automatiškai pritaikyti aukštį", - "mobile-layout": "Mobiliojo režimo išdėstymo nustatymai", - "mobile-row-height": "Mobiliojo režimo eilutės aukštis pikseliais", - "mobile-row-height-required": "Mobiliojo režimo eilutės aukštis būtinas.", - "min-mobile-row-height-message": "Minimalus mobiliojo režimo eilutės aukštis yra 5 pikseliai.", - "max-mobile-row-height-message": "Maksimalus mobiliojo režimo eilutės aukštis yra 200 pikselių.", - "title-settings": "Pavadinimo nustatymai", - "display-title": "Rodyt skydelio pavadinimą", - "title-color": "Pavadinimo spalva", - "toolbar-settings": "Įrankių juostos nustatymai", - "hide-toolbar": "Paslėpti įrankių juostą", - "toolbar-always-open": "Įrankių juostą laikyti atdarytą", - "display-dashboards-selection": "Rodyti skydelių pasirinkimą", - "display-entities-selection": "Rodyti subjektų pasirinkimą", - "display-filters": "Rodyti filtrus", - "display-dashboard-timewindow": "Rodyti laiko langą", - "display-dashboard-export": "Rodyti eksportą", - "display-update-dashboard-image": "Display update dashboard image", - "dashboard-logo-settings": "Dashboard logo settings", - "display-dashboard-logo": "Display logo in dashboard fullscreen mode", - "dashboard-logo-image": "Dashboard logo image", - "advanced-settings": "Advanced settings", - "dashboard-css": "Dashboard CSS", - "import": "Importuoti skydelį", - "export": "Eksportuoti skydelį", - "export-failed-error": "Skydelio importuoti nepavyko: {{error}}", - "export-pdf": "Eksportuoti kaip PDF", - "export-png": "Eksportuoti kaip PNG", - "export-jpg": "Eksportuoti kaip JPEG", - "export-json-config": "Eksportuoti JSON konfigūraciją", - "download-dashboard-progress": "Generuojamas skydelis {{reportType}} ...", - "create-new-dashboard": "Sukurti naują skydelį", - "dashboard-file": "Skydelio failas", - "invalid-dashboard-file-error": "Skydelio importuoti nepavyko: neteisinga duomenų struktūra.", - "dashboard-import-missing-aliases-title": "Konfigūruoti importuoto skydelio naudojamus pseudonimus", - "create-new-widget": "Sukurti naują valdiklį", - "import-widget": "importuoti valdiklį", - "widget-file": "valdiklio failas", - "invalid-widget-file-error": "Valdiklio importuoti nepavyko: neteisinga duomenų struktūra.", - "widget-import-missing-aliases-title": "Konfigūruoti importuoto valdiklio naudojamus pseudonimus", - "open-toolbar": "Atidaryti skydelio įrankių juostą", - "close-toolbar": "Uždaryti įrankių juostą", - "configuration-error": "Konfigūracijos klaida", - "alias-resolution-error-title": "Skydelio pseudonimų konfigūracijos klaida", - "invalid-aliases-config": "Įrenginių, atitinkančių pseudonimų filtrus, nėra.
Susisiekite su sistemos administratoriumi.", - "select-devices": "Pasirinkite įrenginius", - "assignedToCustomer": "Priskirta klientui", - "assignedToCustomers": "Priskirta klientams", - "public": "Viešas", - "copyId": "Kopijuoti skydelio Id", - "idCopiedMessage": "Skydelio Id nukopijuotas į iškarpinę", - "public-link": "Vieša nuoroda", - "copy-public-link": "Kopijuoti viešą nuorodą", - "public-link-copied-message": "Skydelio vieša nuoroda nukopijuota į iškarpinę", - "manage-states": "Valdyti skydelio būsenas", - "states": "Skydelio būsenos", - "states-short": "Būsenos", - "search-states": "Skydelio būsenų paieška", - "selected-states": "Pasirinkta skydelio { count, plural, =1 {1 būsena} other {# būsenos} }", - "edit-state": "Redaguoti skydelio būseną", - "delete-state": "Panaikinti skydelio būseną", - "add-state": "Pridėti skydelio būseną", - "no-states-text": "Būsenų nėra", - "state": "Skydelio būsena", - "state-name": "Pavadinimas", - "state-name-required": "Skydelio pavadinimas būtinas.", - "state-id": "Būsenos Id", - "state-id-required": "Būsenos Id būtinas.", - "state-id-exists": "Skydelio būsena su tokiu pačiu Id jau yra.", - "is-root-state": "Pagrindinė būsena", - "delete-state-title": "Panaikinti skydelio būseną", - "delete-state-text": "Ar tikrai norite panaikinti skydelio būseną '{{stateName}}'?", - "show-details": "Rodyti detales", - "hide-details": "Slėpti detales", - "select-state": "Pasirinkite būseną", - "state-controller": "Būsenų valdiklis", - "search": "Skydelių paieška", - "selected-dashboards": "Pasirinkta { count, plural, =1 {1 skydelis} other {# skydeliai} }", - "home-dashboard": "Pagrindinis skydelis", - "home-dashboard-hide-toolbar": "Slėpti pagrindinio skydelio įrankių juostą", - "select-group-to-add": "Pasirinkite grupę, prie kurios pridėti pažymėtus skydelius", - "select-group-to-move": "Pasirinkite grupę, į kurią perkelti pasirinktus skydelius", - "remove-dashboards-from-group": "Ar tikrai pašalinti { count, plural, =1 {1 skydelį} other {# skydelius} } iš grupės '{{entityGroup}}'?", - "group": "Skydelių grupė", - "list-of-groups": "{ count, plural, =1 {Viena skydelių grupė} other {Sąrašas # skydelių grupių} }", - "group-name-starts-with": "Skydelių grupės, kurių pavadinimai prasideda '{{prefix}}'", - "unassign-dashboard-from-edge-text": "After the confirmation the dashboard will be unassigned and won't be accessible by the edge.", - "unassign-dashboards-from-edge-title": "Are you sure you want to unassign { count, plural, =1 {1 dashboard} other {# dashboards} }?", - "unassign-dashboards-from-edge-text": "After the confirmation all selected dashboards will be unassigned and won't be accessible by the edge.", - "assign-dashboard-to-edge": "Assign Dashboard(s) To Edge", - "assign-dashboard-to-edge-text": "Please select the dashboards to assign to the edge", - "non-existent-dashboard-state-error": "Dashboard state with id \"{{ stateId }}\" is not found", - "edit-mode": "Edit mode" - }, - "datakey": { - "settings": "Nustatymai", - "general": "Bendra", - "advanced": "Patyrusiam vartotojui", - "key": "Raktas", - "label": "Etiketė", - "color": "Spalva", - "units": "Specialieji simboliai, rodomi šalia reikšmės", - "decimals": "Skaičių kiekis po kablelio", - "data-generation-func": "Duomenų generavimo funkcija", - "use-data-post-processing-func": "Papildomo duomenų apdorojimo funkcija", - "configuration": "Duomenų raktų konfigūracija", - "timeseries": "Telemetrija", - "attributes": "Atributai", - "entity-field": "Subjekto laukas", - "alarm": "Įspėjimo laukai", - "timeseries-required": "Subjekto telemetrija būtina.", - "timeseries-or-attributes-required": "Subjekto telemetrija/atributai būtini.", - "alarm-fields-timeseries-or-attributes-required": "Įspėjimo laukai ar subjekto telemetrijos/atributai būtini.", - "maximum-timeseries-or-attributes": "Leidžiama daugiausiai { count, plural, =1 {1 viena telemetrija/atributas.} other {# telemetrijos/atributai} }", - "alarm-fields-required": "Įspėjimo laukai būtini.", - "function-types": "Funkcijų tipai", - "function-type": "Funkcijos tipas", - "function-types-required": "Funkcijos tipai būtini.", - "data-keys": "Duomenų raktai", - "data-key": "Duomenų raktas", - "data-keys-required": "Duomenų raktai būtini.", - "data-key-required": "Duomenų raktas būtinas.", - "alarm-keys": "Įspėjimo duomenų raktai", - "alarm-key": "Įspėjimo duomenų raktas", - "alarm-key-functions": "Alarm key functions", - "alarm-key-function": "Alarm key function", - "latest-keys": "Latest data keys", - "latest-key": "Latest data key", - "latest-key-functions": "Latest key functions", - "latest-key-function": "Latest key function", - "timeseries-keys": "Timeseries data keys", - "timeseries-key": "Timeseries data key", - "timeseries-key-functions": "Timeseries key functions", - "timeseries-key-function": "Timeseries key function", - "maximum-function-types": "Daugiausiai leidžiama { count, plural, =1 {1 funkcijos tipas.} other {# funkcijos tipai} }", - "time-description": "Dabartinės vertės laiko žyma;", - "value-description": "Dabartinė vertė;", - "prev-value-description": "Ankstesnio funkcijos kvietimo rezultatas;", - "time-prev-description": "Ankstesnės vertės laiko žyma;", - "prev-orig-value-description": "Pradinė ankstesnė vertė;", - "aggregation": "Agregavimas", - "aggregation-type-hint-common": "For performance reasons, the aggregated values calculation is available only for fixed time intervals like \"current day\", \"current month\", etc, and is not available for sliding window intervals like 'last 30 minutes' or 'last 24 hours'.", - "aggregation-type-none-hint": "Take latest value.", - "aggregation-type-min-hint": "Find minimum value among data points within a selected time window.", - "aggregation-type-max-hint": "Find maximum value among data points within a selected time window.", - "aggregation-type-avg-hint": "Calculate an average value among data points within a selected time window.", - "aggregation-type-sum-hint": "Sum all values of the data points within a selected time window.", - "aggregation-type-count-hint": "Total number of the data points within a selected time window.", - "delta-calculation": "Delta calculation", - "enable-delta-calculation": "Enable delta calculation", - "enable-delta-calculation-hint": "When enabled, the data key value is calculated based on the aggregated values for a selected time window and a specified comparison period. For performance reasons, the delta calculation is available only for history time windows and not for real-time values. For example, you may calculate the delta between the energy consumption for yesterday compared to the energy consumption for the day before yesterday.", - "delta-calculation-result": "Delta calculation result", - "delta-calculation-result-previous-value": "Previous value", - "delta-calculation-result-delta-absolute": "Delta (absolute)", - "delta-calculation-result-delta-percent": "Delta (percent)", - "source": "Source", - "latest": "Latest", - "latest-value": "Latest value", - "delta": "delta", - "percent": "percent", - "absolute": "absolute" - }, - "datasource": { - "type": "Duomenų šaltinio tipas", - "name": "Pavadinimas", - "label": "Etiketė", - "add-datasource-prompt": "Pridėkite duomenų šaltinį" + "password-requirement": { + "at-least": "Bent:", + "character": "{ count, plural, =1 {1 simbolis} other {# simboliai(-ų)} }", + "digit": "{ count, plural, =1 {1 skaitmuo} other {# skaitmenys(-ų)} }", + "incorrect-password-try-again": "Neteisingas slaptažodis. Bandykite dar kartą", + "lowercase-letter": "{ count, plural, =1 {1 mažoji raidė} other {# mažosios raidės(-ių)} }", + "new-passwords-not-match": "Nauji slaptažodžiai nesutampa", + "password-should-not-contain-spaces": "Slaptažodyje negali būti tarpų", + "password-not-meet-requirements": "Slaptažodis neatitinka reikalavimų", + "password-requirements": "Slaptažodžio reikalavimai", + "password-should-difference": "Naujas slaptažodis turi skirtis nuo dabartinio", + "special-character": "{ count, plural, =1 {1 specialus simbolis} other {# specialūs simboliai(-ių)} }", + "uppercase-letter": "{ count, plural, =1 {1 didžioji raidė} other {# didžiosios raidės(-ių)} }", + "at-most": "Daugiausia:" + } + }, + "relation": { + "relations": "Ryšiai", + "direction": "Kryptis", + "clear-relation-type": "Aiškus ryšio tipas", + "search-direction": { + "FROM": "Iš", + "TO": "Į" }, - "details": { - "details": "Informacija", - "edit-mode": "Redagavimo režimas", - "edit-json": "Redaguoti JSON", - "toggle-edit-mode": "Redagavimo režimas" + "direction-type": { + "FROM": "iš", + "TO": "į" }, - "device": { - "all": "Visi", - "all-devices": "Visi įrenginiai", - "groups": "Grupės", - "shared": "Bendrinami", - "device": "Įrenginys", - "device-required": "Įrenginys būtinas.", - "devices": "Įrenginiai", - "management": "Įrenginių valdymas", - "view-devices": "Peržiūrėti įrenginius", - "device-alias": "Įrenginio pseudonimas", - "device-type-max-length": "Įrenginio tipas negali viršyti 256 simbolių", - "aliases": "Įrenginių pseudonimai aliases", - "no-alias-matching": "'{{alias}}' nerasta.", - "no-aliases-found": "Pseudonimų nėra.", - "no-key-matching": "'{{key}}' nerasta.", - "no-keys-found": "Raktų nėra.", - "create-new-alias": "Sukurti naują!", - "create-new-key": "Sukurti naują!", - "duplicate-alias-error": "'{{alias}}' dubliuojasi.
Įrenginio pseudonimai skydelyje turi būti unikalūs.", - "configure-alias": "Sukonfigūruoti '{{alias}}' pseudonimą", - "no-devices-matching": "Įrenginių, attinkančių '{{entity}}' nėra.", - "alias": "Pseudonimas", - "alias-required": "Įrenginio pseudonimas būtinas.", - "remove-alias": "Panaikinti įrenginio pseudonimą", - "add-alias": "Pridėti įrenginio pseudonimą", - "name-starts-with": "Įrenginio pavadinimas prasideda", - "help-text": "Naudokite '%' simbolį pagal tai, kaip norite ieškoti: '%įrenginio_pavadinimo_fragmentas%', '%įrenginio_pavadinimo_pabaiga', 'įrenginio_pavadinimo_pradžia%'.", - "device-list": "Įrenginių sąrašas", - "use-device-name-filter": "Naudoti filtrą", - "device-list-empty": "Įrenginiai nepasirinkti.", - "device-name-filter-required": "Įrenginio pavadinimo filtras turi būti nustatytas.", - "device-name-filter-no-device-matched": "Įrenginių, kurių pavadinimas prasideda '{{device}}' nėra.", - "add": "Pridėti įrenginį", - "assign-to-customer": "Priskirti kientui", - "assign-device-to-customer": "Įrenginį (-ius) priskirti klientui", - "assign-device-to-customer-text": "Pasirinkite įrenginius, kuriuos norite priskirti klientui", - "make-public": "Įrenginį padaryti viešu", - "make-private": "Įrenginį padaryti privačiu", - "no-devices-text": "Įrenginių nėra", - "assign-to-customer-text": "Pasirinkite klientą, kuriam norite priskirti įrenginį (-ius)", - "device-details": "Įrenginio informacija", - "add-device-text": "Pridėti naują įrenginį", - "credentials": "Įgaliojimai", - "manage-credentials": "Valdyti įgaliojimus", - "delete": "Panaikinti įrenginį", - "assign-devices": "priskirti įrenginius", - "assign-devices-text": "Priskirti { count, plural, =1 {1 įrenginį} other {# įrenginius} } klientui", - "delete-devices": "Panaikinti įrenginius", - "unassign-from-customer": "Atseti nuo kliento", - "unassign-devices": "Atsieti įrenginius", - "unassign-devices-action-title": "Atsieti { count, plural, =1 {1 įrenginį} other {# įrenginius} } nuo kliento", - "unassign-device-from-edge-title": "Are you sure you want to unassign the device '{{deviceName}}'?", - "unassign-device-from-edge-text": "After the confirmation the device will be unassigned and won't be accessible by the edge.", - "unassign-devices-from-edge": "Unassign devices from edge", - "assign-new-device": "Priskirti naują įrenginį", - "make-public-device-title": "Ar tikrai norite įrenginį '{{deviceName}}' padaryti viešu?", - "make-public-device-text": "Po patvirtinimo įrenginys ir visi jo duomenys bus vieši ir prieinami kitiems vartotojams.", - "make-private-device-title": "Ar tikrai norite įrenginį '{{deviceName}}' padaryti privačiu?", - "make-private-device-text": "Po patvirtinimo įrenginys ir visi jo duomenys taps privatūs ir nebus prieinami kitiems vartotojams.", - "view-credentials": "Peržiūrėti įgaliojimus", - "delete-device-title": "Ar tikrai norite panaikinti įrenginį '{{deviceName}}'?", - "delete-device-text": "Būkite dėmesingi, po patvirtinimo įrenginys ir visa su juo susijusi informacija bus panaikinta ir jų atkurti nebegalėsite", - "delete-devices-title": "Ar tikrai norite panaikinti { count, plural, =1 {1 įrenginį} other {# įrenginius} }?", - "delete-devices-action-title": "Panaikinti { count, plural, =1 {1 įrenginį} other {# įrenginius} }", - "delete-devices-text": "Būkite dėmesingi, po patvirtinimo, visi pasirinkti įrenginiai ir su jais susijusi informacija bus panaikinta ir jų atkurti nebegalėsite.", - "unassign-device-title": "Ar tikrai norite atsieti įrenginį '{{deviceName}}'?", - "unassign-device-text": "Po patvirtinimo įrenginys bus atsietas ir klientas jo nebematys.", - "unassign-device": "Atsieti įrenginį", - "unassign-devices-title": "Ar tikrai norite atsieti { count, plural, =1 {1 įrenginį} other {# įrenginius} }?", - "unassign-devices-text": "Po patvirtinimo visi pasirinkti įrenginiai bus atsieti nuo kliento.", - "device-credentials": "įrenginio įgaliojimai", - "loading-device-credentials": "Įkeliami įrenginio įgaliojimai...", - "credentials-type": "Įgaliojimų tipas", - "access-token": "Prieigos raktas", - "access-token-required": "Prieigos raktas būtinas.", - "access-token-invalid": "Prieigos rakto ilgis turi būti nuo 1 iki 32 simbolių.", - "certificate-pem-format": "Certificate in PEM format", - "certificate-pem-format-required": "Certificate is required.", - "copy-access-token": "Copy Access token", - "copy-certificate": "Copy Certificate", - "copy-client-id": "Copy Client ID", - "copy-user-name": "Copy User name", - "copy-password": "Copy Password", - "generate-client-id": "Generate Client ID", - "generate-user-name": "Generate User name", - "generate-password": "Generate Password", - "generate-access-token": "Generate Access Token", - "lwm2m-security-config": { - "identity": "Client Identity", - "identity-required": "Client Identity is required.", - "identity-tooltip": "The PSK identifier is an arbitrary PSK identifier up to 128 bytes, as described in the standard [RFC7925].\nThe PSK identifier MUST first be converted to a character string and then encoded into octets using UTF-8.", - "client-key": "Client Key", - "client-key-required": "Client Key is required.", - "client-key-tooltip-prk": "RPK public key or id must be in the standard [RFC7250] and encoded to Base64 format!", - "client-key-tooltip-psk": "PSK key must be in the standard [RFC4279] and HexDec format: 32, 64, 128 characters!", - "endpoint": "Endpoint Client Name", - "endpoint-required": "Endpoint Client Name is required.", - "client-public-key": "Client public key", - "client-public-key-hint": "If client public key is empty, the trusted certificate will be used", - "client-public-key-tooltip": "X509 public key must be in DER-encoded X509v3 format and support exclusively EC algorithm and then encoded to Base64 format!", - "mode": "Security config mode", - "client-tab": "Client Security Config", - "client-certificate": "Client certificate", - "bootstrap-tab": "Bootstrap Client", - "bootstrap-server": "Bootstrap Server", - "lwm2m-server": "LwM2M Server", - "client-publicKey-or-id": "Client Public Key or Id", - "client-publicKey-or-id-required": "Client Public Key or Id is required.", - "client-publicKey-or-id-tooltip-psk": "The PSK identifier is an arbitrary PSK identifier up to 128 bytes, as described in the standard [RFC7925].\nThe PSK identifier MUST first be converted to a character string and then encoded into octets using UTF-8.", - "client-publicKey-or-id-tooltip-rpk": "RPK public key or id must be in the standard [RFC7250] and encoded to Base64 format!", - "client-publicKey-or-id-tooltip-x509": "X509 public key must be in DER-encoded X509v3 format and support exclusively EC algorithm and then encoded to Base64 format", - "client-secret-key": "Client Secret Key", - "client-secret-key-required": "Client Secret Key is required.", - "client-secret-key-tooltip-psk": "PSK key must be in the standard [RFC4279] and HexDec format: 32, 64, 128 characters!", - "client-secret-key-tooltip-prk": "RPK secret key must be in PKCS_8 format (DER encoding, standard [RFC5958]) and then encoded to Base64 format!", - "client-secret-key-tooltip-x509": "X509 secret key must be in PKCS_8 format (DER encoding, standard [RFC5958]) and then encoded to Base64 format!" - }, - "client-id": "Client ID", - "client-id-pattern": "Contains invalid character.", - "user-name": "User Name", - "user-name-required": "User Name is required.", - "client-id-or-user-name-necessary": "Client ID and/or User Name are necessary", - "password": "Password", - "secret": "Secret", - "secret-required": "Secret is required.", - "device-type": "Įrenginio tipas", - "device-type-required": "Įrenginio tipas būtinas.", - "select-device-type": "Pasirinkite įrenginio tipą", - "enter-device-type": "Įveskite įrenginio tipą", - "any-device": "Bet kuris įrenginys", - "no-device-types-matching": "Įrenginio tipų, atitinkančių '{{entitySubtype}}', nėra.", - "device-type-list-empty": "Nepasirinktas įrenginio tipas!", - "device-types": "Įrenginių tipai", - "name": "Pavadinimas", - "name-required": "Pavadinimas būtinas.", - "name-max-length": "Pavadinimas negali viršyti 256 simbolių", - "label-max-length": "Etiketė negali viršyti 256 simbolių", - "description": "Aprašymas", + "from-relations": "Išeinantys ryšiai", + "to-relations": "įeinantys ryšiai", + "selected-relations": "Pasirinkta { count, plural, =1 {1 ryšys} other {# ryšiai} } selected", + "type": "Tipas", + "to-entity-type": "Į subjekto tipą", + "to-entity-name": "Į subjektą", + "from-entity-type": "iš subjektų tipo", + "from-entity-name": "Iš subjekto", + "to-entity": "į subjektą", + "from-entity": "Iš subjekto", + "delete": "panaikinti ryšį", + "relation-type": "Ryšio tipas", + "relation-type-required": "Ryšio tipas būtinas.", + "relation-type-max-length": "Ryšio tipas negali viršyti 256 simbolių", + "any-relation-type": "Bet kuris tipas", + "add": "pridėti ryšį", + "edit": "Redaguoti ryšį", + "delete-to-relation-title": "Ar tikrai norite panaikinti ryšį su '{{entityName}}' subjektu?", + "delete-to-relation-text": "Būkite dėmesingi, po patvirtinimo '{{entityName}}' subjektas neteks ryšio su dabartiniu subjektu.", + "delete-to-relations-title": "Ar tikrai norite panaikinti { count, plural, =1 {1 ryšį} other {# ryšius} }?", + "delete-to-relations-text": "Būkite dėmesingi, po patvirtinimo visi pasirinkti ryšiai bus panaikinti ir atitinkami subjektai neteks ryšių su dabartiniu subjektu.", + "delete-from-relation-title": "Ar tikrai norite panaikinti ryšį iš '{{entityName}}' subjekto?", + "delete-from-relation-text": "Būkite dėmesingi, po patvirtinimo, dabartinis subjektas neteks ryšio su '{{entityName}}' subjektu.", + "delete-from-relations-title": "Ar tikrai norite panaikinti { count, plural, =1 {1 ryšį} other {# ryšius} }?", + "delete-from-relations-text": "Būkite dėmesingi, po patvirtinimo, visi pasirinkti ryšiai bus panaikinti ir dabartinis subjektas neteks ryšių su atitinkamais subjektais.", + "remove-relation-filter": "Panaikinti ryšių filtrą", + "remove-filter": "Panakinti filtrą", + "add-relation-filter": "Pridėti ryšių filtrą", + "any-relation": "Bet kuris ryšys", + "relation-filters": "Ryšių filtrai", + "relation-filter": "Relation filter", + "additional-info": "Papildoma informacija (JSON)", + "invalid-additional-info": "Papildomos JSON informacijos išanalizuoti nepavyko.", + "no-relations-text": "Ryšių nėra", + "not": "Ne" + }, + "resource": { + "add": "Pridėti išteklių", + "all-types": "Visi", + "copyId": "Kopijuoti ištekliaus ID", + "delete": "Ištrinti išteklių", + "delete-resource-text": "Būkite atsargūs, po patvirtinimo šis išteklius bus negrįžtamai pašalintas.", + "delete-resource-title": "Ar tikrai norite ištrinti išteklių '{{resourceTitle}}'?", + "delete-resources-action-title": "Ištrinti { count, plural, =1 {1 išteklių} other {# išteklius(-ių)} }", + "delete-resources-text": "Atkreipkite dėmesį, kad pasirinkti ištekliai bus ištrinti, net jei jie naudojami įrenginių profiliuose.", + "delete-resources-title": "Ar tikrai norite ištrinti { count, plural, =1 {1 išteklių} other {# išteklius(-ių)} }?", + "download": "Atsisiųsti išteklių", + "drop-file": "Įkelkite išteklių failą arba spustelėkite norėdami pasirinkti failą.", + "drop-resource-file-or": "Vilkdami įkelkite išteklių failą arba", + "empty": "Išteklius tuščias", + "file-name": "Failo pavadinimas", + "idCopiedMessage": "Išteklius ID nukopijuotas į iškarpinę", + "no-resource-matching": "Nerasta ištekliaus, atitinkančio '{{widgetsBundle}}'.", + "no-resource-text": "Išteklių nerasta", + "open-widgets-bundle": "Atidaryti valdiklių paketą", + "resource": "Išteklius", + "resource-file": "Išteklių failas", + "resource-files": "Išteklių failai", + "resource-library-details": "Išteklių informacija", + "resource-type": "Išteklių tipas", + "resources-library": "Išteklių biblioteka", + "search": "Ieškoti išteklių", + "selected-resources": "{ count, plural, =1 {1 išteklius} other {# ištekliai(-ių)} } pasirinkta", + "system": "Sistema", + "title": "Pavadinimas", + "title-required": "Pavadinimas yra privalomas.", + "title-max-length": "Pavadinimas turi būti trumpesnis nei 256 simboliai", + "type": { + "jks": "JKS", + "js-module": "JS modulis", + "lwm2m-model": "LWM2M modelis", + "pkcs-12": "PKCS #12" + }, + "resource-sub-type": "Potipio", + "sub-type": { + "image": "Paveikslėlis", + "scada-symbol": "SCADA simbolis", + "extension": "Plėtinys", + "module": "Modulis" + } + }, + "javascript": { + "add": "Pridėti JavaScript išteklių", + "delete": "Ištrinti JavaScript išteklių", + "delete-javascript-resource-text": "Būkite atsargūs – po patvirtinimo šis JavaScript išteklius bus nebeatkuriamas.", + "delete-javascript-resource-title": "Ar tikrai norite ištrinti JavaScript išteklių '{{resourceTitle}}'?", + "delete-javascript-resources-action-title": "Ištrinti JavaScript { count, plural, =1 {1 išteklių} other {# išteklius} }", + "delete-javascript-resources-text": "Atkreipkite dėmesį, kad pasirinkti JavaScript ištekliai, net jei jie naudojami JavaScript funkcijose, bus ištrinti.", + "delete-javascript-resources-title": "Ar tikrai norite ištrinti JavaScript { count, plural, =1 {1 išteklių} other {# išteklius} }?", + "delete-javascript-resource-in-use-text": "Jei vis tiek norite ištrinti šį JavaScript išteklių, spustelėkite mygtuką Ištrinti vis tiek.", + "download": "Atsisiųsti JavaScript išteklių", + "upload-from-file": "Įkelti JavaScript iš failo", + "resource-file": "JavaScript ištekliaus failas", + "drop-file": "Įmeskite JavaScript failą arba spustelėkite, kad pasirinktumėte failą įkėlimui.", + "drop-resource-file-or": "Vilkite ir numeskite JavaScript failą arba", + "javascript-library": "JavaScript biblioteka", + "javascript-type": "JavaScript tipas", + "javascript-resource-details": "JavaScript ištekliaus detalės", + "javascript-resource-is-in-use": "JavaScript išteklius naudojamas kituose objektuose", + "javascript-resources-are-in-use": "JavaScript ištekliai naudojami kituose objektuose", + "javascript-resource-is-in-use-text": "JavaScript išteklius '{{title}}' nebuvo ištrintas, nes jį naudoja šie objektai:", + "javascript-resources-are-in-use-text": "Ne visi JavaScript ištekliai buvo ištrinti, nes jie naudojami kituose objektuose.
Galite peržiūrėti susijusius objektus spustelėdami mygtuką Nuorodos atitinkamoje eilutėje.
Jei vis tiek norite ištrinti šiuos JavaScript išteklius, pasirinkite juos lentelėje ir spustelėkite mygtuką Ištrinti pasirinktus.", + "search": "Ieškoti JavaScript išteklių", + "selected-javascript-resources": "{ count, plural, =1 {1 JavaScript išteklius} other {# JavaScript ištekliai} } pasirinkta", + "no-javascript-resource-text": "JavaScript išteklių nerasta", + "all-types": "Visi", + "module-script": "Modulio scenarijus" + }, + "rpc": { + "error": { + "target-device-is-not-set": "Tikslinis įrenginys nenustatytas!", + "invalid-target-entity": "RPC komandos nepalaikomos {{entityType}} objektui.", + "failed-to-resolve-target-device": "Nepavyko nustatyti tikslo įrenginio!", + "request-timeout": "Užklausos laikas baigėsi", + "rpc-http-error": "Klaida: {{status}} - {{statusText}}" + } + }, + "rulechain": { + "rulechain": "Taisyklių grandinė", + "rulechain-events": "Taisyklių grandinės įvykiai", + "rulechains": "Taisyklių grandinės", + "root": "Pagrindinė", + "delete": "Ištrinti taisyklių grandinę", + "name": "Pavadinimas", + "name-required": "Pavadinimas yra privalomas.", + "name-max-length": "Pavadinimas turi būti trumpesnis nei 256 simboliai", + "description": "Aprašymas", + "add": "Pridėti taisyklių grandinę", + "set-root": "Padaryti pagrindine", + "set-root-rulechain-title": "Ar tikrai norite taisyklių grandinę '{{ruleChainName}}' padaryti pagrindine?", + "set-root-rulechain-text": "Patvirtinus ši taisyklių grandinė taps pagrindine ir tvarkys visus įeinančius transporto pranešimus.", + "delete-rulechain-title": "Ar tikrai norite ištrinti taisyklių grandinę '{{ruleChainName}}'?", + "delete-rulechain-text": "Atsargiai, po patvirtinimo ši taisyklių grandinė ir visi susiję duomenys bus negrįžtamai pašalinti.", + "delete-rulechains-title": "Ar tikrai norite ištrinti { count, plural, =1 {1 taisyklių grandinę} other {# taisyklių grandines} }?", + "delete-rulechains-action-title": "Ištrinti { count, plural, =1 {1 taisyklių grandinę} other {# taisyklių grandines} }", + "delete-rulechains-text": "Atsargiai, po patvirtinimo visos pažymėtos taisyklių grandinės bus pašalintos ir visi susiję duomenys bus prarasti.", + "add-rulechain-text": "Pridėti naują taisyklių grandinę", + "no-rulechains-text": "Taisyklių grandinių nerasta", + "rulechain-details": "Taisyklių grandinės detalės", + "details": "Detalės", + "events": "Įvykiai", + "system": "Sistema", + "import": "Importuoti taisyklių grandinę", + "export": "Eksportuoti taisyklių grandinę", + "export-failed-error": "Nepavyko eksportuoti taisyklių grandinės: {{error}}", + "create-new-rulechain": "Sukurti naują taisyklių grandinę", + "rulechain-file": "Taisyklių grandinės failas", + "invalid-rulechain-file-error": "Nepavyko importuoti taisyklių grandinės: netinkama duomenų struktūra.", + "copyId": "Kopijuoti taisyklių grandinės ID", + "idCopiedMessage": "Taisyklių grandinės ID nukopijuotas į iškarpinę", + "select-rulechain": "Pasirinkti taisyklių grandinę", + "no-rulechains-matching": "Taisyklių grandinių, atitinkančių '{{entity}}', nerasta.", + "rulechain-required": "Taisyklių grandinė yra privaloma", + "management": "Taisyklių valdymas", + "debug-mode": "Derinimo režimas", + "search": "Ieškoti taisyklių grandinių", + "selected-rulechains": "{ count, plural, =1 {1 taisyklių grandinė} other {# taisyklių grandinės} } pasirinkta", + "open-rulechain": "Atidaryti taisyklių grandinę", + "edge-template-root": "Edge šablono pagrindas", + "assign-to-edge": "Priskirti Edge", + "edge-rulechain": "Edge taisyklių grandinė", + "unassign-rulechain-from-edge-text": "Patvirtinus, taisyklių grandinė bus atšaukta ir nebebus pasiekiama Edge įrenginiui.", + "unassign-rulechains-from-edge-title": "Ar tikrai norite atšaukti { count, plural, =1 {1 taisyklių grandinę} other {# taisyklių grandines} }?", + "unassign-rulechains-from-edge-text": "Patvirtinus visos pažymėtos taisyklių grandinės bus atšauktos ir nebebus prieinamos Edge įrenginiui.", + "assign-rulechain-to-edge-title": "Priskirti taisyklių grandinę (-es) Edge įrenginiui", + "assign-rulechain-to-edge-text": "Pasirinkite taisyklių grandines, kurias norite priskirti Edge įrenginiui", + "set-edge-template-root-rulechain": "Padaryti taisyklių grandinę Edge šablono pagrindine", + "set-edge-template-root-rulechain-title": "Ar tikrai norite taisyklių grandinę '{{ruleChainName}}' padaryti Edge šablono pagrindine?", + "set-edge-template-root-rulechain-text": "Patvirtinus ši taisyklių grandinė taps pagrindine naujai kuriamiems Edge įrenginiams.", + "invalid-rulechain-type-error": "Nepavyko importuoti taisyklių grandinės: netinkamas tipas. Tikimasi tipo {{expectedRuleChainType}}.", + "set-auto-assign-to-edge": "Automatiškai priskirti taisyklių grandinę Edge įrenginiams kūrimo metu", + "set-auto-assign-to-edge-title": "Ar tikrai norite automatiškai priskirti Edge taisyklių grandinę '{{ruleChainName}}' naujai kuriamiems Edge įrenginiams?", + "set-auto-assign-to-edge-text": "Patvirtinus ši taisyklių grandinė bus automatiškai priskiriama Edge įrenginiams jų kūrimo metu.", + "unset-auto-assign-to-edge": "Nepriskirti taisyklių grandinės Edge įrenginiams kūrimo metu", + "unset-auto-assign-to-edge-title": "Ar tikrai nenorite automatiškai priskirti Edge taisyklių grandinės '{{ruleChainName}}' naujai kuriamiems Edge įrenginiams?", + "unset-auto-assign-to-edge-text": "Patvirtinus ši taisyklių grandinė nebus automatiškai priskiriama Edge įrenginiams.", + "unassign-rulechain-title": "Ar tikrai norite atšaukti taisyklių grandinę '{{ruleChainName}}'?", + "unassign-rulechains": "Atšaukti taisyklių grandines" + }, + "rulenode": { + "rule-node-events": "Taisyklių mazgų įvykiai", + "details": "Detalės", + "events": "Įvykiai", + "search": "Ieškoti mazgų", + "open-node-library": "Atidaryti mazgų biblioteką", + "close-node-library": "Uždaryti mazgų biblioteką", + "add": "Pridėti taisyklės mazgą", + "name": "Pavadinimas", + "name-required": "Pavadinimas yra privalomas.", + "name-max-length": "Pavadinimas turi būti trumpesnis nei 256 simboliai", + "type": "Tipas", + "rule-node-description": "Taisyklių mazgo aprašymas", + "delete": "Ištrinti taisyklės mazgą", + "select-all-objects": "Pažymėti visus mazgus ir jungtis", + "deselect-all-objects": "Atžymėti visus mazgus ir jungtis", + "delete-selected-objects": "Ištrinti pažymėtus mazgus ir jungtis", + "delete-selected": "Ištrinti pažymėtus", + "create-nested-rulechain": "Sukurti įdėtą taisyklių grandinę", + "select-all": "Pažymėti visus", + "copy-selected": "Kopijuoti pažymėtus", + "deselect-all": "Atžymėti visus", + "rulenode-details": "Taisyklių mazgo detalės", + "debug-mode": "Derinimo režimas", + "singleton": "Vienetinis (Singleton)", + "configuration": "Konfigūracija", + "link": "Jungtis", + "link-details": "Taisyklių mazgo jungties detalės", + "add-link": "Pridėti jungtį", + "link-label": "Jungties pavadinimas", + "link-label-required": "Jungties pavadinimas yra privalomas.", + "custom-link-label": "Tinkintas jungties pavadinimas", + "custom-link-label-required": "Tinkintas jungties pavadinimas yra privalomas.", + "link-labels": "Jungčių pavadinimai", + "link-labels-required": "Jungčių pavadinimai yra privalomi.", + "no-link-labels-found": "Jungčių pavadinimų nerasta", + "no-link-label-matching": "Jungtis '{{label}}' nerasta.", + "create-new-link-label": "Sukurti naują!", + "type-filter": "Filtras", + "type-filter-details": "Filtruoti įeinančias žinutes pagal konfigūruotas sąlygas", + "type-enrichment": "Praturtinimas", + "type-enrichment-details": "Papildyti žinutės metaduomenis papildoma informacija", + "type-transformation": "Transformacija", + "type-transformation-details": "Keisti žinutės turinį arba metaduomenis", + "type-action": "Veiksmas", + "type-action-details": "Atlikti specialų veiksmą", + "type-external": "Išorinis", + "type-external-details": "Sąveikauja su išorine sistema", + "type-rule-chain": "Taisyklių grandinė", + "type-rule-chain-details": "Perduoda įeinančias žinutes nurodytai taisyklių grandinei", + "type-flow": "Srautas", + "type-flow-details": "Organizuoja žinučių srautą", + "type-input": "Įvestis", + "type-input-details": "Taisyklių grandinės loginė įvestis, perduodanti žinutes tolesniam susijusiam mazgui", + "type-unknown": "Nežinomas", + "type-unknown-details": "Nesprendžiamas taisyklių mazgas", + "directive-is-not-loaded": "Nurodyta konfigūracijos direktyva '{{directiveName}}' nėra prieinama.", + "ui-resources-load-error": "Nepavyko įkelti konfigūracijos UI išteklių.", + "invalid-target-rulechain": "Nepavyko nustatyti paskirties taisyklių grandinės!", + "test-script-function": "Testuoti skripto funkciją", + "script-lang-java-script": "JavaScript", + "script-lang-tbel": "TBEL", + "message": "Žinutė", + "message-type": "Žinutės tipas", + "select-message-type": "Pasirinkti žinutės tipą", + "message-type-required": "Žinutės tipas yra privalomas", + "metadata": "Metaduomenys", + "metadata-required": "Metaduomenų įrašai negali būti tušti.", + "output": "Išvestis", + "test": "Testuoti", + "help": "Pagalba", + "reset-debug-settings": "Atstatyti derinimo nustatymus visuose mazguose", + "test-with-this-message": "{{test}} su šia žinute", + "queue-hint": "Pasirinkite eilę, į kurią bus persiunčiamos žinutės. Numatytoji eilė – 'Main'.", + "queue-singleton-hint": "Pasirinkite eilę žinučių perdavimui kelių egzempliorių aplinkoje. Numatytoji eilė – 'Pagrindinis'." + }, + "rule-node-config": { + "id": "Id", + "additional-info": "Papildoma informacija", + "advanced-settings": "Išplėstiniai nustatymai", + "create-entity-if-not-exists": "Sukurti naują objektą, jei jis neegzistuoja", + "create-entity-if-not-exists-hint": "Jei įjungta, naujas objektas su nurodytais parametrais bus sukurtas, nebent toks jau egzistuoja. Esami objektai bus naudojami tokie, kokie yra, ryšio užmezgimui.", + "select-device-connectivity-event": "Pasirinkite įrenginio ryšio įvykį", + "entity-name-pattern": "Pavadinimo šablonas", + "device-name-pattern": "Įrenginio pavadinimas", + "asset-name-pattern": "Turto pavadinimas", + "entity-view-name-pattern": "Objekto peržiūros pavadinimas", + "customer-title-pattern": "Kliento pavadinimas", + "dashboard-name-pattern": "Valdymo skydelio pavadinimas", + "user-name-pattern": "Naudotojo el. paštas", + "edge-name-pattern": "Edge pavadinimas", + "entity-name-pattern-required": "Pavadinimo šablonas yra privalomas", + "entity-name-pattern-hint": "Pavadinimo šablono laukas palaiko šablonizaciją. Naudokite $[messageKey], kad gautumėte reikšmę iš pranešimo, ir ${metadataKey}, kad gautumėte reikšmę iš metaduomenų.", + "copy-message-type": "Kopijuoti pranešimo tipą", + "entity-type-pattern": "Tipo šablonas", + "entity-type-pattern-required": "Tipo šablonas yra privalomas", + "message-type-value": "Pranešimo tipo reikšmė", + "message-type-value-required": "Pranešimo tipo reikšmė yra privaloma", + "message-type-value-max-length": "Pranešimo tipo reikšmė turi būti trumpesnė nei 256 simboliai", + "output-message-type": "Išvesties pranešimo tipas", + "entity-cache-expiration": "Objektų talpyklos galiojimo laikas (sek.)", + "entity-cache-expiration-hint": "Nurodo maksimalų laiką, kiek galima saugoti rastų objektų įrašus. Reikšmė 0 reiškia, kad įrašai niekada nesibaigs.", + "entity-cache-expiration-required": "Objektų talpyklos galiojimo laikas yra privalomas.", + "entity-cache-expiration-range": "Objektų talpyklos galiojimo laikas turi būti didesnis arba lygus 0.", + "customer-name-pattern": "Kliento pavadinimas", + "customer-name-pattern-required": "Kliento pavadinimas yra privalomas", + "customer-name-pattern-hint": "Naudokite $[messageKey], kad gautumėte reikšmę iš pranešimo, ir ${metadataKey}, kad gautumėte reikšmę iš metaduomenų.", + "create-customer-if-not-exists": "Sukurti naują klientą, jei jis neegzistuoja", + "unassign-from-customer": "Atšaukti priskyrimą klientui, jei siuntėjas yra valdymo skydelis", + "unassign-from-customer-tooltip": "Tik valdymo skydeliai gali būti priskirti keliems klientams vienu metu.\nJei pranešimo siuntėjas yra valdymo skydelis, turite aiškiai nurodyti kliento pavadinimą, kad jį atšauktumėte.", + "customer-cache-expiration": "Klientų talpyklos galiojimo laikas (sek.)", + "customer-cache-expiration-hint": "Nurodo maksimalų laiką, kiek galima saugoti rastų klientų įrašus. Reikšmė 0 reiškia, kad įrašai niekada nesibaigs.", + "customer-cache-expiration-required": "Klientų talpyklos galiojimo laikas yra privalomas.", + "customer-cache-expiration-range": "Klientų talpyklos galiojimo laikas turi būti didesnis arba lygus 0.", + "interval-start": "Intervalo pradžia", + "interval-end": "Intervalo pabaiga", + "time-unit": "Laiko vienetas", + "fetch-mode": "Gavimo režimas", + "order-by-timestamp": "Rikiuoti pagal laiko žymą", + "limit": "Riba", + "limit-hint": "Mažiausia riba – 2, didžiausia – 1000. Jei norite gauti vieną įrašą, pasirinkite gavimo režimą 'Pirmas' arba 'Paskutinis'.", + "limit-required": "Riba yra privaloma.", + "limit-range": "Riba turi būti nuo 2 iki 1000.", + "time-unit-milliseconds": "Milisekundės", + "time-unit-seconds": "Sekundės", + "time-unit-minutes": "Minutės", + "time-unit-hours": "Valandos", + "time-unit-days": "Dienos", + "time-value-range": "Leidžiamas diapazonas nuo 1 iki 2147483647.", + "start-interval-value-required": "Intervalo pradžia yra privaloma.", + "end-interval-value-required": "Intervalo pabaiga yra privaloma.", + "filter": "Filtras", + "switch": "Perjungiklis", + "math-templatization-tooltip": "Šis laukas palaiko šablonizaciją. Naudokite $[messageKey], kad gautumėte reikšmę iš pranešimo, ir ${metadataKey}, kad gautumėte reikšmę iš metaduomenų.", + "add-message-type": "Pridėti pranešimo tipą", + "select-message-types-required": "Turi būti pasirinktas bent vienas pranešimo tipas.", + "select-message-types": "Pasirinkti pranešimo tipus", + "no-message-types-found": "Pranešimo tipų nerasta", + "no-message-type-matching": "'{{messageType}}' nerasta.", + "create-new-message-type": "Sukurti naują.", + "message-types-required": "Pranešimo tipai yra privalomi.", + "client-attributes": "Kliento atributai", + "shared-attributes": "Bendri atributai", + "server-attributes": "Serverio atributai", + "attributes-keys": "Atributų raktai", + "attributes-keys-required": "Atributų raktai yra privalomi", + "attributes-scope": "Atributų sritis", + "attributes-scope-value": "Atributų srities reikšmė", + "attributes-scope-value-copy": "Kopijuoti atributų srities reikšmę", + "attributes-scope-hint": "Naudokite metaduomenų raktą 'scope', kad dinamiškai nustatytumėte atributų sritį kiekvienam pranešimui. Jei pateikta, tai perrašo konfigūracijoje nustatytą sritį.", + "notify-device": "Priverstinai pranešti įrenginiui", + "send-attributes-updated-notification": "Siųsti atnaujintų atributų pranešimą", + "send-attributes-updated-notification-hint": "Siųsti pranešimą apie atnaujintus atributus kaip atskirą žinutę į taisyklių variklio eilę.", + "send-attributes-deleted-notification": "Siųsti ištrintų atributų pranešimą", + "send-attributes-deleted-notification-hint": "Siųsti pranešimą apie ištrintus atributus kaip atskirą žinutę į taisyklių variklio eilę.", + "update-attributes-only-on-value-change": "Išsaugoti atributus tik jei pasikeitė reikšmė", + "update-attributes-only-on-value-change-hint": "Atnaujina atributus su kiekvienu gaunamu pranešimu, neatsižvelgiant į tai, ar reikšmė pasikeitė. Tai padidina API apkrovą ir sumažina našumą.", + "update-attributes-only-on-value-change-hint-enabled": "Atnaujina atributus tik jei jų reikšmė pasikeitė. Jei reikšmė nepasikeitė, atributų laiko žyma ir pranešimas apie pakeitimą nebus siunčiami.", + "fetch-credentials-to-metadata": "Įtraukti prisijungimo duomenis į metaduomenis", + "notify-device-on-update-hint": "Jei įjungta, priverstinai praneša įrenginiui apie bendrų atributų atnaujinimą. Jei išjungta, pranešimo elgesį valdo 'notifyDevice' parametras iš gaunamo pranešimo metaduomenų. Norėdami išjungti pranešimą, pranešimo metaduomenyse turi būti parametras 'notifyDevice' nustatytas į 'false'. Kitais atvejais pranešimas bus siunčiamas įrenginiui.", + "notify-device-on-delete-hint": "Jei įjungta, priverstinai praneša įrenginiui apie bendrų atributų pašalinimą. Jei išjungta, pranešimo elgesį valdo 'notifyDevice' parametras iš gaunamo pranešimo metaduomenų. Norėdami įjungti pranešimą, pranešimo metaduomenyse turi būti parametras 'notifyDevice' nustatytas į 'true'. Kitais atvejais pranešimas įrenginiui nebus siunčiamas.", + "latest-timeseries": "Naujausių laiko eilučių duomenų raktai", + "timeseries-keys": "Laiko eilučių raktai", + "timeseries-keys-required": "Turi būti pasirinktas bent vienas laiko eilučių raktas.", + "add-timeseries-key": "Pridėti laiko eilučių raktą", + "add-message-field": "Pridėti pranešimo lauką", + "relation-search-parameters": "Ryšių paieškos parametrai", + "relation-parameters": "Ryšių parametrai", + "add-metadata-field": "Pridėti metaduomenų lauką", + "data-keys": "Pranešimo laukų pavadinimai", + "copy-from": "Kopijuoti iš", + "data-to-metadata": "Duomenis į metaduomenis", + "metadata-to-data": "Metaduomenis į duomenis", + "use-regular-expression-hint": "Naudokite reguliariąją išraišką raktų kopijavimui pagal šabloną.\n\nPatarimai:\nPaspauskite 'Enter', kad užbaigtumėte lauko pavadinimo įvedimą.\nPaspauskite 'Backspace', kad ištrintumėte lauko pavadinimą. Palaikomi keli pavadinimai.", + "interval": "Intervalas", + "interval-required": "Intervalas yra privalomas", + "interval-hint": "Dublikavimo intervalas sekundėmis.", + "interval-min-error": "Mažiausia leidžiama reikšmė yra 1", + "max-pending-msgs": "Maks. laukiančių pranešimų", + "max-pending-msgs-hint": "Maksimalus pranešimų skaičius, saugomas atmintyje kiekvienam unikaliam dublikavimo ID.", + "max-pending-msgs-required": "Maks. laukiančių pranešimų reikšmė yra privaloma", + "max-pending-msgs-max-error": "Didžiausia leidžiama reikšmė yra 1000", + "max-pending-msgs-min-error": "Mažiausia leidžiama reikšmė yra 1", + "max-retries": "Maksimalus bandymų skaičius", + "max-retries-required": "Maksimalus bandymų skaičius yra privalomas", + "max-retries-hint": "Didžiausias bandymų skaičius išsiųsti dublikuotus pranešimus į eilę. Tarp bandymų taikomas 10 sekundžių delsimas.", + "max-retries-max-error": "Didžiausia leidžiama reikšmė yra 100", + "max-retries-min-error": "Mažiausia leidžiama reikšmė yra 0", + "strategy": "Strategija", + "strategy-required": "Strategija yra privaloma", + "strategy-all-hint": "Grąžina visus pranešimus, gautus dublikavimo laikotarpiu, kaip vieną JSON masyvą, kur kiekvienas elementas turi objektą su 'msg' ir 'metadata' savybėmis.", + "strategy-first-hint": "Grąžina pirmą pranešimą, gautą dublikavimo laikotarpiu.", + "strategy-last-hint": "Grąžina paskutinį pranešimą, gautą dublikavimo laikotarpiu.", + "first": "Pirmas", + "last": "Paskutinis", + "all": "Visi", + "output-msg-type-hint": "Dublikavimo rezultato pranešimo tipas.", + "queue-name-hint": "Eilės pavadinimas, į kurią bus publikuojamas dublikavimo rezultatas.", + "keys": "Raktai", + "keys-required": "Raktai yra privalomi", + "rename-keys-in": "Pervadinti raktus", + "data": "Duomenys", + "message": "Pranešimas", + "metadata": "Metaduomenys", + "current-key-name": "Dabartinis rakto pavadinimas", + "key-name-required": "Rakto pavadinimas yra privalomas", + "new-key-name": "Naujas rakto pavadinimas", + "new-key-name-required": "Naujas rakto pavadinimas yra privalomas", + "metadata-keys": "Metaduomenų laukų pavadinimai", + "json-path-expression": "JSON kelio išraiška", + "json-path-expression-required": "JSON kelio išraiška yra privaloma", + "json-path-expression-hint": "JSONPath nurodo kelią į elementą arba elementų rinkinį JSON struktūroje. '$' reiškia šakninį objektą arba masyvą.", + "relations-query": "Ryšių užklausa", + "device-relations-query": "Įrenginio ryšių užklausa", + "max-relation-level": "Didžiausias ryšių lygis", + "max-relation-level-error": "Reikšmė turi būti didesnė nei 0 arba nenustatyta.", + "max-relation-level-invalid": "Reikšmė turi būti sveikasis skaičius.", + "relation-type": "Ryšio tipas", + "relation-type-pattern": "Ryšio tipo šablonas", + "relation-type-pattern-required": "Ryšio tipo šablonas yra privalomas", + "relation-types-list": "Ryšių tipai, kuriuos reikia perduoti", + "relation-types-list-hint": "Jei nepasirinkti ryšių tipai, signalai (alarmai) bus perduodami be filtravimo pagal ryšio tipą.", + "unlimited-level": "Neribotas lygis", + "latest-telemetry": "Naujausia telemetrija", + "add-telemetry-key": "Pridėti telemetrijos raktą", + "delete-from": "Ištrinti iš", + "use-regular-expression-delete-hint": "Naudokite reguliariąją išraišką raktų ištrynimui pagal šabloną.\n\nPatarimai:\nPaspauskite 'Enter', kad užbaigtumėte lauko pavadinimo įvedimą.\nPaspauskite 'Backspace', kad ištrintumėte lauko pavadinimą.\nPalaikomi keli pavadinimai.", + "fetch-into": "Užkrauti į", + "attr-mapping": "Atributų susiejimas:", + "source-attribute": "Pirminio atributo raktas", + "source-attribute-required": "Pirminio atributo raktas yra privalomas.", + "source-telemetry": "Pirminės telemetrijos raktas", + "source-telemetry-required": "Pirminės telemetrijos raktas yra privalomas.", + "target-key": "Tikslinis raktas", + "target-key-required": "Tikslinis raktas yra privalomas.", + "attr-mapping-required": "Turi būti nurodyta bent viena susiejimo eilutė.", + "fields-mapping": "Laukų susiejimas", + "fields-mapping-hint": "Jei pranešimo laukas nustatytas į $entityId, pranešimo kilmės (originatoriaus) ID bus įrašytas į nurodytą lentelės stulpelį.", + "relations-query-config-direction-suffix": "kilmės objektas", + "profile-name": "Profilio pavadinimas", + "fetch-circle-parameter-info-from-metadata-hint": "Metaduomenų laukas '{{perimeterKeyName}}' turi būti pateiktas šiuo formatu: {\"latitude\":48.196, \"longitude\":24.6532, \"radius\":100.0, \"radiusUnit\":\"METER\"}", + "fetch-poligon-parameter-info-from-metadata-hint": "Metaduomenų laukas '{{perimeterKeyName}}' turi būti pateiktas šiuo formatu: [[48.19736,24.65235],[48.19800,24.65060],...,[48.19849,24.65420]]", + "short-templatization-tooltip": "Naudokite $[messageKey], kad gautumėte reikšmę iš pranešimo, ir ${metadataKey}, kad gautumėte reikšmę iš metaduomenų.", + "fields-mapping-required": "Turi būti nurodytas bent vienas laukų susiejimas.", + "at-least-one-field-required": "Bent vienas įvesties laukas turi turėti reikšmę (-es).", + "originator-fields-sv-map-hint": "Tikslinių raktų laukai palaiko šablonizaciją. Naudokite $[messageKey], kad gautumėte reikšmę iš pranešimo, ir ${metadataKey}, kad gautumėte reikšmę iš metaduomenų.", + "sv-map-hint": "Tik tikslinių raktų laukai palaiko šablonizaciją. Naudokite $[messageKey], kad gautumėte reikšmę iš pranešimo, ir ${metadataKey}, kad gautumėte reikšmę iš metaduomenų.", + "source-field": "Pirminis laukas", + "source-field-required": "Pirminis laukas yra privalomas.", + "originator-source": "Kilmės šaltinis", + "new-originator": "Naujas kilmės objektas", + "originator-customer": "Klientas", + "originator-tenant": "Nuomininkas", + "originator-related": "Susijęs objektas", + "originator-alarm-originator": "Signalo kilmės objektas", + "originator-entity": "Objektas pagal pavadinimo šabloną", + "clone-message": "Klonuoti pranešimą", + "transform": "Transformuoti", + "default-ttl": "Numatytasis TTL", + "default-ttl-required": "Numatytasis TTL yra privalomas.", + "default-ttl-hint": "Taisyklės mazgas (Rule Node) paims Time-to-Live (TTL) reikšmę iš pranešimo metaduomenų. Jei reikšmės nėra, bus naudojamas konfigūracijoje nurodytas TTL. Jei reikšmė lygi 0, bus taikomas TTL iš nuomininko (Tenant) profilio konfigūracijos.", + "default-ttl-zero-hint": "TTL nebus taikomas, jei jo reikšmė nustatyta į 0.", + "min-default-ttl-message": "Leidžiama tik minimali 0 TTL reikšmė.", + "generation-parameters": "Generavimo parametrai", + "message-count": "Generuojamų pranešimų limitas (0 - neribota)", + "message-count-required": "Generuojamų pranešimų limitas yra privalomas.", + "min-message-count-message": "Leidžiama tik minimali 0 pranešimų reikšmė.", + "period-seconds": "Periodas sekundėmis", + "period-seconds-required": "Periodas yra privalomas.", + "generation-frequency-seconds": "Generavimo dažnis sekundėmis", + "generation-frequency-required": "Generavimo dažnis yra privalomas.", + "min-generation-frequency-message": "Leidžiamas mažiausias 60 sekundžių intervalas.", + "script-lang-tbel": "TBEL", + "script-lang-js": "JS", + "use-metadata-period-in-seconds-patterns": "Naudoti periodo sekundėmis šabloną", + "use-metadata-period-in-seconds-patterns-hint": "Jei pasirinkta, taisyklės mazgas naudos periodo sekundėmis šabloną iš pranešimo metaduomenų arba duomenų, laikydamas, kad intervalai pateikti sekundėmis.", + "period-in-seconds-pattern": "Periodo sekundėmis šablonas", + "period-in-seconds-pattern-required": "Periodo sekundėmis šablonas yra privalomas", + "min-period-seconds-message": "Leidžiamas mažiausias 60 sekundžių periodas.", + "originator": "Kilmės objektas", + "message-body": "Pranešimo turinys", + "message-metadata": "Pranešimo metaduomenys", + "generate": "Generuoti", + "current-rule-node": "Dabartinis taisyklės mazgas", + "current-tenant": "Dabartinis nuomininkas", + "generator-function": "Generatoriaus funkcija", + "test-generator-function": "Testuoti generatoriaus funkciją", + "generator": "Generatorius", + "test-filter-function": "Testuoti filtravimo funkciją", + "test-switch-function": "Testuoti perjungimo funkciją", + "test-transformer-function": "Testuoti transformavimo funkciją", + "transformer": "Transformatorius", + "alarm-create-condition": "Signalo (aliarmo) sukūrimo sąlyga", + "test-condition-function": "Testuoti sąlygos funkciją", + "alarm-clear-condition": "Signalo (aliarmo) išvalymo sąlyga", + "alarm-details-builder": "Signalo (aliarmo) informacijos kūrėjas", + "test-details-function": "Testuoti informacijos kūrimo funkciją", + "alarm-type": "Signalo tipas", + "select-entity-types": "Pasirinkti objektų tipus", + "alarm-type-required": "Signalo tipas yra privalomas.", + "alarm-severity": "Signalo svarba", + "alarm-severity-required": "Signalo svarba yra privaloma", + "alarm-severity-pattern": "Signalo svarbos šablonas", + "alarm-status-filter": "Signalo būsenos filtras", + "alarm-status-list-empty": "Signalo būsenų sąrašas tuščias", + "no-alarm-status-matching": "Nerasta atitinkančių signalo būsenų.", + "propagate": "Perduoti signalą susijusiems objektams", + "propagate-to-owner": "Perduoti signalą objekto savininkui (klientui arba nuomininkui)", + "propagate-to-tenant": "Perduoti signalą nuomininkui", + "condition": "Sąlyga", + "details": "Išsami informacija", + "to-string": "Į eilutę (string)", + "test-to-string-function": "Testuoti konvertavimo į eilutę funkciją", + "from-template": "Iš", + "from-template-required": "Laukas „Iš“ yra privalomas", + "message-to-metadata": "Pranešimą į metaduomenis", + "metadata-to-message": "Metaduomenis į pranešimą", + "from-message": "Iš pranešimo", + "from-metadata": "Iš metaduomenų", + "to-template": "Į", + "to-template-required": "Laukas „Į šabloną“ yra privalomas", + "mail-address-list-template-hint": "Adreso sąrašas atskiriamas kableliais. Naudokite ${metadataKey} reikšmėms iš metaduomenų ir $[messageKey] reikšmėms iš pranešimo turinio gauti.", + "cc-template": "Kopija (Cc)", + "bcc-template": "Slapta kopija (Bcc)", + "subject-template": "Tema", + "subject-template-required": "Temos šablonas yra privalomas", + "body-template": "Turinys", + "body-template-required": "Turinio šablonas yra privalomas", + "dynamic-mail-body-type": "Dinaminio el. laiško turinio tipas", + "mail-body-type": "El. laiško turinio tipas", + "body-type-template": "Turinio tipo šablonas", + "reply-routing-configuration": "Atsakymų nukreipimo konfigūracija", + "rpc-reply-routing-configuration-hint": "Šie konfigūracijos parametrai nurodo metaduomenų raktų pavadinimus, naudojamus paslaugos, sesijos ir užklausos identifikavimui siunčiant atsakymą atgal.", + "reply-routing-configuration-hint": "Šie konfigūracijos parametrai nurodo metaduomenų raktų pavadinimus, naudojamus paslaugos ir užklausos identifikavimui siunčiant atsakymą atgal.", + "request-id-metadata-attribute": "Užklausos ID", + "service-id-metadata-attribute": "Paslaugos ID", + "session-id-metadata-attribute": "Sesijos ID", + "timeout-sec": "Laiko limitas (sekundėmis)", + "timeout-required": "Laiko limitas yra privalomas", + "min-timeout-message": "Leidžiama tik minimali 0 laiko limito reikšmė.", + "endpoint-url-pattern": "Galutinio taško (endpoint) URL šablonas", + "endpoint-url-pattern-required": "Galutinio taško (endpoint) URL šablonas yra privalomas", + "request-method": "Užklausos metodas", + "use-simple-client-http-factory": "Naudoti paprastą HTTP kliento kūrimo būdą", + "ignore-request-body": "Be užklausos turinio", + "parse-to-plain-text": "Konvertuoti į gryną tekstą", + "parse-to-plain-text-hint": "Jei pasirinkta, užklausos turinys bus konvertuotas iš JSON eilutės į paprastą tekstą, pvz., msg = \"Hello,\\t\"world\"\" bus konvertuota į Hello, \"world\"", + "read-timeout": "Skaitymo laiko limitas (milisekundėmis)", + "read-timeout-hint": "Reikšmė 0 reiškia neribotą laiko limitą", + "max-parallel-requests-count": "Maksimalus lygiagrečių užklausų skaičius", + "max-parallel-requests-count-hint": "Reikšmė 0 nurodo, kad lygiagretus apdorojimas nėra ribojamas", + "max-response-size": "Maksimalus atsako dydis (KB)", + "max-response-size-hint": "Didžiausias atminties kiekis, skirtas duomenų buferiavimui dekoduojant ar koduojant HTTP pranešimus, pvz., JSON ar XML turinius", + "headers": "Antraštės (Headers)", + "headers-hint": "Naudokite ${metadataKey} reikšmėms iš metaduomenų ir $[messageKey] reikšmėms iš pranešimo turinio antraščių/vertės laukuose", + "header": "Antraštė", + "header-required": "Antraštė yra privaloma", + "value": "Reikšmė", + "value-required": "Reikšmė yra privaloma", + "topic-pattern": "Temos šablonas", + "key-pattern": "Rakto šablonas", + "key-pattern-hint": "Nebūtina. Jei nurodytas galiojantis skaidinio (partition) numeris, jis bus naudojamas siunčiant įrašą. Jei skaidinys nenurodytas, bus naudojamas raktas. Jei abu nėra nurodyti – bus priskiriama apvaliuoju būdu (round-robin).", + "topic-pattern-required": "Temos šablonas yra privalomas", + "topic": "Tema", + "topic-required": "Tema yra privaloma", + "bootstrap-servers": "Bootstrap serveriai", + "bootstrap-servers-required": "Bootstrap serverių reikšmė yra privaloma", + "other-properties": "Kitos savybės", + "key": "Raktas", + "key-required": "Raktas yra privalomas", + "retries": "Automatinio bandymo kartai, jei nepavyksta", + "min-retries-message": "Leidžiama tik minimali 0 pakartojimų reikšmė.", + "batch-size-bytes": "Siunčiamo paketo dydis baitais", + "min-batch-size-bytes-message": "Leidžiama tik minimali 0 paketo dydžio reikšmė.", + "linger-ms": "Buferiavimo laikas vietoje (ms)", + "min-linger-ms-message": "Leidžiama tik minimali 0 ms reikšmė.", + "buffer-memory-bytes": "Maksimalus kliento buferio dydis baitais", + "min-buffer-memory-message": "Leidžiama tik minimali 0 buferio dydžio reikšmė.", + "memory-buffer-size-range": "Atminties buferio dydis turi būti nuo 0 iki {{max}} KB", + "acks": "Patvirtinimų skaičius (ACKs)", + "topic-arn-pattern": "Temos ARN šablonas", + "topic-arn-pattern-required": "Temos ARN šablonas yra privalomas", + "aws-access-key-id": "AWS prieigos rakto ID (Access Key ID)", + "aws-access-key-id-required": "AWS prieigos rakto ID yra privalomas", + "aws-secret-access-key": "AWS slaptasis prieigos raktas (Secret Access Key)", + "aws-secret-access-key-required": "AWS slaptasis prieigos raktas yra privalomas", + "aws-region": "AWS regionas", + "aws-region-required": "AWS regionas yra privalomas", + "exchange-name-pattern": "Mainų (Exchange) pavadinimo šablonas", + "routing-key-pattern": "Maršruto rakto (Routing key) šablonas", + "message-properties": "Pranešimo savybės", + "host": "Serveris (Host)", + "host-required": "Serverio adresas yra privalomas", + "port": "Prievadas (Port)", + "port-required": "Prievadas yra privalomas", + "port-range": "Prievadas turi būti nuo 1 iki 65535.", + "virtual-host": "Virtualus serveris (Virtual host)", + "username": "Vartotojo vardas", + "password": "Slaptažodis", + "automatic-recovery": "Automatinis atkūrimas", + "connection-timeout-ms": "Prisijungimo laiko limitas (ms)", + "min-connection-timeout-ms-message": "Leidžiama tik minimali 0 ms reikšmė.", + "handshake-timeout-ms": "Rankos paspaudimo (Handshake) laiko limitas (ms)", + "min-handshake-timeout-ms-message": "Leidžiama tik minimali 0 ms reikšmė.", + "client-properties": "Kliento savybės", + "queue-url-pattern": "Eilės (Queue) URL šablonas", + "queue-url-pattern-required": "Eilės URL šablonas yra privalomas", + "delay-seconds": "Vėlinimas (sekundėmis)", + "min-delay-seconds-message": "Leidžiama tik minimali 0 sekundžių reikšmė.", + "max-delay-seconds-message": "Leidžiama tik maksimali 900 sekundžių reikšmė.", + "name": "Pavadinimas", + "name-required": "Pavadinimas yra privalomas", + "queue-type": "Eilės tipas", + "sqs-queue-standard": "Standartinė", + "sqs-queue-fifo": "FIFO (First-In-First-Out)", + "gcp-project-id": "GCP projekto ID", + "gcp-project-id-required": "GCP projekto ID yra privalomas", + "gcp-service-account-key": "GCP paslaugos paskyros raktas (key file)", + "gcp-service-account-key-required": "GCP paslaugos paskyros raktas yra privalomas", + "pubsub-topic-name": "Temos pavadinimas", + "pubsub-topic-name-required": "Temos pavadinimas yra privalomas", + "message-attributes": "Pranešimo atributai", + "message-attributes-hint": "Naudokite ${metadataKey} reikšmėms iš metaduomenų ir $[messageKey] reikšmėms iš pranešimo turinio nurodyti vardų/vertės laukuose", + "connect-timeout": "Prisijungimo laiko limitas (sekundėmis)", + "connect-timeout-required": "Prisijungimo laiko limitas yra privalomas.", + "connect-timeout-range": "Prisijungimo laiko limitas turi būti nuo 1 iki 200.", + "client-id": "Kliento ID", + "client-id-hint": "Nebūtina. Palikite tuščią, jei ID generuojamas automatiškai. Nurodydami konkretų Client ID būkite atsargūs — dauguma MQTT brokerių neleidžia kelių jungčių su tuo pačiu ID. Jei platforma veikia mikroservisų režimu, kiekvienas servisas paleidžia atskirą šio mazgo (rule node) egzempliorių, todėl dubliuoti ID gali sukelti klaidų. Kad to išvengtumėte, įjunkite „Pridėti paslaugos ID kaip priesagą prie kliento ID“.", + "append-client-id-suffix": "Pridėti paslaugos ID kaip priesagą prie kliento ID", + "client-id-suffix-hint": "Nebūtina. Naudojama, kai „Client ID“ nurodytas rankiniu būdu. Pridėjus paslaugos ID kaip priesagą, išvengiama klaidų mikroservisų architektūroje.", + "device-id": "Įrenginio ID", + "device-id-required": "Įrenginio ID yra privalomas.", + "clean-session": "Švari sesija (Clean session)", + "enable-ssl": "Įjungti SSL", + "credentials": "Autentifikacijos duomenys", + "credentials-type": "Autentifikacijos tipas", + "credentials-type-required": "Autentifikacijos tipas yra privalomas.", + "credentials-anonymous": "Anoniminis", + "credentials-basic": "Paprastas (Basic)", + "credentials-pem": "PEM sertifikatai", + "credentials-pem-hint": "Reikalingas bent Serverio CA sertifikatas arba Kliento sertifikato ir privačiojo rakto pora", + "credentials-sas": "Bendro prieigos parašo (Shared Access Signature)", + "sas-key": "SAS raktas", + "sas-key-required": "SAS raktas yra privalomas.", + "hostname": "Serverio pavadinimas (Hostname)", + "hostname-required": "Serverio pavadinimas yra privalomas.", + "azure-ca-cert": "CA sertifikato failas", + "username-required": "Vartotojo vardas yra privalomas.", + "password-required": "Slaptažodis yra privalomas.", + "ca-cert": "Serverio CA sertifikato failas", + "private-key": "Kliento privataus rakto failas", + "cert": "Kliento sertifikato failas", + "no-file": "Failas nepasirinktas.", + "drop-file": "Nutempkite failą arba spustelėkite, kad pasirinktumėte failą įkėlimui.", + "private-key-password": "Privataus rakto slaptažodis", + "use-system-smtp-settings": "Naudoti sistemos SMTP nustatymus", + "use-metadata-dynamic-interval": "Naudoti dinaminį intervalą", + "metadata-dynamic-interval-hint": "Intervalo pradžios ir pabaigos laukai palaiko šablonizaciją (templatization). Pakeistos reikšmės turi būti milisekundėmis. Naudokite $[messageKey] reikšmei iš pranešimo ir ${metadataKey} reikšmei iš metaduomenų.", + "use-metadata-interval-patterns-hint": "Jei pasirinkta, mazgas (rule node) naudos pradžios ir pabaigos intervalo šablonus iš pranešimo duomenų arba metaduomenų, manydamas, kad intervalai yra milisekundėmis.", + "use-message-alarm-data": "Naudoti pranešimo pavojaus (alarm) duomenis", + "overwrite-alarm-details": "Perrašyti pavojaus detales", + "use-alarm-severity-pattern": "Naudoti pavojaus svarbos (severity) šabloną", + "check-all-keys": "Patikrinti, ar visi nurodyti laukai egzistuoja", + "check-all-keys-hint": "Jei pasirinkta, tikrina, ar visi nurodyti raktai yra pranešimo duomenyse ir metaduomenyse.", + "check-relation-to-specific-entity": "Tikrinti ryšį su konkrečiu objektu", + "check-relation-to-specific-entity-tooltip": "Jei įjungta, tikrinamas ryšio buvimas su konkrečiu objektu, kitu atveju – su bet kuriuo objektu. Abiem atvejais ryšys nustatomas pagal kryptį ir tipą.", + "check-relation-hint": "Tikrina ryšio buvimą su konkrečiu ar bet kuriuo objektu, atsižvelgiant į kryptį ir ryšio tipą.", + "delete-relation-with-specific-entity": "Pašalinti ryšį su konkrečiu objektu", + "delete-relation-with-specific-entity-hint": "Jei įjungta, bus pašalintas tik ryšys su vienu konkrečiu objektu. Kitu atveju, ryšys bus pašalintas su visais atitinkančiais objektais.", + "delete-relation-hint": "Pašalina ryšį tarp pranešimo kilmės (originator) ir nurodyto objekto (-ų), remiantis kryptimi ir tipu.", + "remove-current-relations": "Pašalinti esamus ryšius", + "remove-current-relations-hint": "Pašalina esamus ryšius iš pranešimo kilmės (originator) pagal kryptį ir tipą.", + "change-originator-to-related-entity": "Pakeisti pranešimo kilmę į susijusį objektą", + "change-originator-to-related-entity-hint": "Naudojama, kad pranešimas būtų apdorojamas kaip gautas iš kito objekto.", + "start-interval": "Intervalo pradžia", + "end-interval": "Intervalo pabaiga", + "start-interval-required": "Intervalo pradžia yra privaloma.", + "end-interval-required": "Intervalo pabaiga yra privaloma.", + "smtp-protocol": "Protokolas", + "smtp-host": "SMTP serveris", + "smtp-host-required": "SMTP serveris yra privalomas.", + "smtp-port": "SMTP prievadas", + "smtp-port-required": "Reikia nurodyti SMTP prievadą.", + "smtp-port-range": "SMTP prievadas turi būti nuo 1 iki 65535.", + "timeout-msec": "Laiko limitas (ms)", + "min-timeout-msec-message": "Leidžiama tik minimali 0 ms reikšmė.", + "enter-username": "Įveskite vartotojo vardą", + "enter-password": "Įveskite slaptažodį", + "enable-tls": "Įjungti TLS", + "tls-version": "TLS versija", + "enable-proxy": "Įjungti tarpiklį (Proxy)", + "use-system-proxy-properties": "Naudoti sistemos tarpiklio nustatymus", + "proxy-host": "Tarpiklio serveris (Proxy host)", + "proxy-host-required": "Tarpiklio serveris yra privalomas.", + "proxy-port": "Tarpiklio prievadas (Proxy port)", + "proxy-port-required": "Tarpiklio prievadas yra privalomas.", + "proxy-port-range": "Tarpiklio prievadas turi būti nuo 1 iki 65535.", + "proxy-user": "Tarpiklio vartotojas", + "proxy-password": "Tarpiklio slaptažodis", + "proxy-scheme": "Tarpiklio schema (Proxy scheme)", + "numbers-to-template": "Telefono numerių šablonas", + "numbers-to-template-required": "Telefono numerių šablonas yra privalomas", + "numbers-to-template-hint": "Telefono numerius atskirkite kableliais. Naudokite ${metadataKey} reikšmėms iš metaduomenų ir $[messageKey] reikšmėms iš pranešimo turinio.", + "sms-message-template": "SMS žinutės šablonas", + "sms-message-template-required": "SMS žinutės šablonas yra privalomas", + "use-system-sms-settings": "Naudoti sistemos SMS paslaugų teikėjo nustatymus", + "min-period-0-seconds-message": "Leidžiamas tik minimalus 0 sekundžių periodas.", + "max-pending-messages": "Maksimalus laukiančių pranešimų skaičius", + "max-pending-messages-required": "Maksimalus laukiančių pranešimų skaičius yra privalomas.", + "max-pending-messages-range": "Maksimalus laukiančių pranešimų skaičius turi būti nuo 1 iki 100000.", + "originator-types-filter": "Siuntėjų (originatorių) tipų filtras", + "interval-seconds": "Intervalas sekundėmis", + "interval-seconds-required": "Intervalas yra privalomas.", + "int-range": "Reikšmė neturi viršyti maksimalios sveiko skaičiaus ribos (2147483648)", + "min-interval-seconds-message": "Leidžiamas tik minimalus 1 sekundės intervalas.", + "output-timeseries-key-prefix": "Išvesties laiko eilučių rakto priešdėlis", + "output-timeseries-key-prefix-required": "Išvesties laiko eilučių rakto priešdėlis yra privalomas.", + "separator-hint": "Paspauskite „Enter“, kad užbaigtumėte lauko įvedimą.", + "select-details": "Pasirinkti detales", + "entity-details-id": "Id", + "entity-details-title": "Pavadinimas", + "entity-details-country": "Šalis", + "entity-details-state": "Valstija / regionas", + "entity-details-city": "Miestas", + "entity-details-zip": "Pašto kodas", + "entity-details-address": "Adresas", + "entity-details-address2": "Adresas 2", + "entity-details-additional_info": "Papildoma informacija", + "entity-details-phone": "Telefonas", + "entity-details-email": "El. paštas", + "email-sender": "El. pašto siuntėjas", + "fields-to-check": "Laukai, kuriuos reikia patikrinti", + "add-detail": "Pridėti detalę", + "check-all-keys-tooltip": "Jei įjungta, tikrina, ar visi pranešime ir metaduomenyse nurodyti laukai yra pranešime.", + "fields-to-check-hint": "Paspauskite „Enter“, kad užbaigtumėte lauko įvedimą. Palaikomi keli laukų pavadinimai.", + "entity-details-list-empty": "Reikia pasirinkti bent vieną detalę.", + "alarm-status": "Pavojaus būsena", + "alarm-required": "Turi būti pasirinkta bent viena pavojaus būsena.", + "no-entity-details-matching": "Nerasta atitinkančių objektų detalių.", + "custom-table-name": "Individualios lentelės pavadinimas", + "custom-table-name-required": "Lentelės pavadinimas yra privalomas", + "custom-table-hint": "Lentelė turi būti sukurta jūsų Cassandra klasteryje, jos pavadinimas turi prasidėti prefiksu „cs_tb_“, kad duomenys nebūtų įrašyti į bendras TB lenteles. Įveskite lentelės pavadinimą be „cs_tb_“ prefikso.", + "message-field": "Pranešimo laukas", + "message-field-required": "Pranešimo laukas yra privalomas.", + "table-col": "Lentelės stulpelis", + "table-col-required": "Lentelės stulpelis yra privalomas.", + "latitude-field-name": "Platumos lauko pavadinimas", + "longitude-field-name": "Ilgumos lauko pavadinimas", + "latitude-field-name-required": "Platumos lauko pavadinimas yra privalomas.", + "longitude-field-name-required": "Ilgumos lauko pavadinimas yra privalomas.", + "fetch-perimeter-info-from-metadata": "Gauti perimetro informaciją iš metaduomenų", + "fetch-perimeter-info-from-metadata-tooltip": "Jei perimetro tipas nustatytas kaip „Poligonas“, metaduomenų lauko '{{perimeterKeyName}}' reikšmė bus naudojama kaip perimetro apibrėžimas be papildomo reikšmės apdorojimo. Priešingu atveju, jei perimetro tipas nustatytas kaip „Apskritimas“, '{{perimeterKeyName}}' metaduomenų lauko reikšmė bus išanalizuota, kad būtų išgauti 'latitude', 'longitude', 'radius', 'radiusUnit' laukai, naudojami apskritimo perimetro apibrėžimui.", + "perimeter-key-name": "Perimetro rakto pavadinimas", + "perimeter-key-name-hint": "Metaduomenų lauko pavadinimas, kuriame yra perimetro informacija.", + "perimeter-key-name-required": "Perimetro rakto pavadinimas yra privalomas.", + "perimeter-circle": "Apskritimas", + "perimeter-polygon": "Poligonas", + "perimeter-type": "Perimetro tipas", + "circle-center-latitude": "Centro platuma", + "circle-center-latitude-required": "Centro platuma yra privaloma.", + "circle-center-longitude": "Centro ilguma", + "circle-center-longitude-required": "Centro ilguma yra privaloma.", + "range-unit-meter": "Metrai", + "range-unit-kilometer": "Kilometrai", + "range-unit-foot": "Pėdos", + "range-unit-mile": "Mylios", + "range-unit-nautical-mile": "Jūrmylės", + "range-units": "Atstumo vienetai", + "range-units-required": "Atstumo vienetai yra privalomi.", + "range": "Atstumas", + "range-required": "Atstumas yra privalomas.", + "polygon-definition": "Poligono apibrėžimas", + "polygon-definition-required": "Poligono apibrėžimas yra privalomas.", + "polygon-definition-hint": "Naudokite šį formatą rankiniam poligono apibrėžimui: [[lat1,lon1],[lat2,lon2], ... ,[latN,lonN]].", + "min-inside-duration": "Minimalus buvimo viduje laikas", + "min-inside-duration-value-required": "Minimalus buvimo viduje laikas yra privalomas", + "min-inside-duration-time-unit": "Minimalus buvimo viduje laiko vienetas", + "min-outside-duration": "Minimalus buvimo išorėje laikas", + "min-outside-duration-value-required": "Minimalus buvimo išorėje laikas yra privalomas", + "min-outside-duration-time-unit": "Minimalus buvimo išorėje laiko vienetas", + "tell-failure-if-absent": "Pranešti apie klaidą", + "tell-failure-if-absent-hint": "Jei bent vienas pasirinktas raktas neegzistuoja, siunčiama žinutė praneš apie „Klaida“.", + "get-latest-value-with-ts": "Gauti naujausias telemetrijos reikšmes su laiko žyma", + "get-latest-value-with-ts-hint": "Jei pasirinkta, naujausios telemetrijos reikšmės taip pat turės laiko žymą, pvz.: \"temp\": \"{\"ts\":1574329385897, \"value\":42}\"", + "ignore-null-strings": "Ignoruoti tuščias eilutes", + "ignore-null-strings-hint": "Jei pasirinkta, taisyklės mazgas ignoruos objektų laukus su tuščia reikšme.", + "add-metadata-key-values-as-kafka-headers": "Pridėti metaduomenų raktų-reikšmių poras į Kafka antraštes", + "add-metadata-key-values-as-kafka-headers-hint": "Jei pasirinkta, raktų-reikšmių poros iš metaduomenų bus pridėtos prie siunčiamų įrašų antraščių kaip baitų masyvai su iš anksto nustatytu kodavimu.", + "charset-encoding": "Koduotė", + "charset-encoding-required": "Koduotė yra privaloma.", + "charset-us-ascii": "US-ASCII", + "charset-iso-8859-1": "ISO-8859-1", + "charset-utf-8": "UTF-8", + "charset-utf-16be": "UTF-16BE", + "charset-utf-16le": "UTF-16LE", + "charset-utf-16": "UTF-16", + "select-queue-hint": "Eilės pavadinimą galima pasirinkti iš sąrašo arba įvesti rankiniu būdu.", + "device-profile-node-hint": "Naudinga, jei turite trukmės ar pasikartojančias sąlygas, kad būtų užtikrintas aliarmo būsenos vertinimo tęstinumas.", + "persist-alarm-rules": "Išsaugoti aliarmo taisyklių būseną", + "persist-alarm-rules-hint": "Jei įjungta, taisyklių mazgas išsaugos apdorojimo būseną duomenų bazėje.", + "fetch-alarm-rules": "Atkurti aliarmo taisyklių būseną", + "fetch-alarm-rules-hint": "Jei įjungta, taisyklių mazgas atkūrimo metu atkurs apdorojimo būseną ir užtikrins, kad aliarmai būtų aktyvuojami net po serverio perkrovimo. Priešingu atveju būsena bus atkurta, kai atvyks pirmoji žinutė iš įrenginio.", + "input-value-key": "Įvesties reikšmės raktas", + "input-value-key-required": "Įvesties reikšmės raktas yra privalomas.", + "output-value-key": "Išvesties reikšmės raktas", + "output-value-key-required": "Išvesties reikšmės raktas yra privalomas.", + "number-of-digits-after-floating-point": "Skaičių kiekis po kablelio", + "number-of-digits-after-floating-point-range": "Skaičių kiekis po kablelio turi būti nuo 0 iki 15.", + "failure-if-delta-negative": "Pranešti apie klaidą, jei delta yra neigiama", + "failure-if-delta-negative-tooltip": "Taisyklių mazgas privers pranešimą žymėti kaip klaidą, jei delta reikšmė neigiama.", + "use-caching": "Naudoti kešavimą", + "use-caching-tooltip": "Taisyklių mazgas kaups \"{{inputValueKey}}\" reikšmę iš gaunamos žinutės, kad pagerintų našumą. Atkreipkite dėmesį, kad kešas nebus atnaujintas, jei reikšmė bus pakeista kitur.", + "add-time-difference-between-readings": "Pridėti laiko skirtumą tarp \"{{inputValueKey}}\" nuskaitymų", + "add-time-difference-between-readings-tooltip": "Jei įjungta, taisyklių mazgas pridės \"{{periodValueKey}}\" prie siunčiamos žinutės.", + "period-value-key": "Laikotarpio reikšmės raktas", + "period-value-key-required": "Laikotarpio reikšmės raktas yra privalomas.", + "general-pattern-hint": "Naudokite ${metadataKey} reikšmei iš metaduomenų, $[messageKey] reikšmei iš pranešimo kūno.", + "alarm-severity-pattern-hint": "Naudokite ${metadataKey} reikšmei iš metaduomenų, $[messageKey] reikšmei iš pranešimo kūno. Aliarmo rimtumas turi būti sistemos (CRITICAL, MAJOR ir t. t.)", + "output-node-name-hint": "Taisyklių mazgo pavadinimas atitinka pranešimo ryšio tipą ir naudojamas pranešimams perduoti kitiems taisyklių mazgams toje pačioje taisyklių grandinėje.", + "use-server-ts": "Naudoti serverio laiko žymą", + "use-server-ts-hint": "Naudoti serverio dabartinę laiko žymą laiko eilučių duomenims, kurie neturi aiškios laiko žymos. Tai padeda išlaikyti teisingą eiliškumą apdorojant žinutes iš kelių šaltinių arba kai jos atvyksta ne iš eilės.", + "kv-map-pattern-hint": "Visi įvesties laukai palaiko šablonizaciją. Naudokite $[messageKey], kad gautumėte reikšmę iš pranešimo, ir ${metadataKey}, kad gautumėte reikšmę iš metaduomenų.", + "kv-map-single-pattern-hint": "Įvesties laukas palaiko šablonizaciją. Naudokite $[messageKey], kad gautumėte reikšmę iš pranešimo, ir ${metadataKey}, kad gautumėte reikšmę iš metaduomenų.", + "shared-scope": "Bendras taikymo sritis", + "server-scope": "Serverio taikymo sritis", + "client-scope": "Kliento taikymo sritis", + "attribute-type": "Atributas", + "attribute-type-description": "Gauti atributo reikšmę iš duomenų bazės", + "attribute-type-result-description": "Išsaugoti rezultatą kaip subjekto atributą duomenų bazėje", + "constant-type": "Konstanta", + "constant-type-description": "Nustatyti pastovią reikšmę", + "time-series-type": "Laiko eilutė", + "time-series-type-description": "Gauti naujausią laiko eilučių reikšmę iš duomenų bazės", + "time-series-type-result-description": "Išsaugoti rezultatą kaip subjekto laiko eilutę duomenų bazėje", + "message-body-type": "Pranešimas", + "message-body-type-description": "Gauti argumento reikšmę iš gaunamo pranešimo", + "message-body-type-result-description": "Pridėti rezultatą prie siunčiamo pranešimo", + "message-metadata-type": "Metaduomenys", + "message-metadata-type-description": "Gauti argumento reikšmę iš gaunamo pranešimo metaduomenų", + "message-metadata-result-description": "Pridėti rezultatą prie siunčiamo pranešimo metaduomenų", + "argument-tile": "Argumentai", + "no-arguments-prompt": "Argumentai nesukonfigūruoti", + "result-title": "Rezultatas", + "functions-field-input": "Funkcijos", + "no-option-found": "Parinkčių nerasta", + "argument-source-field-input": "Šaltinis", + "argument-source-field-input-required": "Argumento šaltinis yra privalomas.", + "argument-key-field-input": "Raktas", + "argument-key-field-input-required": "Argumento raktas yra privalomas.", + "constant-value-field-input": "Pastovioji reikšmė", + "constant-value-field-input-required": "Pastovioji reikšmė yra privaloma.", + "attribute-scope-field-input": "Atributo taikymo sritis", + "attribute-scope-field-input-required": "Atributo taikymo sritis yra privaloma.", + "default-value-field-input": "Numatytoji reikšmė", + "type-field-input": "Tipas", + "type-field-input-required": "Tipas yra privalomas.", + "key-field-input": "Raktas", + "add-entity-type": "Pridėti subjekto tipą", + "add-device-profile": "Pridėti įrenginio profilį", + "key-field-input-required": "Raktas yra privalomas.", + "number-floating-point-field-input": "Skaičių kiekis po kablelio", + "number-floating-point-field-input-hint": "Naudokite 0, kad konvertuotumėte rezultatą į sveiką skaičių", + "add-to-message-field-input": "Pridėti prie pranešimo", + "add-to-metadata-field-input": "Pridėti prie metaduomenų", + "custom-expression-field-input": "Matematinė išraiška", + "custom-expression-field-input-required": "Matematinė išraiška yra privaloma", + "custom-expression-field-input-hint": "Nurodykite matematinę išraišką įvertinimui. Numatytoji išraiška parodo, kaip konvertuoti Fahrenheit į Celsijų", + "retained-message": "Išsaugotas", + "attributes-mapping": "Atributų susiejimas", + "latest-telemetry-mapping": "Naujausios telemetrijos susiejimas", + "add-mapped-attribute-to": "Pridėti susietus atributus į", + "add-mapped-latest-telemetry-to": "Pridėti susietą naujausią telemetriją į", + "add-mapped-fields-to": "Pridėti susietus laukus į", + "add-selected-details-to": "Pridėti pasirinktą informaciją į", + "clear-selected-types": "Išvalyti pasirinktus tipus", + "clear-selected-details": "Išvalyti pasirinktą informaciją", + "clear-selected-fields": "Išvalyti pasirinktus laukus", + "clear-selected-keys": "Išvalyti pasirinktus raktus", + "geofence-configuration": "Geozonos konfigūracija", + "coordinate-field-names": "Koordinačių laukų pavadinimai", + "coordinate-field-hint": "Taisyklių mazgas bando gauti nurodytus laukus iš pranešimo. Jei jų nėra, ieškos metaduomenyse.", + "presence-monitoring-strategy": "Buvimo stebėjimo strategija", + "presence-monitoring-strategy-on-first-message": "Pirmoje žinutėje", + "presence-monitoring-strategy-on-each-message": "Kiekvienoje žinutėje", + "presence-monitoring-strategy-on-first-message-hint": "Praneša buvimo būseną „Viduje“ arba „Išorėje“ pirmoje žinutėje, kai nuo ankstesnio būsenos „Įėjo“ arba „Išėjo“ atnaujinimo praėjo nustatytas minimalus laikas.", + "presence-monitoring-strategy-on-each-message-hint": "Praneša buvimo būseną „Viduje“ arba „Išorėje“ kiekvienoje žinutėje po būsenos „Įėjo“ arba „Išėjo“ atnaujinimo.", + "fetch-credentials-to": "Gauti kredencialus į", + "add-originator-attributes-to": "Pridėti siuntėjo atributus į", + "originator-attributes": "Siuntėjo atributai", + "fetch-latest-telemetry-with-timestamp": "Gauti naujausią telemetriją su laiko žyma", + "fetch-latest-telemetry-with-timestamp-tooltip": "Jei pasirinkta, naujausios telemetrijos reikšmės bus pridėtos prie siunčiamų metaduomenų su laiko žyma, pvz.: \"{{latestTsKeyName}}\": \"{\"ts\":1574329385897, \"value\":42}\"", + "tell-failure": "Pranešti apie klaidą, jei trūksta bent vieno atributo", + "tell-failure-tooltip": "Jei bent vienas pasirinktas raktas neegzistuoja, siunčiama žinutė praneš apie „Klaida“.", + "created-time": "Sukūrimo laikas", + "chip-help": "Paspauskite 'Enter', kad užbaigtumėte {{inputName}} įvedimą.\nPaspauskite 'Backspace', kad ištrintumėte {{inputName}}.\nPalaikomos kelios reikšmės.", + "detail": "informacija", + "field-name": "lauko pavadinimas", + "device-profile": "įrenginio profilis", + "entity-type": "subjekto tipas", + "message-type": "pranešimo tipas", + "timeseries-key": "laiko eilučių raktas", + "type": "Tipas", + "first-name": "Vardas", + "last-name": "Pavardė", + "label": "Etiketė", + "originator-fields-mapping": "Siuntėjo laukų susiejimas", + "add-mapped-originator-fields-to": "Pridėti susietus siuntėjo laukus į", + "fields": "Laukai", + "skip-empty-fields": "Praleisti tuščius laukus", + "skip-empty-fields-tooltip": "Laukai su tuščiomis reikšmėmis nebus pridėti prie išvesties pranešimo ar metaduomenų.", + "fetch-interval": "Gavimo intervalas", + "fetch-strategy": "Gavimo strategija", + "fetch-timeseries-from-to": "Gauti laiko eilučių duomenis nuo {{startInterval}} {{startIntervalTimeUnit}} iki {{endInterval}} {{endIntervalTimeUnit}} atgal.", + "fetch-timeseries-from-to-invalid": "Laiko eilučių gavimo klaida („Intervalo pradžia“ turi būti mažesnė už „Intervalo pabaigą“).", + "use-metadata-dynamic-interval-tooltip": "Jei pasirinkta, taisyklių mazgas naudos dinaminį intervalo pradžios ir pabaigos laiką pagal pranešimo bei metaduomenų šablonus.", + "all-mode-hint": "Jei pasirinktas gavimo režimas „Visi“, taisyklių mazgas gaus telemetriją iš intervalo pagal konfigūruojamus užklausos parametrus.", + "first-mode-hint": "Jei pasirinktas režimas „Pirmas“, taisyklių mazgas gaus artimiausią telemetriją intervalo pradžiai.", + "last-mode-hint": "Jei pasirinktas režimas „Paskutinis“, taisyklių mazgas gaus artimiausią telemetriją intervalo pabaigai.", + "ascending": "Didėjančia tvarka", + "descending": "Mažėjančia tvarka", + "min": "Min.", + "max": "Maks.", + "average": "Vidurkis", + "sum": "Suma", + "count": "Kiekis", + "none": "Nėra", + "last-level-relation-tooltip": "Jei pasirinkta, taisyklių mazgas ieškos susijusių subjektų tik maksimaliame nustatytame ryšio lygyje.", + "last-level-device-relation-tooltip": "Jei pasirinkta, taisyklių mazgas ieškos susijusių įrenginių tik maksimaliame nustatytame ryšio lygyje.", + "data-to-fetch": "Duomenys, kuriuos reikia gauti", + "mapping-of-customers": "Klientų susiejimas", + "map-fields-required": "Visi susiejimo laukai yra privalomi.", + "attributes": "Atributai", + "related-device-attributes": "Susijusio įrenginio atributai", + "add-selected-attributes-to": "Pridėti pasirinktus atributus į", + "device-profiles": "Įrenginių profiliai", + "mapping-of-tenant": "Nuomininko susiejimas", + "add-attribute-key": "Pridėti atributo raktą", + "message-template": "Pranešimo šablonas", + "message-template-required": "Pranešimo šablonas yra privalomas", + "use-system-slack-settings": "Naudoti sistemos Slack nustatymus", + "slack-api-token": "Slack API raktas", + "slack-api-token-required": "Slack API raktas yra privalomas", + "keys-mapping": "Raktų susiejimas", + "add-key": "Pridėti raktą", + "recipients": "Gavėjai", + "message-subject-and-content": "Pranešimo tema ir turinys", + "template-rules-hint": "Abu įvesties laukai palaiko šablonizaciją. Naudokite $[messageKey] reikšmei iš pranešimo ir ${metadataKey} reikšmei iš metaduomenų.", + "originator-customer-desc": "Naudoti gaunamo pranešimo siuntėjo klientą kaip naują siuntėją.", + "originator-tenant-desc": "Naudoti dabartinį nuomininką kaip naują siuntėją.", + "originator-related-entity-desc": "Naudoti susijusį subjektą kaip naują siuntėją. Paieška atliekama pagal konfigūruotą ryšio tipą ir kryptį.", + "originator-alarm-originator-desc": "Naudoti aliarmo siuntėją kaip naują siuntėją. Tik jei gaunamo pranešimo siuntėjas yra aliarmo subjektas.", + "originator-entity-by-name-pattern-desc": "Naudoti iš duomenų bazės gautą subjektą kaip naują siuntėją. Paieška atliekama pagal subjekto tipą ir nurodytą pavadinimo šabloną.", + "email-from-template-hint": "Naudokite $[messageKey] reikšmei iš pranešimo ir ${metadataKey} reikšmei iš metaduomenų.", + "recipients-block-main-hint": "Adresų sąrašas, atskirtas kableliais. Visi įvesties laukai palaiko šablonizaciją. Naudokite $[messageKey] reikšmei iš pranešimo ir ${metadataKey} reikšmei iš metaduomenų.", + "forward-msg-default-rule-chain": "Persiųsti pranešimą į siuntėjo numatytą taisyklių grandinę", + "forward-msg-default-rule-chain-tooltip": "Jei įjungta, pranešimas bus persiųstas į siuntėjo numatytą taisyklių grandinę arba į konfigūracijoje nurodytą grandinę, jei siuntėjas neturi numatytos grandinės subjekto profilyje.", + "exclude-zero-deltas": "Pašalinti nulinės delta reikšmes iš siunčiamo pranešimo", + "exclude-zero-deltas-hint": "Jei įjungta, \"{{outputValueKey}}\" bus pridėtas prie siunčiamo pranešimo tik jei reikšmė nėra lygi nuliui.", + "exclude-zero-deltas-time-difference-hint": "Jei įjungta, \"{{outputValueKey}}\" ir \"{{periodValueKey}}\" bus pridėti prie siunčiamo pranešimo tik jei \"{{outputValueKey}}\" reikšmė nėra nulinė.", + "search-direction-from": "Nuo siuntėjo iki tikslo", + "search-direction-to": "Nuo tikslo iki siuntėjo", + "del-relation-direction-from": "Nuo siuntėjo", + "del-relation-direction-to": "Į siuntėją", + "target-entity": "Tikslinis subjektas", + "function-configuration": "Funkcijos konfigūracija", + "function-name": "Funkcijos pavadinimas", + "function-name-required": "Funkcijos pavadinimas yra privalomas.", + "qualifier": "Kvalifikatorius", + "qualifier-hint": "Jei kvalifikatorius nenurodytas, bus naudojamas numatytasis \"$LATEST\".", + "aws-credentials": "AWS kredencialai", + "connection-timeout": "Ryšio laiko limitas", + "connection-timeout-required": "Ryšio laiko limitas yra privalomas.", + "connection-timeout-min": "Minimalus ryšio laikas yra 0.", + "connection-timeout-hint": "Laikas sekundėmis, kurį sistema laukia užmezgant ryšį prieš nutraukdama bandymą. Reikšmė 0 reiškia begalybę ir nerekomenduojama.", + "request-timeout": "Užklausos laiko limitas", + "request-timeout-required": "Užklausos laiko limitas yra privalomas.", + "request-timeout-min": "Minimalus užklausos laikas yra 0.", + "request-timeout-hint": "Laikas sekundėmis, kiek sistema laukia, kol užklausa bus įvykdyta. Reikšmė 0 reiškia begalybę ir nerekomenduojama.", + "units": "Vienetai", + "tell-failure-aws-lambda": "Pranešti apie klaidą, jei AWS Lambda funkcijos vykdymas sukelia išimtį", + "tell-failure-aws-lambda-hint": "Taisyklių mazgas privers pranešimą žymėti kaip klaidą, jei AWS Lambda funkcijos vykdymas sukelia išimtį.", + "basic-mode": "Paprastas režimas", + "advanced-mode": "Išplėstinis režimas", + "save-time-series": { + "processing-settings": "Apdorojimo nustatymai", + "processing-settings-hint": "Nustatykite, kaip apdorojamos gaunamos žinutės. Paprasti apdorojimo nustatymai leidžia pasirinkti iš anksto sukonfigūruotas strategijas, o išplėstiniai – individualiai pritaikyti strategijas kiekvienam veiksmui.", + "advanced-settings-hint": "Būkite atsargūs konfigūruodami apdorojimo strategijas. Kai kurie deriniai gali sukelti netikėtą elgesį.", + "strategy": "Strategija", + "deduplication-interval": "Dublikavimo šalinimo intervalas", + "deduplication-interval-required": "Dublikavimo šalinimo intervalas yra privalomas.", + "deduplication-interval-min-max-range": "Dublikavimo šalinimo intervalas turi būti ne trumpesnis nei 1 sekundė ir ne ilgesnis nei 1 diena.", + "strategy-type": { + "every-message": "Kiekvienai žinutei", + "skip": "Praleisti", + "deduplicate": "Pašalinti dublikatus", + "web-sockets-only": "Tik WebSockets" + }, + "time-series": "Laiko eilutės", + "latest": "Naujausios reikšmės", + "web-sockets": "WebSockets", + "calculated-fields": "Apskaičiuoti laukai" + }, + "save-attribute": { + "processing-settings": "Apdorojimo nustatymai", + "processing-settings-hint": "Nustatykite, kaip bus apdorojamos gaunamos žinutės. Paprasti apdorojimo nustatymai leidžia pasirinkti iš anksto sukonfigūruotas strategijas, o išplėstiniai – pasirinkti individualias apdorojimo strategijas kiekvienam veiksmui.", + "advanced-settings-hint": "Būkite atsargūs konfigūruodami apdorojimo strategijas. Kai kurie deriniai gali sukelti netikėtą elgesį.", + "strategy": "Strategija", + "deduplication-interval": "Dublikavimo šalinimo intervalas", + "deduplication-interval-required": "Dublikavimo šalinimo intervalas yra privalomas.", + "deduplication-interval-min-max-range": "Dublikavimo šalinimo intervalas turi būti ne trumpesnis nei 1 sekundė ir ne ilgesnis nei 1 diena.", + "scope": "Taikymo sritis", + "strategy-type": { + "every-message": "Kiekvienai žinutei", + "skip": "Praleisti", + "deduplicate": "Pašalinti dublikatus", + "web-sockets-only": "Tik WebSockets" + }, + "attributes": "Atributai" + }, + "key-val": { + "key": "Raktas", + "value": "Reikšmė", + "see-examples": "Žiūrėti pavyzdžius.", + "remove-entry": "Pašalinti įrašą", + "remove-mapping-entry": "Pašalinti susiejimo įrašą", + "add-mapping-entry": "Pridėti susiejimą", + "add-entry": "Pridėti įrašą", + "copy-key-values-from": "Kopijuoti raktų-reikšmių poras iš", + "delete-key-values": "Ištrinti raktų-reikšmių poras", + "delete-key-values-from": "Ištrinti raktų-reikšmių poras iš", + "at-least-one-key-error": "Turi būti pasirinktas bent vienas raktas.", + "unique-key-value-pair-error": "'{{keyText}}' turi skirtis nuo '{{valText}}'!" + }, + "mail-body-types": { + "plain-text": "Grynasis tekstas", + "html": "HTML", + "dynamic": "Dinaminis", + "use-body-type-template": "Naudoti turinio tipo šabloną", + "plain-text-description": "Paprastas, neformatuotas tekstas be specialaus stiliaus ar formatavimo.", + "html-text-description": "Leidžia naudoti HTML žymes formatavimui, nuorodoms ir vaizdams el. laiško turinyje.", + "dynamic-text-description": "Leidžia dinamiškai naudoti Grynąjį tekstą arba HTML turinio tipą pagal šablonizacijos funkciją.", + "after-template-evaluation-hint": "Po šablono įvertinimo reikšmė turi būti „true“ HTML turiniui ir „false“ grynajam tekstui." + }, + "ai": { + "ai-model": "DI modelis", + "model": "Modelis", + "ai-model-hint": "Pasirinkite iš anksto sukonfigūruotą DI modelį užklausų, siunčiamų per šį taisyklių mazgą, apdorojimui arba naudokite „Sukurti naują“, kad sukonfigūruotumėte naują modelį.", + "prompt-settings": "Užklausos nustatymai", + "prompt-settings-hint": "Neprivalomas sistemos užklausos tekstas nustato DI bendrą vaidmenį ir apribojimus, o vartotojo užklausa apibrėžia konkrečią vykdomą užduotį. Abu laukai palaiko šablonizaciją.", + "system-prompt": "Sistemos užklausa", + "system-prompt-max-length": "Sistemos užklausa turi būti ne ilgesnė nei 500000 simbolių.", + "system-prompt-blank": "Sistemos užklausa negali būti tuščia.", + "user-prompt": "Vartotojo užklausa", + "user-prompt-required": "Vartotojo užklausa yra privaloma.", + "user-prompt-max-length": "Vartotojo užklausa turi būti ne ilgesnė nei 500000 simbolių.", + "user-prompt-blank": "Vartotojo užklausa negali būti tuščia.", + "response-format": "Atsakymo formatas", + "response-text": "Tekstas", + "response-json": "JSON", + "response-json-schema": "JSON Schema", + "response-format-hint-TEXT": "Leidžia modeliui generuoti laisvo formato tekstą, kuris gali būti arba nebūti tinkamas JSON objektas. Jei išvestis nėra tinkamas JSON objektas, ji bus automatiškai įvyniota į JSON objektą po raktu „response“.", + "response-format-hint-JSON": "Modelis privalo sugeneruoti atsakymą, kuris yra teisingas JSON objektas. Jei išvestis nėra tinkamas JSON objektas, ji bus automatiškai įvyniota į JSON objektą po raktu „response“.", + "response-format-hint-JSON_SCHEMA": "Modelis privalo sugeneruoti JSON, atitinkantį nurodytą struktūrą ir duomenų tipus pagal pateiktą schemą. Jei išvestis nėra tinkamas JSON objektas, ji bus automatiškai įvyniota į JSON objektą po raktu „response“.", + "response-json-schema-hint": "Galima įvesti bet kokią tinkamą JSON schemą, tačiau šis taisyklių mazgas palaiko tik ribotą jos funkcionalumo rinkinį. Išsamesnę informaciją rasite mazgo dokumentacijoje.", + "response-json-schema-required": "JSON schema yra privaloma.", + "advanced-settings": "Išplėstiniai nustatymai", + "timeout": "Laiko limitas", + "timeout-hint": "Didžiausias laukimo laikas, kol bus gautas atsakymas iš DI modelio prieš nutraukiant užklausą.", + "timeout-required": "Laiko limitas yra privalomas.", + "timeout-validation": "Turi būti nuo 1 sekundės iki 10 minučių.", + "force-acknowledgement": "Priverstinis patvirtinimas", + "force-acknowledgement-hint": "Jei įjungta, gaunamas pranešimas patvirtinamas iš karto. Modelio atsakymas tada įtraukiamas į eilę kaip atskiras naujas pranešimas." + } + }, + "timezone": { + "timezone": "Laiko juosta", + "select-timezone": "Pasirinkti laiko juostą", + "no-timezones-matching": "Laiko juostų, atitinkančių '{{timezone}}' nėra.", + "timezone-required": "Laiko juosta būtina.", + "browser-time": "Naršyklės laikas" + }, + "queue": { + "queue-name": "Eilė", + "no-queues-found": "Eilių nerasta.", + "no-queues-matching": "Eilių, atitinkančių '{{queue}}', nerasta.", + "select-name": "Pasirinkite eilės pavadinimą", + "name": "Pavadinimas", + "name-required": "Eilės pavadinimas yra privalomas!", + "name-unique": "Eilės pavadinimas nėra unikalus!", + "name-pattern": "Eilės pavadinimas turi simbolį, kuris nėra ASCII raidinis-skaitmeninis, '.', '_' ar '-'!", + "queue-required": "Eilė yra privaloma!", + "topic-required": "Eilės tema yra privaloma!", + "poll-interval-required": "Apklausos intervalas yra privalomas!", + "poll-interval-min-value": "Apklausos intervalo reikšmė negali būti mažesnė nei 1.", + "partitions-required": "Padaliniai yra privalomi!", + "partitions-min-value": "Padalinių reikšmė negali būti mažesnė nei 1.", + "pack-processing-timeout-required": "Apdorojimo laiko limitas yra privalomas.", + "pack-processing-timeout-min-value": "Apdorojimo laiko limito reikšmė negali būti mažesnė nei 1.", + "batch-size-required": "Paketo dydis yra privalomas!", + "batch-size-min-value": "Paketo dydžio reikšmė negali būti mažesnė nei 1.", + "retries-required": "Bandymai yra privalomi!", + "retries-min-value": "Bandymai negali būti neigiami.", + "failure-percentage-required": "Klaidos procentas yra privalomas!", + "failure-percentage-min-value": "Klaidos procentas negali būti mažesnis nei 0.", + "failure-percentage-max-value": "Klaidos procentas negali būti didesnis nei 100.", + "pause-between-retries-required": "Pauzė tarp bandymų yra privaloma!", + "pause-between-retries-min-value": "Pauzės tarp bandymų reikšmė negali būti mažesnė nei 1.", + "max-pause-between-retries-required": "Maksimali pauzė tarp bandymų yra privaloma!", + "max-pause-between-retries-min-value": "Maksimalios pauzės tarp bandymų reikšmė negali būti mažesnė nei 1.", + "submit-strategy-type-required": "Pateikimo strategijos tipas yra privalomas!", + "processing-strategy-type-required": "Apdorojimo strategijos tipas yra privalomas!", + "queues": "Eilės", + "selected-queues": "Pasirinkta { count, plural, =1 {1 eilė} other {# eilės} }", + "delete-queue-title": "Ar tikrai norite ištrinti eilę '{{queueName}}'?", + "delete-queues-title": "Ar tikrai norite ištrinti { count, plural, =1 {1 eilę} other {# eiles} }?", + "delete-queue-text": "Būkite atsargūs — po patvirtinimo eilė ir visi su ja susiję duomenys bus negrįžtamai pašalinti.", + "delete-queues-text": "Po patvirtinimo visos pasirinktos eilės bus ištrintos ir taps nepasiekiamos.", + "search": "Ieškoti eilės", + "add": "Pridėti eilę", + "details": "Eilės informacija", + "topic": "Tema", + "submit-settings": "Pateikimo nustatymai", + "submit-strategy": "Strategijos tipas *", + "grouping-parameter": "Grupavimo parametras", + "processing-settings": "Bandyminių apdorojimų nustatymai", + "processing-strategy": "Apdorojimo tipas *", + "retries-settings": "Bandyminių bandymų nustatymai", + "polling-settings": "Apklausos nustatymai", + "batch-processing": "Paketo apdorojimas", + "poll-interval": "Apklausos intervalas", + "partitions": "Padaliniai", + "immediate-processing": "Tiesioginis apdorojimas", + "consumer-per-partition": "Siųsti žinučių apklausą kiekvienam vartotojui", + "consumer-per-partition-hint": "Įjungti atskirą vartotoją (-us) kiekvienam padaliniui", + "duplicate-msg-to-all-partitions": "Dubliuoti žinutę į visus padalinius", + "processing-timeout": "Apdorojimo trukmė, ms", + "batch-size": "Paketo dydis", + "retries": "Bandymai (0 – neribota)", + "failure-percentage": "Klaidingų žinučių procentas, praleidžiant bandymus", + "pause-between-retries": "Pakartoti po, sek.", + "max-pause-between-retries": "Papildomas pakartojimas po, sek.", + "delete": "Ištrinti eilę", + "copyId": "Kopijuoti eilės ID", + "idCopiedMessage": "Eilės ID nukopijuotas į iškarpinę", + "description": "Aprašymas", + "description-hint": "Šis tekstas bus rodomas eilės aprašyme vietoj pasirinktos strategijos.", + "alt-description": "Pateikimo strategija: {{submitStrategy}}, Apdorojimo strategija: {{processingStrategy}}", + "custom-properties": "Pasirinktinės savybės", + "custom-properties-hint": "Pasirinktinės eilės (temos) kūrimo savybės, pvz.: 'retention.ms:604800000;retention.bytes:1048576000'", + "strategies": { + "sequential-by-originator-label": "Sekvencinis pagal siuntėją", + "sequential-by-originator-hint": "Nauja žinutė, pvz., iš įrenginio A, nepateikiama, kol nepatvirtinama ankstesnė žinutė iš to paties įrenginio.", + "sequential-by-tenant-label": "Sekvencinis pagal nuomininką", + "sequential-by-tenant-hint": "Nauja žinutė, pvz., iš nuomininko A, nepateikiama, kol nepatvirtinama ankstesnė žinutė iš to paties nuomininko.", + "sequential-label": "Sekvencinis", + "sequential-hint": "Nauja žinutė nepateikiama, kol nepatvirtinama ankstesnė žinutė.", + "burst-label": "Srautinis (Burst)", + "burst-hint": "Visos žinutės pateikiamos taisyklių grandinėms tokia tvarka, kokia jos gaunamos.", + "batch-label": "Paketas", + "batch-hint": "Naujas paketas nepateikiamas, kol ankstesnis nepatvirtintas.", + "skip-all-failures-label": "Praleisti visas klaidas", + "skip-all-failures-hint": "Ignoruoti visas klaidas.", + "skip-all-failures-and-timeouts-label": "Praleisti visas klaidas ir laiko limitus", + "skip-all-failures-and-timeouts-hint": "Ignoruoti visas klaidas ir laiko viršijimus.", + "retry-all-label": "Kartoti visas", + "retry-all-hint": "Kartoti visas žinutes iš apdorojimo paketo.", + "retry-failed-label": "Kartoti nesėkmingas", + "retry-failed-hint": "Kartoti visas nesėkmingai apdorotas žinutes iš paketo.", + "retry-timeout-label": "Kartoti laiko viršijusias", + "retry-timeout-hint": "Kartoti visas laiko limitą viršijusias žinutes iš apdorojimo paketo.", + "retry-failed-and-timeout-label": "Kartoti nesėkmingas ir laiko viršijusias", + "retry-failed-and-timeout-hint": "Kartoti visas nesėkmingas ir laiko limitą viršijusias žinutes iš apdorojimo paketo." + } + }, + "queue-statistics": { + "queue-statistics": "Eilių statistika", + "no-queue-statistics-matching": "Eilių statistikos, atitinkančios '{{entity}}', nerasta.", + "queue-statistics-required": "Eilių statistika yra privaloma.", + "list-of-queue-statistics": "{ count, plural, =1 {Viena eilės statistika} other {# eilių statistikos sąrašas} }", + "selected-queue-statistics": "Pasirinkta { count, plural, =1 {1 eilės statistika} other {# eilių statistikos} }", + "no-queue-statistics-text": "Eilių statistikos nerasta", + "queue-statistics-starts-with": "Eilių statistika, kurios pavadinimai prasideda '{{prefix}}'" + }, + "server-error": { + "general": "Bendra serverio klaida", + "authentication": "Autentifikavimo klaida", + "jwt-token-expired": "JWT prieigos raktas pasibaigęs", + "tenant-trial-expired": "Nuomininko bandomasis laikotarpis pasibaigė", + "credentials-expired": "Prisijungimo duomenys pasibaigę", + "permission-denied": "Prieiga uždrausta", + "invalid-arguments": "Neteisingi argumentai", + "bad-request-params": "Netinkami užklausos parametrai", + "item-not-found": "Elementas nerastas", + "too-many-requests": "Per daug užklausų", + "too-many-updates": "Per daug atnaujinimų" + }, + "tenant": { + "tenant": "Valdytojas", + "tenants": "Valdytojai", + "management": "Valdytojų valdymas", + "add": "Pridėti valdytoją", + "admins": "Administratoriai", + "manage-tenant-admins": "Valdyti valdytojo administratorius", + "delete": "Ištrinti valdytoją", + "add-tenant-text": "Pridėti naują valdytoją", + "no-tenants-text": "Valdytojų nėra", + "tenant-details": "Informacija apie valdytoją", + "title-max-length": "Pavadinimas negali viršyti 256 simbolių", + "delete-tenant-title": "Ar tikrai norite ištrinti valdytoją '{{tenantTitle}}'?", + "delete-tenant-text": "Būkite dėmesingi, po patvirtinimo valdytojas ir visa su juo susijusi informacija bus pašalinta.", + "delete-tenants-title": "Ar tikrai norite pašalinti { count, plural, =1 {1 valdytoją} other {# valdytojus} }?", + "delete-tenants-action-title": "Pašalinti { count, plural, =1 {1 valdytoją} other {# valdytojus} }", + "delete-tenants-text": "Būkite dėmesingi, po patvirtinimo, visi pasirinkti valdytojai ir su jais susijusi informacija bus pašalinta.", + "title": "Pavadinimas", + "title-required": "Pavadinimas būtinas.", + "description": "Aprašymas", + "details": "Informacija", + "events": "Įvykiai", + "copyId": "Kopijuoti valdytojo Id", + "idCopiedMessage": "Valdytojo Id nukopijuotas į iškarpinę", + "select-tenant": "Pasirinkti valdytoją", + "no-tenants-matching": "Valdytojų, atitinkančių '{{entity}}' nėra.", + "tenant-required": "Valdytojas būtinas", + "search": "Valdytojų paieška", + "selected-tenants": "Pasirinkta { count, plural, =1 {1 valdytojas} other {# valdytojai} }", + "isolated-tb-rule-engine": "Naudoti atskiras ThingsBoard taisyklių variklio eiles", + "isolated-tb-rule-engine-details": "Kiekvienas nuomininkas turės atskiras taisyklių variklio eiles" + }, + "tenant-profile": { + "tenant-profile": "Nuomininko profilis", + "tenant-profiles": "Nuomininkų profiliai", + "add": "Pridėti nuomininko profilį", + "add-profile": "Pridėti profilį", + "debug": "Derinimas", + "edit": "Redaguoti nuomininko profilį", + "tenant-profile-details": "Informacija apie nuomininko profilį", + "no-tenant-profiles-text": "Nuomininkų profilių nėra", + "name-max-length": "Pavadinimas negali viršyti 256 simbolių", + "search": "Nuomininkų profilių paieška", + "selected-tenant-profiles": "Pasirinkta { count, plural, =1 {1 nuomininko profilis} other {# nuomininkų profiliai} }", + "no-tenant-profiles-matching": "Nuomininkų profilių, atitinkančių '{{entity}}', nėra.", + "tenant-profile-required": "Nuomininko profilis yra privalomas", + "idCopiedMessage": "Nuomininko profilio ID nukopijuotas į iškarpinę", + "set-default": "Nustatyti kaip pagrindinį nuomininko profilį", + "delete": "Pašalinti nuomininko profilį", + "copyId": "Kopijuoti nuomininko profilio ID", + "name": "Pavadinimas", + "name-required": "Pavadinimas yra privalomas.", + "data": "Profilio duomenys", + "profile-configuration": "Profilio konfigūracija", + "description": "Aprašymas", + "default": "Pagrindinis", + "delete-tenant-profile-title": "Ar tikrai norite pašalinti nuomininko profilį '{{tenantProfileName}}'?", + "delete-tenant-profile-text": "Būkite atsargūs — po patvirtinimo nuomininko profilis ir visa su juo susijusi informacija bus negrįžtamai pašalinta.", + "delete-tenant-profiles-title": "Ar tikrai norite pašalinti { count, plural, =1 {1 nuomininko profilį} other {# nuomininkų profilius} }?", + "delete-tenant-profiles-text": "Būkite atsargūs — po patvirtinimo visi pasirinkti nuomininkų profiliai ir su jais susijusi informacija bus negrįžtamai pašalinti.", + "set-default-tenant-profile-title": "Ar tikrai norite nuomininko profilį '{{tenantProfileName}}' nustatyti kaip pagrindinį?", + "set-default-tenant-profile-text": "Po patvirtinimo šis nuomininko profilis bus nustatytas kaip pagrindinis ir bus automatiškai priskiriamas naujiems nuomininkams, kuriems profilis nenurodytas.", + "no-tenant-profiles-found": "Nuomininkų profilių nerasta.", + "create-new-tenant-profile": "Sukurti naują!", + "create-tenant-profile": "Sukurti naują nuomininko profilį", + "import": "Importuoti nuomininko profilį", + "export": "Eksportuoti nuomininko profilį", + "export-failed-error": "Nepavyko eksportuoti nuomininko profilio: {{error}}", + "tenant-profile-file": "Nuomininko profilio failas", + "invalid-tenant-profile-file-error": "Nepavyko importuoti nuomininko profilio: neteisinga duomenų struktūra.", + "advanced-settings": "Pažangūs nustatymai", + "entities": "Subjektai", + "rule-engine": "Taisyklių variklis", + "time-to-live": "Gyvavimo trukmė (Time-to-Live)", + "calculated-fields": "Apskaičiuojami laukai", + "alarms-and-notifications": "Pavojaus signalai ir pranešimai", + "ota-files-in-bytes": "OTA failai baitais", + "ws-title": "WS", + "unlimited": "(0 – neribota)", + "maximum-devices": "Didžiausias įrenginių skaičius", + "maximum-devices-required": "Didžiausias įrenginių skaičius yra privalomas.", + "maximum-devices-range": "Didžiausias įrenginių skaičius negali būti neigiamas", + "maximum-assets": "Didžiausias išteklių (asset) skaičius", + "maximum-assets-required": "Didžiausias išteklių (asset) skaičius yra privalomas.", + "maximum-assets-range": "Didžiausias išteklių (asset) skaičius negali būti neigiamas", + "maximum-customers": "Didžiausias klientų skaičius", + "maximum-customers-required": "Didžiausias klientų skaičius yra privalomas.", + "maximum-customers-range": "Didžiausias klientų skaičius negali būti neigiamas", + "maximum-users": "Didžiausias vartotojų skaičius", + "maximum-users-required": "Didžiausias vartotojų skaičius yra privalomas.", + "maximum-users-range": "Didžiausias vartotojų skaičius negali būti neigiamas", + "maximum-dashboards": "Didžiausias skydelių (dashboard) skaičius", + "maximum-dashboards-required": "Didžiausias skydelių (dashboard) skaičius yra privalomas.", + "maximum-dashboards-range": "Didžiausias skydelių (dashboard) skaičius negali būti neigiamas", + "maximum-edges": "Didžiausias Edge įrenginių skaičius", + "maximum-edges-required": "Didžiausias Edge įrenginių skaičius yra privalomas.", + "maximum-edges-range": "Didžiausias Edge įrenginių skaičius negali būti neigiamas", + "maximum-rule-chains": "Didžiausias taisyklių grandinių (rule chains) skaičius", + "maximum-rule-chains-required": "Didžiausias taisyklių grandinių (rule chains) skaičius yra privalomas.", + "maximum-rule-chains-range": "Didžiausias taisyklių grandinių (rule chains) skaičius negali būti neigiamas", + "maximum-resources-sum-data-size": "Išteklių failų bendras dydis", + "maximum-resources-sum-data-size-required": "Išteklių failų bendras dydis yra privalomas.", + "maximum-resources-sum-data-size-range": "Išteklių failų bendras dydis negali būti neigiamas", + "maximum-resource-size": "Didžiausias vieno ištekliaus failo dydis (baitais)", + "maximum-resource-size-required": "Didžiausias ištekliaus failo dydis yra privalomas.", + "maximum-resource-size-range": "Didžiausias ištekliaus failo dydis negali būti neigiamas", + "maximum-ota-packages-sum-data-size": "OTA paketų failų bendras dydis", + "maximum-ota-package-sum-data-size-required": "OTA paketų failų bendras dydis yra privalomas.", + "maximum-ota-package-sum-data-size-range": "OTA paketų failų bendras dydis negali būti neigiamas", + "maximum-debug-duration-min": "Didžiausia derinimo trukmė (minutėmis)", + "maximum-debug-duration-min-range": "Didžiausia derinimo trukmė negali būti neigiama", + "rest-requests-for-tenant": "REST užklausos nuomininkui", + "transport-tenant-telemetry-msg-rate-limit": "Nuomininko telemetrijos pranešimų limitas", + "transport-tenant-telemetry-data-points-rate-limit": "Nuomininko telemetrijos duomenų taškų limitas", + "transport-device-msg-rate-limit": "Įrenginių pranešimų limitas", + "transport-device-telemetry-msg-rate-limit": "Įrenginių telemetrijos pranešimų limitas", + "transport-device-telemetry-data-points-rate-limit": "Įrenginių telemetrijos duomenų taškų limitas", + "transport-gateway-msg-rate-limit": "Šliuzo pranešimų limitas", + "transport-gateway-telemetry-msg-rate-limit": "Šliuzo telemetrijos pranešimų limitas", + "transport-gateway-telemetry-data-points-rate-limit": "Šliuzo telemetrijos duomenų taškų limitas", + "transport-gateway-device-msg-rate-limit": "Šliuzo įrenginių pranešimų limitas", + "transport-gateway-device-telemetry-msg-rate-limit": "Šliuzo įrenginių telemetrijos pranešimų limitas", + "transport-gateway-device-telemetry-data-points-rate-limit": "Šliuzo įrenginių telemetrijos duomenų taškų limitas", + "tenant-entity-export-rate-limit": "Objektų versijų kūrimo limitas", + "tenant-entity-import-rate-limit": "Objektų versijų įkėlimo limitas", + "tenant-notification-request-rate-limit": "Pranešimų užklausų limitas", + "tenant-notification-requests-per-rule-rate-limit": "Pranešimų užklausų limitas pagal taisyklę", + "max-calculated-fields": "Didžiausias apskaičiuojamų laukų skaičius vienam subjektui", + "max-calculated-fields-range": "Apskaičiuojamų laukų skaičius negali būti neigiamas", + "max-calculated-fields-required": "Didžiausias apskaičiuojamų laukų skaičius vienam subjektui yra privalomas", + "max-data-points-per-rolling-arg": "Didžiausias duomenų taškų skaičius slenkančiuose argumentuose", + "max-data-points-per-rolling-arg-range": "Didžiausias duomenų taškų skaičius slenkančiuose argumentuose negali būti neigiamas", + "max-data-points-per-rolling-arg-required": "Didžiausias duomenų taškų skaičius slenkančiuose argumentuose yra privalomas", + "max-arguments-per-cf": "Didžiausias argumentų skaičius viename apskaičiuojamame lauke", + "max-arguments-per-cf-range": "Didžiausias argumentų skaičius viename apskaičiuojamame lauke negali būti neigiamas", + "max-arguments-per-cf-required": "Didžiausias argumentų skaičius viename apskaičiuojamame lauke yra privalomas", + "max-state-size": "Didžiausias būsenos dydis (KB)", + "max-state-size-range": "Didžiausias būsenos dydis (KB) negali būti neigiamas", + "max-state-size-required": "Didžiausias būsenos dydis (KB) yra privalomas", + "max-value-argument-size": "Didžiausias vieno argumento reikšmės dydis (KB)", + "max-value-argument-size-range": "Didžiausias vieno argumento reikšmės dydis (KB) negali būti neigiamas", + "max-value-argument-size-required": "Didžiausias vieno argumento reikšmės dydis (KB) yra privalomas", + "max-transport-messages": "Didžiausias transporto pranešimų skaičius", + "max-transport-messages-required": "Didžiausias transporto pranešimų skaičius yra privalomas.", + "max-transport-messages-range": "Didžiausias transporto pranešimų skaičius negali būti neigiamas", + "max-transport-data-points": "Didžiausias transporto duomenų taškų skaičius", + "max-transport-data-points-required": "Didžiausias transporto duomenų taškų skaičius yra privalomas.", + "max-transport-data-points-range": "Didžiausias transporto duomenų taškų skaičius negali būti neigiamas", + "max-r-e-executions": "Didžiausias taisyklių variklio vykdymų skaičius", + "max-r-e-executions-required": "Didžiausias taisyklių variklio vykdymų skaičius yra privalomas.", + "max-r-e-executions-range": "Didžiausias taisyklių variklio vykdymų skaičius negali būti neigiamas", + "max-j-s-executions": "Didžiausias JavaScript vykdymų skaičius", + "max-j-s-executions-required": "Didžiausias JavaScript vykdymų skaičius yra privalomas.", + "max-j-s-executions-range": "Didžiausias JavaScript vykdymų skaičius negali būti neigiamas", + "max-tbel-executions": "Didžiausias TBEL vykdymų skaičius", + "max-tbel-executions-required": "Didžiausias TBEL vykdymų skaičius yra privalomas.", + "max-tbel-executions-range": "Didžiausias TBEL vykdymų skaičius negali būti neigiamas", + "max-d-p-storage-days": "Didžiausias duomenų taškų saugojimo dienų skaičius", + "max-d-p-storage-days-required": "Didžiausias duomenų taškų saugojimo dienų skaičius yra privalomas.", + "max-d-p-storage-days-range": "Didžiausias duomenų taškų saugojimo dienų skaičius negali būti neigiamas", + "default-storage-ttl-days": "Numatytasis duomenų saugojimo laikotarpis (TTL dienomis)", + "default-storage-ttl-days-required": "Numatytasis duomenų saugojimo laikotarpis (TTL) yra privalomas.", + "default-storage-ttl-days-range": "Numatytasis duomenų saugojimo laikotarpis (TTL) negali būti neigiamas", + "alarms-ttl-days": "Pavojaus signalų TTL (dienomis)", + "alarms-ttl-days-required": "Pavojaus signalų TTL (dienomis) yra privalomas", + "alarms-ttl-days-days-range": "Pavojaus signalų TTL (dienomis) negali būti neigiamas", + "rpc-ttl-days": "RPC TTL (dienomis)", + "rpc-ttl-days-required": "RPC TTL (dienomis) yra privalomas", + "rpc-ttl-days-days-range": "RPC TTL (dienomis) negali būti neigiamas", + "queue-stats-ttl-days": "Eilių statistikos TTL (dienomis)", + "queue-stats-ttl-days-required": "Eilių statistikos TTL (dienomis) yra privalomas", + "queue-stats-ttl-days-range": "Eilių statistikos TTL (dienomis) negali būti neigiamas", + "rule-engine-exceptions-ttl-days": "Taisyklių variklio išimčių TTL (dienomis)", + "rule-engine-exceptions-ttl-days-required": "Taisyklių variklio išimčių TTL (dienomis) yra privalomas", + "rule-engine-exceptions-ttl-days-range": "Taisyklių variklio išimčių TTL (dienomis) negali būti neigiamas", + "max-rule-node-executions-per-message": "Didžiausias taisyklių mazgo vykdymų skaičius vienai žinutei", + "max-rule-node-executions-per-message-required": "Didžiausias taisyklių mazgo vykdymų skaičius vienai žinutei yra privalomas.", + "max-rule-node-executions-per-message-range": "Didžiausias taisyklių mazgo vykdymų skaičius vienai žinutei negali būti neigiamas", + "max-emails": "Didžiausias išsiųstų el. laiškų skaičius", + "max-emails-required": "Didžiausias išsiųstų el. laiškų skaičius yra privalomas.", + "max-emails-range": "Didžiausias išsiųstų el. laiškų skaičius negali būti neigiamas", + "sms-enabled": "SMS siuntimas įjungtas", + "max-sms": "Didžiausias išsiųstų SMS skaičius", + "max-sms-required": "Didžiausias išsiųstų SMS skaičius yra privalomas.", + "max-sms-range": "Didžiausias išsiųstų SMS skaičius negali būti neigiamas", + "max-created-alarms": "Didžiausias sukurtų pavojaus signalų skaičius", + "max-created-alarms-required": "Didžiausias sukurtų pavojaus signalų skaičius yra privalomas.", + "max-created-alarms-range": "Didžiausias sukurtų pavojaus signalų skaičius negali būti neigiamas", + "no-queue": "Eilė nesukonfigūruota", + "add-queue": "Pridėti eilę", + "queues-with-count": "Eilės ({{count}})", + "tenant-rest-limits": "REST užklausų limitas nuomininkui", + "customer-rest-limits": "REST užklausų limitas klientui", + "incorrect-pattern-for-rate-limits": "Formatas turi būti kableliais atskirtos poros su talpa ir laikotarpiu (sekundėmis), pvz.: 100:1,2000:60", + "too-small-value-zero": "Reikšmė turi būti didesnė nei 0", + "too-small-value-one": "Reikšmė turi būti didesnė nei 1", + "queue-size-is-limited-by-system-configuration": "Eilės dydis taip pat yra ribojamas sistemos konfigūracijos.", + "cassandra-write-tenant-core-limits-configuration": "REST API Cassandra rašymo užklausos", + "cassandra-read-tenant-core-limits-configuration": "REST API ir WS telemetrijos Cassandra skaitymo užklausos", + "cassandra-write-tenant-rule-engine-limits-configuration": "Taisyklių variklio telemetrijos Cassandra rašymo užklausos", + "cassandra-read-tenant-rule-engine-limits-configuration": "Taisyklių variklio telemetrijos Cassandra skaitymo užklausos", + "ws-limit-max-sessions-per-tenant": "Didžiausias sesijų skaičius vienam nuomininkui", + "ws-limit-max-sessions-per-customer": "Didžiausias sesijų skaičius vienam klientui", + "ws-limit-max-sessions-per-regular-user": "Didžiausias sesijų skaičius vienam vartotojui", + "ws-limit-max-sessions-per-public-user": "Didžiausias sesijų skaičius viešam vartotojui", + "ws-limit-queue-per-session": "Didžiausias pranešimų eilės dydis vienai sesijai", + "ws-limit-max-subscriptions-per-tenant": "Didžiausias prenumeratų skaičius vienam nuomininkui", + "ws-limit-max-subscriptions-per-customer": "Didžiausias prenumeratų skaičius vienam klientui", + "ws-limit-max-subscriptions-per-regular-user": "Didžiausias prenumeratų skaičius vienam vartotojui", + "ws-limit-max-subscriptions-per-public-user": "Didžiausias prenumeratų skaičius viešam vartotojui", + "ws-limit-updates-per-session": "WS atnaujinimų skaičius vienai sesijai", + "rate-limits": { + "add-limit": "Pridėti limitą", + "and-also-less-than": "ir taip pat mažesnis nei", + "advanced-settings": "Pažangūs nustatymai", + "edit-limit": "Redaguoti limitą", + "calculated-field-debug-event-rate-limit": "Apskaičiuojamų laukų derinimo įvykių limitas", + "edit-calculated-field-debug-event-rate-limit": "Redaguoti apskaičiuojamų laukų derinimo įvykių limitus", + "edit-transport-tenant-msg-title": "Redaguoti nuomininko transporto pranešimų limitus", + "edit-transport-tenant-telemetry-msg-title": "Redaguoti nuomininko telemetrijos pranešimų limitus", + "edit-transport-tenant-telemetry-data-points-title": "Redaguoti nuomininko telemetrijos duomenų taškų limitus", + "edit-transport-device-msg-title": "Redaguoti įrenginių transporto pranešimų limitus", + "edit-transport-device-telemetry-msg-title": "Redaguoti įrenginių telemetrijos pranešimų limitus", + "edit-transport-device-telemetry-data-points-title": "Redaguoti įrenginių telemetrijos duomenų taškų limitus", + "edit-transport-gateway-msg-title": "Redaguoti šliuzo pranešimų limitus", + "edit-transport-gateway-telemetry-msg-title": "Redaguoti šliuzo telemetrijos pranešimų limitus", + "edit-transport-gateway-telemetry-data-points-title": "Redaguoti šliuzo telemetrijos duomenų taškų limitus", + "edit-transport-gateway-device-msg-title": "Redaguoti šliuzo įrenginių pranešimų limitus", + "edit-transport-gateway-device-telemetry-msg-title": "Redaguoti šliuzo įrenginių telemetrijos pranešimų limitus", + "edit-transport-gateway-device-telemetry-data-points-title": "Redaguoti šliuzo įrenginių telemetrijos duomenų taškų limitus", + "edit-tenant-rest-limits-title": "Redaguoti REST užklausų limitus nuomininkui", + "edit-customer-rest-limits-title": "Redaguoti REST užklausų limitus klientui", + "edit-ws-limit-updates-per-session-title": "Redaguoti WS atnaujinimų per sesiją limitus", + "edit-cassandra-write-tenant-core-limits-configuration": "Redaguoti REST API Cassandra rašymo užklausų limitus", + "edit-cassandra-read-tenant-core-limits-configuration": "Redaguoti REST API ir WS telemetrijos Cassandra skaitymo užklausų limitus", + "edit-cassandra-write-tenant-rule-engine-limits-configuration": "Redaguoti taisyklių variklio telemetrijos Cassandra rašymo užklausų limitus", + "edit-cassandra-read-tenant-rule-engine-limits-configuration": "Redaguoti taisyklių variklio telemetrijos Cassandra skaitymo užklausų limitus", + "edit-tenant-entity-export-rate-limit-title": "Redaguoti objektų versijų kūrimo limitus", + "edit-tenant-entity-import-rate-limit-title": "Redaguoti objektų versijų įkėlimo limitus", + "edit-tenant-notification-request-rate-limit-title": "Redaguoti pranešimų užklausų limitus", + "edit-tenant-notification-requests-per-rule-rate-limit-title": "Redaguoti pranešimų užklausų limitus pagal taisyklę", + "edit-edge-events-rate-limit": "Redaguoti Edge įvykių limitus", + "edit-edge-events-per-edge-rate-limit": "Redaguoti Edge įvykių limitus pagal Edge įrenginį", + "edge-events-rate-limit": "Edge įvykiai", + "edge-events-per-edge-rate-limit": "Edge įvykiai pagal Edge įrenginį", + "edit-edge-uplink-messages-rate-limit": "Redaguoti Edge į viršų siunčiamų pranešimų (uplink) limitus", + "edit-edge-uplink-messages-per-edge-rate-limit": "Redaguoti Edge į viršų siunčiamų pranešimų (uplink) limitus pagal Edge įrenginį", + "edge-uplink-messages-rate-limit": "Edge uplink pranešimai", + "edge-uplink-messages-per-edge-rate-limit": "Edge uplink pranešimai pagal Edge įrenginį", + "messages-per": "pranešimų per", + "not-set": "Nenustatyta", + "number-of-messages": "Pranešimų skaičius", + "number-of-messages-required": "Pranešimų skaičius yra privalomas.", + "number-of-messages-min": "Mažiausia reikšmė yra 1.", + "preview": "Peržiūra", + "per-seconds": "Per sekundes", + "per-seconds-required": "Laiko norma yra privaloma.", + "per-seconds-min": "Mažiausia reikšmė yra 1.", + "per-seconds-duplicate": "Pasikartojanti laiko norma. Kiekvienas laiko intervalas turi būti unikalus.", + "rate-limits": "Greitaveikos limitai", + "remove-limit": "Pašalinti limitą", + "transport-tenant-msg": "Nuomininko transporto pranešimai", + "transport-tenant-telemetry-msg": "Nuomininko telemetrijos pranešimai", + "transport-tenant-telemetry-data-points": "Nuomininko telemetrijos duomenų taškai", + "transport-device-msg": "Įrenginių transporto pranešimai", + "transport-device-telemetry-msg": "Įrenginių telemetrijos pranešimai", + "transport-device-telemetry-data-points": "Įrenginių telemetrijos duomenų taškai", + "transport-gateway-msg": "Šliuzo pranešimai", + "transport-gateway-telemetry-msg": "Šliuzo telemetrijos pranešimai", + "transport-gateway-telemetry-data-points": "Šliuzo telemetrijos duomenų taškai", + "transport-gateway-device-msg": "Šliuzo įrenginių pranešimai", + "transport-gateway-device-telemetry-msg": "Šliuzo įrenginių telemetrijos pranešimai", + "transport-gateway-device-telemetry-data-points": "Šliuzo įrenginių telemetrijos duomenų taškai", + "sec": "sek." + } + }, + "timeinterval": { + "seconds-interval": "{ seconds, plural, =1 {1 sekundė} other {# sekundės} }", + "minutes-interval": "{ minutes, plural, =1 {1 minutė} other {# minutės} }", + "hours-interval": "{ hours, plural, =1 {1 valanda} other {# valandos} }", + "days-interval": "{ days, plural, =1 {1 diena} other {# dienos} }", + "days": "Dienos", + "hours": "Valandos", + "minutes": "Minutės", + "seconds": "Sekundės", + "advanced": "Išplėstiniai nustatymai", + "custom": "Pasirinktinis", + "predefined": { + "yesterday": "Vakar", + "day-before-yesterday": "Užvakar", + "this-day-last-week": "Ši diena prieš savaitę", + "previous-week": "Praėjusi savaitė (Sek – Šeš)", + "previous-week-iso": "Praėjusi savaitė (Pir – Sek)", + "previous-month": "Praėjęs mėnuo", + "previous-quarter": "Praėjęs ketvirtis", + "previous-half-year": "Praėjęs pusmetis", + "previous-year": "Praėję metai", + "current-hour": "Dabartinė valanda", + "current-day": "Dabartinė diena", + "current-day-so-far": "Dabartinė diena iki dabar", + "current-week": "Dabartinė savaitė (Sek – Šeš)", + "current-week-iso": "Dabartinė savaitė (Pir – Sek)", + "current-week-so-far": "Dabartinė savaitė iki dabar (Sek – Šeš)", + "current-week-iso-so-far": "Dabartinė savaitė iki dabar (Pir – Sek)", + "current-month": "Dabartinis mėnuo", + "current-month-so-far": "Dabartinis mėnuo iki dabar", + "current-quarter": "Dabartinis ketvirtis", + "current-quarter-so-far": "Dabartinis ketvirtis iki dabar", + "current-half-year": "Dabartinis pusmetis", + "current-half-year-so-far": "Dabartinis pusmetis iki dabar", + "current-year": "Dabartiniai metai", + "current-year-so-far": "Dabartiniai metai iki dabar" + }, + "type": { + "week": "Savaitė (Sek – Šeš)", + "week-iso": "Savaitė (Pir – Sek)", + "month": "Mėnuo", + "quarter": "Ketvirtis" + } + }, + "timeunit": { + "milliseconds": "Milisekundės", + "seconds": "Sekundės", + "minutes": "Minutės", + "hours": "Valandos", + "days": "Dienos" + }, + "timewindow": { + "timewindow": "Laiko langas", + "timewindow-settings": "Laiko lango nustatymai", + "years": "{ years, plural, =1 { metai } other {# metai } }", + "years-short": "{{ years }}m", + "months": "{ months, plural, =1 { mėnuo } other {# mėnesiai } }", + "months-short": "{{ months }}mėn", + "weeks": "{ weeks, plural, =1 { savaitė } other {# savaitės } }", + "weeks-short": "{{ weeks }}sav", + "days": "{ days, plural, =1 { diena } other {# dienos } }", + "days-short": "{{ days }}d", + "hours": "{ hours, plural, =0 { valandų } =1 {1 valanda } other {# valandos } }", + "hr": "{{ hr }} val", + "hr-short": "{{ hr }}val", + "minutes": "{ minutes, plural, =0 { minučių } =1 {1 minutė } other {# minutės } }", + "min": "{{ min }} min", + "min-short": "{{ min }}min", + "seconds": "{ seconds, plural, =0 { sekundžių } =1 {1 sekundė } other {# sekundės } }", + "sec": "{{ sec }} sek", + "sec-short": "{{ sec }}s", + "short": { + "years": "{ years, plural, =1 {1 metai } other {# metai } }", + "days": "{ days, plural, =1 {1 diena } other {# dienos } }", + "hours": "{ hours, plural, =1 {1 valanda } other {# valandos } }", + "minutes": "{{ minutes }} min", + "seconds": "{{ seconds }} sek" + }, + "realtime": "Realiu laiku", + "history": "Istorija", + "last-prefix": "Paskutinė", + "period": "nuo {{ startTime }} iki {{ endTime }}", + "edit": "Redaguoti laiko langą", + "date-range": "Datų intervalas", + "for-all-time": "Visas laikotarpis", + "last": "Paskutinė", + "time-period": "Laikotarpis", + "hide": "Slėpti", + "interval": "Intervalas", + "just-now": "Ką tik", + "just-now-lower": "ką tik", + "ago": "prieš", + "style": "Laiko lango stilius", + "icon": "Piktograma", + "icon-position": "Piktogramos padėtis", + "icon-position-left": "Kairėje", + "icon-position-right": "Dešinėje", + "font": "Šriftas", + "color": "Spalva", + "displayTypePrefix": "Rodyti „Realiu laiku“ / „Istorija“ priešdėlį", + "preview": "Peržiūra", + "relative": "Santykinis", + "range": "Intervalas", + "hide-timewindow-section": "Slėpti laiko lango sekciją nuo naudotojų", + "hide-last-interval": "Slėpti paskutinį intervalą nuo naudotojų", + "hide-relative-interval": "Slėpti santykinį intervalą nuo naudotojų", + "hide-fixed-interval": "Slėpti fiksuotą intervalą nuo naudotojų", + "hide-aggregation": "Slėpti agregaciją nuo naudotojų", + "hide-group-interval": "Slėpti grupavimo intervalą nuo naudotojų", + "hide-max-values": "Slėpti maksimalias reikšmes nuo naudotojų", + "hide-timezone": "Slėpti laiko juostą nuo naudotojų", + "disable-custom-interval": "Išjungti pasirinktinių intervalų pasirinkimą", + "edit-aggregation-functions-list": "Redaguoti agregavimo funkcijų sąrašą", + "edit-aggregation-functions-list-hint": "Galima nurodyti galimų funkcijų sąrašą.", + "allowed-aggregation-functions": "Leidžiamos agregavimo funkcijos", + "edit-intervals-list": "Redaguoti intervalų sąrašą", + "allowed-agg-intervals": "Grupavimo intervalai", + "default-agg-interval": "Numatytasis grupavimo intervalas", + "edit-intervals-list-hint": "Galima nurodyti galimų intervalų parinkčių sąrašą.", + "edit-grouping-intervals-list-hint": "Galima sukonfigūruoti grupavimo intervalų sąrašą ir numatytąjį grupavimo intervalą.", + "all": "Visi" + }, + "tooltip": { + "trigger": "Trigeris", + "trigger-point": "Taškas", + "trigger-axis": "Ašis", + "label": "Etiketė", + "value": "Reikšmė", + "date": "Data", + "show-date-time-interval": "Rodyti datos ir laiko intervalą", + "show-date-time-interval-hint": "Rodyti datos ir laiko intervalą pagal duomenų agregaciją.", + "hide-zero-tooltip-values": "Slėpti nulines reikšmes", + "background-color": "Fono spalva", + "background-blur": "Fono suliejimas" + }, + "unit": { + "set-unit-conversion": "Nustatyti matavimo vienetų konvertavimą", + "unit-settings": { + "unit-settings": "Vienetų nustatymai", + "source-unit": "Pirminis vienetas", + "source-unit-hint": "Tai saugomos reikšmės vienetas. Vienetas, iš kurio konvertuojama. Įveskite simbolį, naudojamą jūsų šaltinio duomenyse (pvz., m, km, ft, in).", + "target-metric-unit": "Tikslinis metrinis vienetas", + "target-metric-unit-hint": "Pasirinkite, į kurį metrinį (SI) vienetą konvertuoti šaltinio reikšmę (pvz., cm, mm, km).", + "target-imperial-unit": "Tikslinis imperinis vienetas", + "target-imperial-unit-hint": "Pasirinkite, į kurį imperinį vienetą konvertuoti šaltinio reikšmę (pvz., in, ft, yd).", + "target-hybrid-unit": "Tikslinis mišrus vienetas", + "target-hybrid-unit-hint": "Pasirinkite, į kurį mišrų vienetą konvertuoti šaltinio reikšmę (pvz., cm, in, km). Mišrūs vienetai jungia metrinius ir/arba imperinius vienetus.", + "enable-unit-conversion": "Įjungti vienetų konvertavimą", + "enable-unit-conversion-hint": "Įjunkite, kad suaktyvintumėte konvertavimą. Kai išjungta – šaltinio reikšmė bus perduodama nekeičiama. Išjungta, jei atitinkamoje matavimo grupėje yra tik vienas vienetas (pvz., šviesos srautas, OKI)." + }, + "unit-system": "Matavimo sistema", + "unit-system-type": { + "AUTO": "Automatinė", + "METRIC": "Metrinė", + "IMPERIAL": "Imperinė", + "HYBRID": "Mišri" + }, + "measures": { + "absorbed-dose-rate": "Sugertos dozės greitis", + "acceleration": "Pagreitis", + "acidity": "Rūgštingumas", + "air-quality-index": "Oro kokybės indeksas", + "amount-of-substance": "Medžiagos kiekis", + "angle": "Kampas", + "angular-acceleration": "Kampinis pagreitis", + "area": "Plotas", + "area-density": "Paviršiaus tankis", + "capacitance": "Talpa", + "catalytic-activity": "Katalizinė veikla", + "catalytic-concentration": "Katalizinė koncentracija", + "charge": "Krovinys", + "current-density": "Srovės tankis", + "data-transfer-rate": "Duomenų perdavimo greitis", + "density": "Tankis", + "digital": "Skaitmeninis", + "dimension-ratio": "Matmenų santykis", + "dynamic-viscosity": "Dinaminė klampa", + "earthquake-magnitude": "Žemės drebėjimo stiprumas", + "electric-charge-density": "Elektros krūvio tankis", + "electric-current": "Elektros srovė", + "electric-dipole-moment": "Elektrinis dipolio momentas", + "electric-field-strength": "Elektrinio lauko stipris", + "electric-flux": "Elektrinis srautas", + "electric-permittivity": "Elektrinė skvarba", + "electric-polarizability": "Elektrinė poliariškumas", + "electrical-conductance": "Elektrinė laidumo varža", + "electrical-conductivity": "Elektrinis laidumas", + "energy": "Energija", + "energy-density": "Energijos tankis", + "force": "Jėga", + "frequency": "Dažnis", + "fuel-efficiency": "Kuro sąnaudos / efektyvumas", + "heat-capacity": "Šiluminė talpa", + "illuminance": "Apšvietis", + "inductance": "Induktyvumas", + "kinematic-viscosity": "Kinematinė klampa", + "length": "Ilgis", + "light-exposure": "Šviesos ekspozicija", + "linear-charge-density": "Linijinis krūvio tankis", + "logarithmic-ratio": "Logaritminis santykis", + "luminous-efficacy": "Šviesos efektyvumas", + "luminous-flux": "Šviesos srautas", + "luminous-intensity": "Šviesos stipris", + "magnetic-field-gradient": "Magnetinio lauko gradientas", + "magnetic-flux": "Magnetinis srautas", + "magnetic-flux-density": "Magnetinio srauto tankis", + "magnetic-moment": "Magnetinis momentas", + "magnetic-permeability": "Magnetinė skvarba", + "mass": "Masa", + "mass-fraction": "Masės dalis", + "molar-concentration": "Molinė koncentracija", + "molar-energy": "Molinė energija", + "molar-heat-capacity": "Molinė šiluminė talpa", + "molar-mass": "Molinė masė", + "number-concentration": "Dalelių koncentracija", + "parts-per-million": "Dalinės dalys milijone (ppm)", + "power": "Galia", + "power-density": "Galios tankis", + "pressure": "Slėgis", + "radiance": "Spinduliuotė", + "radiant-intensity": "Spinduliuotės intensyvumas", + "radiation-dose": "Radiacijos dozė", + "radioactive-decay": "Radioaktyvus skilimas", + "radioactivity": "Radioaktyvumas", + "radioactivity-concentration": "Radioaktyvumo koncentracija", + "reciprocal-length": "Atvirkštinis ilgis", + "resistance": "Varža", + "reynolds-number": "Reinoldso skaičius", + "signal-level": "Signalo lygis", + "solid-angle": "Erdvinis kampas", + "specific-energy": "Specifinė energija", + "specific-heat-capacity": "Specifinė šiluminė talpa", + "specific-humidity": "Specifinė drėgmė", + "specific-volume": "Specifinis tūris", + "speed": "Greičio", + "surface-charge-density": "Paviršiaus krūvio tankis", + "surface-tension": "Paviršiaus įtempimas", + "temperature": "Temperatūra", + "thermal-conductivity": "Šilumos laidumas", + "time": "Laikas", + "torque": "Sukimo momentas", + "turbidity": "Drumstumas", + "voltage": "Įtampa", + "volume": "Tūris", + "volume-flow": "Tūrio srautas" + }, + "millimeter": "Milimetras", + "centimeter": "Centimetras", + "decimeter": "Decimetras", + "angstrom": "Angstromas", + "nanometer": "Nanometras", + "micrometer": "Mikrometras", + "meter": "Metras", + "kilometer": "Kilometras", + "inch": "Colis", + "foot": "Pėda", + "foot-us": "Pėda (JAV matavimas)", + "yard": "Jardas", + "mile": "Mylia", + "nautical-mile": "Jūrmylė", + "astronomical-unit": "Astronominis vienetas", + "reciprocal-metre": "Atvirkštinis metras", + "meter-per-meter": "Metrai vienam metrui", + "steradian": "Steradianas", + "thou": "Tausas", + "barleycorn": "Miežio grūdas", + "hand": "Rankos ilgis", + "chain": "Grandinė", + "furlong": "Furlongas", + "league": "Lygos vienetas", + "fathom": "Sazenas", + "cable": "Kabelis", + "link": "Nuoroda", + "rod": "Lazda", + "nanogram": "Nanogramas", + "microgram": "Mikrogramas", + "milligram": "Miligramas", + "gram": "Gramas", + "kilogram": "Kilogramas", + "tonne": "Tona", + "ounce": "Uncija", + "pound": "Svaras", + "stone": "Akmuo (matavimo vienetas)", + "hundredweight-count": "Svorinė šimtinė", + "short-tons": "Trumpa tona", + "dalton": "Daltonas", + "grain": "Grūdas", + "drachm": "Drachma", + "quarter": "Ketvirtis", + "slug": "Slugas", + "carat": "Karat", + "cubic-millimeter": "Kubinis milimetras", + "cubic-centimeter": "Kubinis centimetras", + "cubic-meter": "Kubinis metras", + "cubic-kilometer": "Kubinis kilometras", + "microliter": "Mikrolitras", + "milliliter": "Mililitras", + "liter": "Litras", + "hectoliter": "Hektolitras", + "cubic-inch": "Kubinis colis", + "cubic-foot": "Kubinė pėda", + "cubic-yard": "Kubinis jardas", + "fluid-ounce": "Skysčio uncija", + "fluid-ounce-per-second": "Skysčio uncija per sekundę", + "pint": "Pinta", + "quart": "Kvorta", + "gallon": "Galonas", + "oil-barrels": "Naftos statinė", + "cubic-meter-per-kilogram": "Kubinis metras kilogramui", + "gill": "Gilas", + "hogshead": "Statinė (Hogshead)", + "teaspoon": "Arbatinis šaukštelis", + "tablespoon": "Valgomasis šaukštas", + "cup": "Puodelis", + "celsius": "Celsijus", + "kelvin": "Kelvinas", + "rankine": "Rankinas", + "fahrenheit": "Farenheitas", + "percent": "Procentas", + "meter-per-second": "Metrai per sekundę", + "kilometer-per-hour": "Kilometrai per valandą", + "foot-per-second": "Pėdos per sekundę", + "foot-per-minute": "Pėdos per minutę", + "mile-per-hour": "Mylios per valandą", + "knot": "Mazgas", + "inch-per-second": "Coliai per sekundę", + "inch-per-hour": "Coliai per valandą", + "millimeters-per-minute": "Milimetrai per minutę", + "meter-per-minute": "Metrai per minutę", + "kilometer-per-hour-squared": "Kilometrai per valandą kvadratu", + "foot-per-second-squared": "Pėdos per sekundę kvadratu", + "pascal": "Paskalis", + "kilopascal": "Kilopaskalis", + "megapascal": "Megapaskalis", + "gigapascal": "Gigapaskalis", + "millibar": "Milibaras", + "bar": "Baras", + "kilobar": "Kilobaras", + "newton": "Niutonas", + "newton-meter": "Niutono metras", + "foot-pounds": "Pėdos-svarai", + "inch-pounds": "Colio-svarai", + "newton-per-meter": "Niutonas metrui", + "atmospheres": "Atmosferos", + "pounds-per-square-inch": "Svarai kvadratiniam coliui", + "kilopound-per-square-inch": "Kilosvarai kvadratiniam coliui", + "torr": "Torras", + "inches-of-mercury": "Gyvsidabrio coliai", + "pascal-per-square-meter": "Paskalis kvadratiniam metrui", + "pound-per-square-inch": "Svoris kvadratiniam coliui", + "newton-per-square-meter": "Niutonas kvadratiniam metrui", + "kilogram-force-per-square-meter": "Kilogramo jėga kvadratiniam metrui", + "pascal-per-square-centimeter": "Paskalis kvadratiniam centimetrui", + "ton-force-per-square-inch": "Tonos jėga kvadratiniam coliui", + "kilonewton-per-square-meter": "Kiloniutonas kvadratiniam metrui", + "newton-per-square-millimeter": "Niutonas kvadratiniam milimetrui", + "microjoule": "Mikrodžiaulis", + "millijoule": "Milidžiaulis", + "joule": "Džiaulis", + "kilojoule": "Kilodžiaulis", + "megajoule": "Megadžiaulis", + "gigajoule": "Gigadžiaulis", + "watt-hour": "Vatvalandė", + "watt-minute": "Vatminutė", + "kilowatt-hour": "Kilovatvalandė", + "milliwatt-hour": "Milivatvalandė", + "megawatt-hour": "Megavatvalandė", + "gigawatt-hour": "Gigavatvalandė", + "electron-volts": "Elektronvoltai", + "joules-per-coulomb": "Džiauliai kulonui", + "british-thermal-unit": "Britų šiluminis vienetas (BTU)", + "thousand-british-thermal-unit": "Tūkstantis britų šiluminių vienetų", + "million-british-thermal-unit": "Milijonas britų šiluminių vienetų", + "foot-pound": "Pėdos-svaras", + "calorie": "Kalorija", + "small-calorie": "Mažoji kalorija", + "kilocalorie": "Kilokalorija", + "joule-per-kelvin": "Džiaulis kelvinui", + "joule-per-kilogram-kelvin": "Džiaulis kilogramui-kelvinui", + "joule-per-kilogram": "Džiaulis kilogramui", + "watt-per-meter-kelvin": "Vatas metrui-kelvinui", + "joule-per-cubic-meter": "Džiaulis kubiniam metrui", + "therm": "Termas", + "electric-dipole-moment": "Elektrinis dipolio momentas", + "magnetic-dipole-moment": "Magnetinis dipolio momentas", + "debye": "Debajus", + "coulomb-per-square-meter-per-volt": "Kulonas kvadratiniam metrui voltui", + "milliwatt": "Miliwatas", + "microwatt": "Mikrovatas", + "watt": "Vatas", + "kilowatt": "Kilovatas", + "megawatt": "Megavatas", + "gigawatt": "Gigavatas", + "metric-horsepower": "Metinė arklio galia", + "milliwatt-per-square-centimeter": "Milivatai kvadratiniam centimetrui", + "watt-per-square-centimeter": "Vatai kvadratiniam centimetrui", + "kilowatt-per-square-centimeter": "Kilovatai kvadratiniam centimetrui", + "milliwatt-per-square-meter": "Milivatai kvadratiniam metrui", + "watt-per-square-meter": "Vatai kvadratiniam metrui", + "kilowatt-per-square-meter": "Kilovatai kvadratiniam metrui", + "watt-per-square-inch": "Vatai kvadratiniam coliui", + "kilowatt-per-square-inch": "Kilovatai kvadratiniam coliui", + "horsepower": "Arklio galia", + "btu-per-hour": "Britų šiluminiai vienetai per valandą", + "btu-per-second": "Britų šiluminiai vienetai per sekundę", + "btu-per-day": "Britų šiluminiai vienetai per dieną", + "mbtu-per-hour": "Tūkstantis britų šiluminių vienetų per valandą", + "mbtu-per-second": "Tūkstantis britų šiluminių vienetų per sekundę", + "mbtu-per-day": "Tūkstantis britų šiluminių vienetų per dieną", + "mmbtu-per-hour": "Milijonas britų šiluminių vienetų per valandą", + "mmbtu-per-second": "Milijonas britų šiluminių vienetų per sekundę", + "mmbtu-per-day": "Milijonas britų šiluminių vienetų per dieną", + "foot-pound-per-second": "Pėdos-svarai per sekundę", + "coulomb": "Kulonas", + "millicoulomb": "Milikulonas", + "microcoulomb": "Mikrokulonas", + "nanocoulomb": "Nanokulonas", + "picocoulomb": "Pikokulonas", + "coulomb-per-meter": "Kulonai metrui", + "coulomb-per-cubic-meter": "Kulonai kubiniam metrui", + "coulomb-per-square-meter": "Kulonai kvadratiniam metrui", + "square-millimeter": "Kvadratinis milimetras", + "square-centimeter": "Kvadratinis centimetras", + "square-meter": "Kvadratinis metras", + "hectare": "Hektaras", + "square-kilometer": "Kvadratinis kilometras", + "square-inch": "Kvadratinis colis", + "square-foot": "Kvadratinė pėda", + "square-yard": "Kvadratinis jardas", + "acre": "Akras", + "square-mile": "Kvadratinė mylia", + "are": "Aras", + "barn": "Barnas", + "circular-inch": "Apskritiminis colis", + "milliampere-hour": "Miliampervalandė", + "ampere-hours": "Ampervalandės", + "kiloampere-hours": "Kiloampervalandės", + "nanoampere": "Nanoamperas", + "picoampere": "Pikoamperas", + "microampere": "Mikroamperas", + "milliampere": "Miliamperas", + "ampere": "Amperas", + "kiloampere": "Kiloamperas", + "megaampere": "Megaamperas", + "gigaampere": "Gigaamperas", + "microampere-per-square-centimeter": "Mikroamperai kvadratiniam centimetrui", + "ampere-per-square-meter": "Amperai kvadratiniam metrui", + "ampere-per-meter": "Amperai metrui", + "oersted": "Erstedas", + "bohr-magneton": "Boro magnetonas", + "ampere-meter-squared": "Ampermetrai kvadratu", + "nanovolt": "Nanovoltas", + "picovolt": "Pikovoltas", + "millivolt": "Milivoltas", + "microvolt": "Mikrovoltas", + "volt": "Voltas", + "kilovolt": "Kilovoltas", + "megavolt": "Megavoltas", + "dbmV": "dBmV", + "dbm": "Decibelmilivatai", + "volt-meter": "Voltmetras", + "kilovolt-meter": "Kilovoltmetras", + "megavolt-meter": "Megavoltmetras", + "microvolt-meter": "Mikrovoltmetras", + "millivolt-meter": "Milivoltmetras", + "nanovolt-meter": "Nanovoltmetras", + "ohm": "Omas", + "microohm": "Mikroomas", + "milliohm": "Milioomas", + "kilohm": "Kiloomas", + "megohm": "Megaomas", + "gigohm": "Gigaomas", + "millihertz": "Milihercas", + "hertz": "Hercas", + "kilohertz": "Kilohercas", + "megahertz": "Megahercas", + "gigahertz": "Gigahercas", + "terahertz": "Terahercas", + "rpm": "Apsisukimai per minutę", + "candela-per-square-meter": "Kandela kvadratiniam metrui", + "candela": "Kandela", + "lumen": "Liumenas", + "lux": "Liuksas", + "foot-candle": "Pėdos žvakė", + "lumen-per-square-meter": "Liumenai kvadratiniam metrui", + "lux-second": "Liuksas sekundei", + "lumen-second": "Liumenas sekundei", + "lumens-per-watt": "Liumenai vatui", + "mole": "Molis", + "nanomole": "Nanomolis", + "micromole": "Mikromolis", + "millimole": "Milimolis", + "kilomole": "Kilomolis", + "mole-per-cubic-meter": "Moliai kubiniam metrui", + "rssi": "RSSI (signalo stiprumas)", + "ppm": "Dalis milijone (ppm)", + "ppb": "Dalis milijarde (ppb)", + "micrograms-per-cubic-meter": "Mikrogramai kubiniam metrui", + "aqi": "Oro kokybės indeksas (OKI)", + "gram-per-cubic-meter": "Gramai kubiniam metrui", + "gram-per-kilogram": "Specifinis drėgnis (g/kg)", + "millimeters-per-second": "Milimetrai per sekundę", + "neper": "Neperas", + "bel": "Belas", + "decibel": "Decibelas", + "meters-per-second-squared": "Metrai per sekundę kvadratu", + "becquerel": "Bekerelis", + "curie": "Kiuris", + "gray": "Grėjus", + "sievert": "Zyvertas", + "roentgen": "Rentgenas", + "cps": "Impulsai per sekundę", + "rad": "Radas", + "rem": "Remas", + "dps": "Skaidymasis per sekundę", + "rutherford": "Ruterfordas", + "coulombs-per-kilogram": "Kulonai kilogramui", + "becquerels-per-cubic-meter": "Bekereliai kubiniam metrui", + "curies-per-liter": "Kiuriai litrui", + "becquerels-per-second": "Bekereliai per sekundę", + "curies-per-second": "Kiuriai per sekundę", + "gy-per-second": "Grėjai per sekundę", + "watt-per-steradian": "Vatai steradianui", + "watt-per-square-metre-steradian": "Vatai kvadratiniam metrui-steradianui", + "ph-level": "pH lygis", + "turbidity": "Drumstumas", + "mg-per-liter": "Miligramai litrui", + "microsiemens-per-centimeter": "Mikrosiemensai centimetrui", + "millisiemens-per-meter": "Milisiemensai metrui", + "siemens-per-meter": "Siemensai metrui", + "kilogram-per-cubic-meter": "Kilogramai kubiniam metrui", + "gram-per-cubic-centimeter": "Gramai kubiniam centimetrui", + "kilogram-per-square-meter": "Kilogramai kvadratiniam metrui", + "milligram-per-milliliter": "Miligramai mililitrui", + "milligram-per-cubic-meter": "Miligramai kubiniam metrui", + "pound-per-cubic-foot": "Svarai kubinei pėdai", + "ounces-per-cubic-inch": "Uncijos kubiniam coliui", + "tons-per-cubic-yard": "Tonos kubiniam jardui", + "particle-density": "Dalinė tankio vertė", + "kilometers-per-liter": "Kilometrai litrui", + "miles-per-gallon": "Mylios galonui", + "liters-per-100-km": "Litrai 100 kilometrų", + "gallons-per-mile": "Galonai myliai", + "liters-per-hour": "Litrai per valandą", + "gallons-per-hour": "Galonai per valandą", + "beats-per-minute": "Dūžiai per minutę", + "millimeters-of-mercury": "Gyvsidabrio milimetrai", + "milligrams-per-deciliter": "Miligramai decilitrui", + "g-force": "G-jėga", + "kilonewton": "Kiloniutonas", + "kilogram-force": "Kilogramo jėga", + "pound-force": "Svarinė jėga", + "kilopound-force": "Kilosvarinė jėga", + "dyne": "Dina", + "poundal": "Paundalas", + "kip": "Kipas", + "gal": "Galas", + "gravity": "Gravitacija", + "hectopascal": "Hektopaskalis", + "atmosphere": "Atmosfera", + "millibars": "Milibarai", + "inch-of-mercury": "Gyvsidabrio colis", + "richter-scale": "Richtėro skalė", + "nanosecond": "Nanosekundė", + "microsecond": "Mikrosekundė", + "millisecond": "Milisekundė", + "second": "Sekundė", + "minute": "Minutė", + "hour": "Valanda", + "day": "Diena", + "week": "Savaitė", + "month": "Mėnuo", + "year": "Metai", + "cubic-foot-per-minute": "Kubinės pėdos per minutę", + "cubic-meters-per-hour": "Kubiniai metrai per valandą", + "cubic-meters-per-second": "Kubiniai metrai per sekundę", + "liter-per-second": "Litrai per sekundę", + "liter-per-minute": "Litrai per minutę", + "gallons-per-minute": "Galonai per minutę", + "cubic-foot-per-second": "Kubinė pėda per sekundę", + "milliliters-per-minute": "Mililitrai per minutę", + "cubic-decimeter-per-second": "Kubinis decimetras per sekundę", + "bit": "Bitas", + "byte": "Baitas", + "kilobyte": "Kilobaitas", + "megabyte": "Megabaitas", + "gigabyte": "Gigabaitas", + "terabyte": "Terabaitas", + "petabyte": "Petabaitas", + "exabyte": "Eksabaitas", + "zettabyte": "Zetabaitas", + "yottabyte": "Jotabaitas", + "bit-per-second": "Bitai per sekundę", + "kilobit-per-second": "Kilobitai per sekundę", + "megabit-per-second": "Megabitai per sekundę", + "gigabit-per-second": "Gigabitai per sekundę", + "terabit-per-second": "Terabitai per sekundę", + "byte-per-second": "Baitai per sekundę", + "kilobyte-per-second": "Kilobaitai per sekundę", + "megabyte-per-second": "Megabaitai per sekundę", + "gigabyte-per-second": "Gigabaitai per sekundę", + "degree": "Laipsnis", + "radian": "Radianas", + "gradian": "Gradianas", + "arcminute": "Kampinė minutė", + "arcsecond": "Kampinė sekundė", + "milliradian": "Miliradianas", + "revolution": "Apsisukimas", + "siemens": "Siemensas", + "millisiemens": "Milisiemensas", + "microsiemens": "Mikrosiemensas", + "kilosiemens": "Kilosiemensas", + "megasiemens": "Megasiemensas", + "gigasiemens": "Gigasiemensas", + "farad": "Faradas", + "millifarad": "Milifaradas", + "microfarad": "Mikrofaradas", + "nanofarad": "Nanofaradas", + "picofarad": "Pikofaradas", + "kilofarad": "Kilofaradas", + "megafarad": "Megafaradas", + "gigafarad": "Gigafaradas", + "terfarad": "Terafaradas", + "farad-per-meter": "Faradai metrui", + "tesla": "Tesla", + "gauss": "Gausas", + "kilogauss": "Kilogausas", + "millitesla": "Militesla", + "microtesla": "Mikrotesla", + "nanotesla": "Nanotesla", + "kilotesla": "Kilotesla", + "megatesla": "Megatesla", + "millitesla-square-meters": "Militeslos kvadratiniai metrai", + "gamma": "Gama", + "lambda": "Lambda", + "square-meter-per-second": "Kvadratiniai metrai per sekundę", + "square-centimeter-per-second": "Kvadratiniai centimetrai per sekundę", + "stoke": "Stokas", + "centistokes": "Centistokai", + "square-foot-per-second": "Kvadratinės pėdos per sekundę", + "square-inch-per-second": "Kvadratiniai coliai per sekundę", + "pascal-second": "Paskalų sekundė", + "centipoise": "CentiPoisas", + "poise": "Poisas", + "reynolds": "Reinoldso skaičius", + "pound-per-foot-hour": "Svarai pėdai per valandą", + "newton-second-per-square-meter": "Niutono sekundė kvadratiniam metrui", + "dyne-second-per-square-centimeter": "Dinos sekundė kvadratiniam centimetrui", + "kilogram-per-meter-second": "Kilogramai metrui per sekundę", + "tesla-square-meters": "Teslos kvadratiniai metrai", + "maxwell": "Maksvelas", + "tesla-per-meter": "Teslos metrui", + "gauss-per-centimeter": "Gausai centimetrui", + "weber": "Veberis", + "microweber": "Mikroveberis", + "milliweber": "Miliveberis", + "gauss-square-centimeter": "Gausai kvadratiniam centimetrui", + "kilogauss-square-centimeter": "Kilogausai kvadratiniam centimetrui", + "henry": "Henris", + "millihenry": "Milihenris", + "microhenry": "Mikrohenris", + "nanohenry": "Nanohenris", + "henry-per-meter": "Henriai metrui", + "tesla-meter-per-ampere": "Teslos metras amperui", + "gauss-per-oersted": "Gausai erstedui", + "kilogram-per-mole": "Kilogramai moliui", + "gram-per-mole": "Gramai moliui", + "milligram-per-mole": "Miligramai moliui", + "joule-per-mole": "Džiauliai moliui", + "joule-per-mole-kelvin": "Džiauliai moliui-kelvinui", + "millivolts-per-meter": "Milivoltai metrui", + "volts-per-meter": "Voltai metrui", + "kilovolts-per-meter": "Kilovoltai metrui", + "radian-per-second": "Radianai per sekundę", + "radian-per-second-squared": "Radianai per sekundę kvadratu", + "revolutions-per-minute-per-second": "Apsisukimai per minutę per sekundę", + "deg-per-second": "laipsn./s", + "rotation-per-minute": "Apsisukimai per minutę", + "degrees-brix": "Brix laipsniai", + "katal": "Katalis", + "katal-per-cubic-metre": "Kataliai kubiniam metrui", + "paris-inch": "Paryžiaus colis" + }, + "user": { + "user": "Vartotojas", + "users": "Vartotojai", + "customer-users": "Kliento vartotojai", + "tenant-admins": "Valdytojų administratoriai", + "sys-admin": "Sistemos administratoriai", + "tenant-admin": "Valdytojo administratoriai", + "customer": "Klientas", + "anonymous": "Anonimas", + "add": "Pridėti vartotoją", + "delete": "Panaikinti vartotoją", + "add-user-text": "Pridėti naują vartotoją", + "no-users-text": "Vartotojų nėra", + "user-details": "Informacija apie vartotoją", + "delete-user-title": "Ar tikrai norite panaikinti vartotoją '{{userEmail}}'?", + "delete-user-text": "Būkite dėmesingi – po patvirtinimo vartotojas ir visa su juo susijusi informacija bus panaikinta.", + "delete-users-title": "Ar tikrai norite panaikinti { count, plural, =1 {1 vartotoją} other {# vartotojus} }?", + "delete-users-action-title": "Panaikinti { count, plural, =1 {1 vartotoją} other {# vartotojus} }", + "delete-users-text": "Būkite dėmesingi – po patvirtinimo visi pasirinkti vartotojai ir su jais susijusi informacija bus panaikinta.", + "activation-email-sent-message": "Aktyvinimo el. laiškas sėkmingai išsiųstas!", + "resend-activation": "Iš naujo siųsti aktyvavimo laišką", + "email": "El. pašto adresas", + "email-required": "El. pašto adresas būtinas.", + "invalid-email-format": "Neteisingas el. pašto adreso formatas.", + "first-name": "Vardas", + "last-name": "Pavardė", + "description": "Aprašymas", + "default-dashboard": "Pagrindinis skydelis", + "always-fullscreen": "Visada per visą ekraną", + "select-user": "Pasirinkti vartotoją", + "no-users-matching": "Vartotojų, atitinkančių '{{entity}}', nėra.", + "user-required": "Vartotojas būtinas", + "activation-method": "Aktyvavimo būdas", + "display-activation-link": "Rodyti aktyvavimo nuorodą", + "send-activation-mail": "Siųsti aktyvavimo el. laišką", + "activation-link": "Vartotojo aktyvavimo nuoroda", + "activation-link-text": "Norėdami aktyvuoti vartotoją, paspauskite nuorodą:", + "copy-activation-link": "Kopijuoti aktyvavimo nuorodą", + "activation-link-copied-message": "Vartotojo aktyvavimo nuoroda nukopijuota į iškarpinę", + "details": "Informacija", + "login-as-tenant-admin": "Prisijungti kaip valdytojo administratorius", + "login-as-customer-user": "Prisijungti kaip kliento vartotojas", + "search": "Vartotojų paieška", + "selected-users": "Pasirinkta { count, plural, =1 {1 vartotojas} other {# vartotojai} }", + "disable-account": "Išjungti vartotojo paskyrą", + "enable-account": "Įjungti vartotojo paskyrą", + "enable-account-message": "Vartotojo paskyra sėkmingai įjungta!", + "disable-account-message": "Vartotojo paskyra sėkmingai išjungta!", + "copyId": "Kopijuoti vartotojo ID", + "idCopiedMessage": "Vartotojo ID nukopijuotas į iškarpinę", + "user-list": "Vartotojų sąrašas", + "user-list-required": "Vartotojų sąrašas būtinas" + }, + "value": { + "type": "Reikšmės tipas", + "string": "Tekstas", + "string-value": "Tekstinė informacija", + "string-value-required": "Tekstinė informacija būtina", + "integer": "Sveikasis skaičius", + "integer-value": "Sveikojo skaičiaus reikšmė", + "integer-value-required": "Sveikojo skaičiaus reikšmė būtina", + "invalid-integer-value": "Sveikojo skaičiaus reikšmė neteisinga", + "double": "Realusis skaičius", + "double-value": "Realiojo skaičiaus reikšmė", + "double-value-required": "Realiojo skaičiaus reikšmė būtina", + "boolean": "Loginis", + "boolean-value": "Loginė reikšmė", + "false": "Netiesa", + "true": "Tiesa", + "long": "Sveikas skaičius", + "json": "JSON", + "json-value": "JSON reikšmė", + "json-value-invalid": "Neteisingas JSON reikšmės formatas", + "json-value-required": "JSON reikšmė būtina." + }, + "version-control": { + "version-control": "Versijų valdymas", + "management": "Versijų valdymo administravimas", + "search": "Ieškoti versijų", + "branch": "Šaka", + "default": "Numatytoji", + "select-branch": "Pasirinkite šaką", + "branch-required": "Šaka būtina", + "create-entity-version": "Sukurti subjekto versiją", + "version-name": "Versijos pavadinimas", + "version-name-required": "Versijos pavadinimas būtinas", + "author": "Autorius", + "export-relations": "Eksportuoti ryšius", + "export-attributes": "Eksportuoti atributus", + "export-credentials": "Eksportuoti įgaliojimus", + "export-calculated-fields": "Eksportuoti skaičiuojamus laukus", + "entity-versions": "Subjektų versijos", + "versions": "Versijos", + "created-time": "Sukūrimo laikas", + "version-id": "Versijos ID", + "no-entity-versions-text": "Subjektų versijų nerasta", + "no-versions-text": "Versijų nerasta", + "copy-full-version-id": "Kopijuoti pilną versijos ID", + "create-version": "Sukurti versiją", + "creating-version": "Kuriama versija... Prašome palaukti", + "nothing-to-commit": "Nėra pakeitimų, kuriuos galima įkelti", + "restore-version": "Atkurti versiją", + "restore-entity-from-version": "Atkurti subjektą iš versijos '{{versionName}}'", + "restoring-entity-version": "Atkuriama subjekto versija... Prašome palaukti", + "load-relations": "Įkelti ryšius", + "load-attributes": "Įkelti atributus", + "load-credentials": "Įkelti įgaliojimus", + "load-calculated-fields": "Įkelti skaičiuojamus laukus", + "compare-with-current": "Palyginti su dabartine", + "diff-entity-with-version": "Palyginti su subjekto versija '{{versionName}}'", + "previous-difference": "Ankstesnis skirtumas", + "next-difference": "Kitas skirtumas", + "current": "Dabartinė", + "differences": "{ count, plural, =1 {1 skirtumas} other {# skirtumai} }", + "create-entities-version": "Sukurti subjektų versiją", + "default-sync-strategy": "Numatytoji sinchronizavimo strategija", + "sync-strategy-merge": "Sujungti (Merge)", + "sync-strategy-overwrite": "Perrašyti (Overwrite)", + "entities-to-export": "Subjektai eksportui", + "entities-to-restore": "Subjektai atkūrimui", + "sync-strategy": "Sinchronizavimo strategija", + "all-entities": "Visi subjektai", + "no-entities-to-export-prompt": "Nurodykite subjektus, kuriuos norite eksportuoti", + "no-entities-to-restore-prompt": "Nurodykite subjektus, kuriuos norite atkurti", + "add-entity-type": "Pridėti subjekto tipą", + "remove-all": "Pašalinti visus", + "version-create-result": "{ added, plural, =0 {Subjektų nepridėta} =1 {1 subjektas pridėtas} other {# subjektai pridėti} }.
{ modified, plural, =0 {Neatnaujinta nė vieno subjekto} =1 {1 subjektas atnaujintas} other {# subjektai atnaujinti} }.
{ removed, plural, =0 {Neištrinta nė vieno subjekto} =1 {1 subjektas pašalintas} other {# subjektai pašalinti} }.", + "remove-other-entities": "Pašalinti kitus subjektus", + "find-existing-entity-by-name": "Rasti esamą subjektą pagal pavadinimą", + "restore-entities-from-version": "Atkurti subjektus iš versijos '{{versionName}}'", + "restoring-entities-from-version": "Atkuriami subjektai... Prašome palaukti", + "no-entities-restored": "Neatkurtas nė vienas subjektas", + "created": "{{created}} sukurta", + "updated": "{{updated}} atnaujinta", + "deleted": "{{deleted}} ištrinta", + "remove-other-entities-confirm-text": "Būkite atsargūs! Tai negrįžtamai ištrins visus dabartinius subjektus,
kurių nėra atkuriamoje versijoje.

Įveskite „remove other entities“, kad patvirtintumėte.", + "auto-commit-to-branch": "automatiškai įkelti į šaką {{ branch }}", + "default-create-entity-version-name": "{{entityName}} atnaujinimas", + "sync-strategy-merge-hint": "Sukuria arba atnaujina pasirinktus subjektus saugykloje. Kiti saugyklos subjektai neliečiami.", + "sync-strategy-overwrite-hint": "Sukuria arba atnaujina pasirinktus subjektus saugykloje. Visi kiti saugyklos subjektai bus ištrinti.", + "device-credentials-conflict": "Nepavyko įkelti įrenginio su išoriniu ID {{entityId}}
nes tie patys įgaliojimai jau egzistuoja kitam įrenginiui duomenų bazėje.
Apsvarstykite galimybę išjungti įkelti įgaliojimus nustatymą atkūrimo formoje.", + "missing-referenced-entity": "Nepavyko įkelti {{sourceEntityTypeName}} su išoriniu ID {{sourceEntityId}}
nes jis nurodo neegzistuojantį {{targetEntityTypeName}} su ID {{targetEntityId}}.", + "runtime-failed": "Klaida: {{message}}", + "auto-commit-settings-read-only-hint": "Automatinio įkėlimo funkcija neveikia, kai saugykla nustatyta tik skaitymui.", + "rollback-on-error": "Atšaukti pakeitimus klaidos atveju", + "rollback-on-error-hint": "Jei atkuriate didelį subjektų kiekį, galite išjungti šią parinktį našumui padidinti.\nAtminkite: jei atkūrimo metu įvyks klaida, jau išsaugoti subjektai (su ryšiais, atributais ir kt.) liks nepakitę." + }, + "widget": { + "widget-library": "Valdiklių galerija", + "widget-bundle": "Valdiklių rinkinys", + "all-bundles": "Visi rinkiniai", + "select-widgets-bundle": "Pasirinkti valdiklių rinkinį", + "widgets": "Valdikliai", + "all-widgets": "Visi valdikliai", + "widget": "Valdiklis", + "select-widget": "Pasirinkti valdiklį", + "no-widgets-matching": "Valdiklių atitinkančių '{{entity}}' nėra.", + "no-widgets": "Valdiklių dar nėra", + "no-widgets-text": "Valdiklių nėra", + "management": "Valdiklių valdymas", + "editor": "Valdiklių redaktorius", + "confirm-to-exit-editor-html": "Turite neišsaugotų valdiklio nustatymų.
Ar tikrai norite palikti šį puslapį?", + "widget-type-not-found": "Įkeliant valdiklio konfigūraciją įvyko klaida.
Gali būti, kad šis valdiklio tipas buvo pašalintas.", + "widget-type-load-error": "Valdiklis neįkeltas dėl klaidų:", + "remove": "Panaikinti valdiklį", + "delete": "Panaikinti valdiklį", + "edit": "Redaguoti valdiklį", + "remove-widget-title": "Ar tikrai norite panaikinti valdiklį '{{widgetTitle}}'?", + "remove-widget-text": "Būkite dėmesingi — po patvirtinimo valdiklis ir visa su juo susijusi informacija bus pašalinta.", + "replace-reference-with-widget-copy": "Pakeisti nuorodą valdiklio kopija", + "timeseries": "Telemetrija", + "search-data": "Duomenų paieška", + "no-data-found": "Duomenų nerasta", + "latest": "Naujausios reikšmės", + "rpc": "Valdymo valdiklis", + "alarm": "Įspėjimų valdiklis", + "static": "Statinis valdiklis", + "timeseries-short": "telemetrija", + "latest-short": "naujausios", + "rpc-short": "valdymas", + "alarm-short": "įspėjimas", + "static-short": "statinis", + "select-widget-type": "Pasirinkite valdiklio tipą", + "missing-widget-title-error": "Valdiklio pavadinimas būtinas!", + "widget-saved": "Valdiklis išsaugotas", + "unable-to-save-widget-error": "Valdiklio išsaugoti nepavyko! Yra klaidų konfigūracijoje.", + "save": "Išsaugoti valdiklį", + "saveAs": "Išsaugoti valdiklį kaip", + "move": "Perkelti valdiklį", + "save-widget-as": "Išsaugoti valdiklį kaip", + "save-widget-as-text": "Įveskite naują valdiklio pavadinimą", + "toggle-fullscreen": "Perjungti į viso ekrano režimą", + "run": "Paleisti valdiklį", + "widget-title": "Valdiklio pavadinimas", + "title": "Pavadinimas", + "title-required": "Valdiklio pavadinimas būtinas.", + "title-max-length": "Pavadinimas negali viršyti 256 simbolių.", + "system": "Sisteminis", + "type": "Tipas", + "resources": "Resursai", + "resource-url": "JavaScript/CSS URL", + "resource-is-extension": "Yra plėtinys", + "remove-resource": "Pašalinti resursą", + "add-resource": "Pridėti resursą", + "html": "HTML", + "tidy": "Tvarkyti (Tidy)", + "css": "CSS", + "settings-form": "Nustatymų forma", + "data-key-settings-form": "Duomenų rakto nustatymų forma", + "latest-data-key-settings-form": "Naujausių duomenų rakto nustatymų forma", + "widget-settings": "Valdiklio nustatymai", + "description": "Aprašymas", + "tags": "Žymos", + "image-preview": "Paveiksliuko peržiūra", + "settings-form-selector": "Nustatymų formos pasirinkiklis", + "data-key-settings-form-selector": "Duomenų rakto nustatymų formos pasirinkiklis", + "latest-data-key-settings-form-selector": "Naujausių duomenų rakto nustatymų formos pasirinkiklis", + "all": "Visi", + "actual": "Esamas", + "scada": "SCADA simbolis", + "deprecated": "Pasenęs", + "has-basic-mode": "Turi bazinį režimą", + "basic-mode-form-selector": "Bazinio režimo formos pasirinkiklis", + "basic-mode": "Bazinė versija", + "advanced-mode": "Pažangi versija", + "javascript": "JavaScript", + "js": "JS", + "delete-widget-title": "Ar tikrai norite panaikinti valdiklį '{{widgetName}}'?", + "delete-widget-text": "Po patvirtinimo valdiklis ir visa susijusi informacija bus negrįžtamai pašalinti.", + "delete-widgets-title": "Ar tikrai norite panaikinti { count, plural, =1 {1 valdiklį} other {# valdiklius} }?", + "delete-widgets-text": "Būkite dėmesingi — po patvirtinimo visi pasirinkti valdikliai ir susijusi informacija bus negrįžtamai pašalinta.", + "delete-widget": "Panaikinti valdiklį", + "widget-template-load-failed-error": "Nepavyko įkelti valdiklio šablono!", + "details": "Informacija", + "widget-details": "Informacija apie valdiklį", + "add": "Pridėti valdiklį", + "add-existing-widget": "Pridėti esamą valdiklį", + "add-new-widget": "Pridėti naują valdiklį", + "search-widgets": "Valdiklių paieška", + "selected-widgets": "Pasirinkta { count, plural, =1 {1 valdiklis} other {# valdikliai} }", + "undo": "Atšaukti valdiklio pakeitimus", + "export": "Eksportuoti valdiklį", + "export-prompt": "Įtraukti valdiklio paveikslėlius ir resursus", + "export-widgets": "Eksportuoti valdiklius", + "export-widgets-prompt": "Įtraukti valdiklių paveikslėlius ir resursus", + "import": "Importuoti valdiklį", + "no-data": "Nėra duomenų atvaizdavimui", + "data-overflow": "Valdiklyje rodoma {{count}} iš {{total}} įrašų", + "alarm-data-overflow": "Valdiklyje rodomi {{allowedEntities}} (maksimalus leistinas skaičius) įspėjimų įrašai iš {{totalEntities}}", + "search": "Valdiklių paieška", + "filter": "Valdiklių filtro tipas", + "loading-widgets": "Įkeliami valdikliai...", + "widget-template-error": "Netinkamas valdiklio HTML šablonas.", + "reference": "Nuoroda" + }, + "widget-action": { + "header-button": "Valdiklio antraštės mygtukas", + "do-nothing": "Nedaryti nieko", + "open-dashboard-state": "Eiti į naują skydelio būseną", + "update-dashboard-state": "Atnaujinti dabartinę skydelio būseną", + "open-dashboard": "Eiti į kitą skydelį", + "custom": "Aprašomas veiksmas", + "custom-pretty": "Aprašomas veiksmas (su HTML šablonu)", + "custom-pretty-error-title": "Klaida vykdant pasirinktą dialogą", + "custom-pretty-template-error": "Netinkamas pasirinktinio dialogo šablonas.", + "custom-pretty-controller-error": "Įvyko klaida vykdant pasirinktinio dialogo funkciją.", + "mobile-action": "Mobilusis veiksmas", + "target-dashboard-state": "Tikslinė skydelio būsena", + "target-dashboard-state-required": "Tikslnė skydelio būsena būtina", + "set-entity-from-widget": "Nustatyti subjektą iš valdiklio", + "target-dashboard": "Tikslinis skydelis", + "select-target-dashboard": "Pasirinkite tikslinį skydelį", + "target-dashboard-required": "Tikslinis skydelis būtinas.", + "open-right-layout": "Atidaryti tinkamą skydelio išdėstymą (mobilusis vaizdas)", + "state-display-type": "Skydelio būsenos rodymo būdas", + "open-normal": "Normalus vaizdas", + "open-in-separate-dialog": "Atidaryti atskirame dialoge", + "open-in-popover": "Atidaryti iškylančiame lange", + "dialog-title": "Dialogo pavadinimas", + "dialog-hide-dashboard-toolbar": "Slėpti skydelio įrankių juostą dialoge", + "dialog-width": "Dialogo plotis (procentais nuo lango pločio)", + "dialog-height": "Dialogo aukštis (procentais nuo lango aukščio)", + "dialog-size-range-error": "Dialogo dydžio reikšmė turi būti nuo 1 iki 100 procentų.", + "popover-preferred-placement": "Pageidaujama iškylančio lango padėtis", + "popover-placement-top": "Viršuje", + "popover-placement-topLeft": "Viršuje kairėje", + "popover-placement-topRight": "Viršuje dešinėje", + "popover-placement-right": "Dešinėje", + "popover-placement-rightTop": "Dešinėje viršuje", + "popover-placement-rightBottom": "Dešinėje apačioje", + "popover-placement-bottom": "Apačioje", + "popover-placement-bottomLeft": "Apačioje kairėje", + "popover-placement-bottomRight": "Apačioje dešinėje", + "popover-placement-left": "Kairėje", + "popover-placement-leftTop": "Kairėje viršuje", + "popover-placement-leftBottom": "Kairėje apačioje", + "popover-hide-on-click-outside": "Slėpti iškylantį langą spustelėjus už ribų", + "popover-hide-dashboard-toolbar": "Slėpti skydelio įrankių juostą iškylančiame lange", + "popover-width": "Iškylančio lango plotis naršyklės vienetais (pvz. 100px, 25vw)", + "popover-height": "Iškylančio lango aukštis naršyklės vienetais (pvz. 100px, 25vh)", + "popover-style": "Iškylančio lango stilius", + "open-new-browser-tab": "Atidaryti naujame naršyklės skirtuke", + "open-URL": "Atidaryti URL", + "URL": "URL", + "url-required": "URL būtinas.", + "mobile": { + "device-provision": "Įrenginio paruošimas", + "action-type": "Mobiliojo veiksmo tipas", + "select-action-type": "Pasirinkite mobiliojo veiksmo tipą", + "action-type-required": "Mobiliojo veiksmo tipas būtinas.", + "take-picture-from-gallery": "Pasirinkti nuotrauką iš galerijos", + "take-photo": "Padaryti nuotrauką", + "map-direction": "Atidaryti maršrutą žemėlapyje", + "map-location": "Atidaryti vietą žemėlapyje", + "scan-qr-code": "Skenuoti QR kodą", + "make-phone-call": "Skambinti telefonu", + "get-location": "Gauti telefono vietą", + "take-screenshot": "Padaryti ekrano nuotrauką" + }, + "custom-action-function": "Pasirinktinio veiksmo funkcija", + "custom-pretty-function": "Pasirinktinio veiksmo (su HTML šablonu) funkcija", + "map-item-type": "Žemėlapio elemento tipas", + "map-item": { + "marker": "Žymeklis", + "polygon": "Daugiakampis", + "rectangle": "Stačiakampis", + "circle": "Apskritimas" + }, + "place-map-item": "Įdėti žemėlapio elementą", + "map-item-tooltip": { + "customize-map-item-tooltips": "Tinkinti žemėlapio elementų paaiškinimus (tooltips)", + "place-marker": "Padėti žymeklį", + "start-draw-rectangle": "Pradėti piešti stačiakampį", + "finish-draw-rectangle": "Baigti piešti stačiakampį", + "start-draw-polygon": "Pradėti piešti daugiakampį", + "continue-draw-polygon": "Tęsti daugiakampio piešimą", + "finish-draw-polygon": "Baigti piešti daugiakampį", + "start-draw-circle": "Pradėti piešti apskritimą", + "finish-draw-circle": "Baigti piešti apskritimą" + } + }, + "widgets-bundle": { + "current": "Dabartinis rinkinys", + "widgets-bundles": "Valdiklių rinkiniai", + "widgets-bundle-widgets": "Valdiklių rinkinio valdikliai", + "add": "Pridėti valdiklių rinkinį", + "delete": "Panaikinti valdiklių rinkinį", + "title": "Pavadinimas", + "title-required": "Pavadinimas būtinas.", + "title-max-length": "Pavadinimas negali viršyti 256 simbolių.", + "description": "Aprašymas", + "image-preview": "Paveiksliuko peržiūra", + "scada": "SCADA valdiklių rinkinys", + "order": "Eiliškumas", + "add-widgets-bundle-text": "Pridėti naują valdiklių rinkinį", + "no-widgets-bundles-text": "Valdiklių rinkinių nėra", + "empty": "Valdiklių rinkinys tuščias", + "details": "Informacija", + "widgets-bundle-details": "Informacija apie valdiklių rinkinį", + "delete-widgets-bundle-title": "Ar tikrai norite panaikinti valdiklių rinkinį '{{widgetsBundleTitle}}'?", + "delete-widgets-bundle-text": "Būkite dėmesingi — po patvirtinimo valdiklių rinkinys ir visa su juo susijusi informacija bus pašalinta.", + "delete-widgets-bundles-title": "Ar tikrai norite panaikinti { count, plural, =1 {1 valdiklių rinkinį} other {# valdiklių rinkinius} }?", + "delete-widgets-bundles-action-title": "Panaikinti { count, plural, =1 {1 valdiklių rinkinį} other {# valdiklių rinkinius} }", + "delete-widgets-bundles-text": "Būkite dėmesingi — po patvirtinimo visi pasirinkti valdiklių rinkiniai ir su jais susijusi informacija bus pašalinti.", + "no-widgets-bundles-matching": "Valdiklių rinkinių, atitinkančių '{{widgetsBundle}}', nėra.", + "widgets-bundle-required": "Valdiklių rinkinys būtinas.", + "system": "Sisteminis", + "import": "Importuoti valdiklių rinkinį", + "export": "Eksportuoti valdiklių rinkinį", + "export-widgets-bundle-widgets-prompt": "Įtraukti valdiklių tipus į eksportuotus duomenis (kitu atveju bus eksportuojami tik nurodytų valdiklių FQN identifikatoriai)", + "export-failed-error": "Valdiklių rinkinio eksportuoti nepavyko: {{error}}", + "create-new-widgets-bundle": "Sukurti naują valdiklių rinkinį", + "widgets-bundle-file": "Valdiklių rinkinio failas", + "invalid-widgets-bundle-file-error": "Valdiklių rinkinio importuoti nepavyko: neteisinga duomenų struktūra.", + "search": "Valdiklių rinkinių paieška", + "selected-widgets-bundles": "Pasirinkta { count, plural, =1 {1 valdiklių rinkinys} other {# valdiklių rinkiniai} }", + "open-widgets-bundle": "Atverti valdiklių rinkinį", + "loading-widgets-bundles": "Įkeliamas valdiklių rinkinys...", + "create-new": "Sukurti naują valdiklių rinkinį" + }, + "widget-config": { + "data": "Duomenys", + "settings": "Nustatymai", + "advanced": "Išplėstiniai nustatymai", + "appearance": "Išvaizda", + "widget-card": "Valdiklio kortelė", + "mobile": "Mobilusis vaizdas", + "title": "Pavadinimas", + "title-tooltip": "Pavadinimo paaiškinimas", + "general-settings": "Pagrindiniai nustatymai", + "display-title": "Rodyti valdiklio pavadinimą", + "card-title": "Kortelės pavadinimas", + "drop-shadow": "Šešėlis", + "enable-fullscreen": "Įjungti rodymą per visą ekraną", + "background-color": "Fono spalva", + "text-color": "Teksto spalva", + "border-radius": "Rėmelio apvalinimas", + "padding": "Vidinis atstumas (padding)", + "margin": "Išorinis atstumas (margin)", + "widget-style": "Valdiklio stilius", + "widget-css": "Valdiklio CSS stilius", + "title-style": "Antraštės stilius", + "mobile-mode-settings": "Mobiliojo režimo nustatymai", + "order": "Rikiavimo tvarka", + "height": "Aukštis", + "mobile-hide": "Slėpti valdiklį mobiliajame režime", + "desktop-hide": "Slėpti valdiklį darbalaukio režime", + "units": "Papildomas simbolis šalia reikšmės", + "units-by-default": "Numatytieji matavimo vienetai", + "decimals": "Skaitmenys po kablelio", + "decimals-by-default": "Numatytieji dešimtainiai skaitmenys", + "default-data-key-parameter-hint": "Šis parametras taikomas visoms valdiklio reikšmėms, nebent jis perrašomas konkretaus duomenų rakto konfigūracijoje", + "units-short": "Vienetai", + "decimals-short": "Dešimtainiai", + "decimals-suffix": "dešimtainiai skaitmenys", + "digits-suffix": "skaitmenys", + "timewindow": "Laikotarpio langas", + "use-dashboard-timewindow": "Naudoti skydelio laikotarpio langą", + "use-widget-timewindow": "Naudoti valdiklio laikotarpio langą", + "display-timewindow": "Rodyti laikotarpio langą", + "legend": "Legenda", + "display-legend": "Rodyti legendą", + "datasources": "Duomenų šaltiniai", + "datasource": "Duomenų šaltinis", + "maximum-datasources": "Daugiausiai leidžiama { count, plural, =1 {1 duomenų šaltinis.} other {# duomenų šaltiniai} }", + "timeseries-key-error": "Reikia nurodyti bent vieną telemetrijos rodiklį", + "datasource-type": "Tipas", + "datasource-parameters": "Parametrai", + "remove-datasource": "Pašalinti duomenų šaltinį", + "add-datasource": "Pridėti duomenų šaltinį", + "target-device": "Tikslinis įrenginys", + "alarm-source": "Įspėjimo šaltinis", + "actions": "Veiksmai", + "action": "Veiksmas", + "add-action": "Pridėti veiksmą", + "search-actions": "Veiksmų paieška", + "no-actions-text": "Veiksmų nėra", + "action-source": "Veiksmo šaltinis", + "select-action-source": "Pasirinkite veiksmo šaltinį", + "action-source-required": "Veiksmo šaltinis būtinas.", + "column-index": "Stulpelio indeksas", + "select-column-index": "Pasirinkite stulpelio indeksą", + "column-index-required": "Stulpelio indeksas būtinas.", + "not-set": "Nenurodyta", + "action-name": "Veiksmo pavadinimas", + "action-name-required": "Veiksmo pavadinimas būtinas.", + "action-name-not-unique": "Veiksmas su tokiu pavadinimu jau egzistuoja.
To paties šaltinio veiksmų pavadinimai negali kartotis.", + "action-icon": "Piktograma", + "header-button": { + "button-settings": "Mygtuko nustatymai", + "button-type": "Mygtuko tipas", + "button-type-basic": "Paprastas", + "button-type-raised": "Iškeltas (Raised)", + "button-type-stroked": "Kontūrinis (Stroked)", + "button-type-flat": "Plokščias (Flat)", + "button-type-icon": "Piktogramos mygtukas", + "button-type-mini-fab": "Mini FAB (Floating Action Button)", + "colors": "Spalvos", + "color": "Spalva", + "background": "Fonas", + "border": "Rėmelis", + "advanced-button-style": "Išplėstinis mygtuko stilius", + "button-style": "Mygtuko stilius" + }, + "show-hide-action-using-function": "Rodyti / slėpti veiksmą pagal funkciją", + "show-action-function": "Veiksmo rodymo funkcija", + "action-type": "Veiksmo tipas", + "action-type-required": "Veiksmo tipas būtinas.", + "edit-action": "Redaguoti veiksmą", + "delete-action": "Panaikinti veiksmą", + "delete-action-title": "Panaikinti valdiklio veiksmą", + "delete-action-text": "Ar tikrai norite panaikinti valdiklio veiksmą '{{actionName}}'?", + "title-icon": "Antraštės piktograma", + "display-icon": "Rodyti antraštės piktogramą", + "card-icon": "Kortelės piktograma", + "icon": "Piktograma", + "icon-color": "Piktogramos spalva", + "icon-size": "Piktogramos dydis", + "advanced-settings": "Išplėstiniai nustatymai", + "data-settings": "Duomenų nustatymai", + "limits": "Ribos", + "no-data-display-message": "Alternatyvus tekstas, kai nėra duomenų", + "data-page-size": "Maksimalus subjektų skaičius viename duomenų šaltinyje", + "settings-component-not-found": "Nerasta nustatymų formos komponento su selektoriumi '{{selector}}'", + "preview": "Peržiūra", + "set": "Nustatyti", + "set-message": "Nustatyti pranešimą", + "advanced-title-style": "Išplėstinis antraštės stilius", + "card-style": "Kortelės stilius", + "text": "Tekstas", + "background": "Fonas", + "advanced-widget-style": "Išplėstinis valdiklio stilius", + "card-buttons": "Kortelės mygtukai", + "show-card-buttons": "Rodyti kortelės mygtukus", + "card-border-radius": "Kortelės kampų apvalinimas", + "card-padding": "Kortelės vidinis atstumas (padding)", + "card-appearance": "Kortelės išvaizda", + "color": "Spalva", + "tooltip": "Paaiškinimas (tooltip)", + "units-required": "Matavimo vienetas būtinas.", + "list-layout": "Sąrašo išdėstymas", + "layout": "Išdėstymas", + "resize-options": "Dydžio keitimo parinktys", + "resizable": "Keičiamo dydžio", + "preserve-aspect-ratio": "Išlaikyti proporcijas" + }, + "widget-type": { + "import": "Importuoti valdiklį", + "export": "Eksportuoti valdiklį", + "export-failed-error": "Valdiklio eksportuoti nepavyko: {{error}}", + "widget-file": "Valdiklio failas", + "invalid-widget-file-error": "Nepavyko importuoti valdiklio: neteisinga valdiklio duomenų struktūra." + }, + "markdown": { + "edit": "Redaguoti", + "preview": "Peržiūra", + "copy-code": "Spustelėkite, kad nukopijuotumėte", + "copied": "Nukopijuota!" + }, + "widgets": { + "mobile-app-qr-code": { + "configuration-hint": "Konfigūracija priklauso nuo mobiliosios aplikacijos QR kodo valdiklio pagrindiniuose platformos nustatymuose", + "get-it-on-google-play": "Atsisiųsti iš Google Play", + "download-on-the-app-store": "Atsisiųsti iš App Store" + }, + "action-button": { + "behavior": "Elgsena", + "on-click": "Paspaudus", + "on-click-hint": "Veiksmas, kuris įvykdomas paspaudus mygtuką", + "first-button-click": "Pirmas mygtuko paspaudimas", + "first-button-click-hint": "Veiksmas, vykdomas pirmo mygtuko paspaudimo metu.", + "second-button-click": "Antras mygtuko paspaudimas", + "second-button-click-hint": "Veiksmas, vykdomas antro mygtuko paspaudimo metu.", + "button-click-hint": "Veiksmas, vykdomas paspaudus valdiklį." + }, + "command-button": { + "behavior": "Elgsena", + "on-click": "Paspaudus", + "on-click-hint": "Veiksmas, atliekamas paspaudus mygtuką." + }, + "power-button": { + "behavior": "Elgsena", + "power-on": "Įjungti", + "power-on-hint": "Veiksmas, atliekamas įjungiant komponentą.", + "power-off": "Išjungti", + "power-off-hint": "Veiksmas, atliekamas išjungiant komponentą.", + "on-label": "Įjungta", + "off-label": "Išjungta", + "layout": "Išdėstymas", + "layout-default": "Numatytasis", + "layout-simplified": "Supaprastintas", + "layout-outlined": "Aptvertas", + "layout-default-volume": "Numatytasis.Garsas", + "layout-simplified-volume": "Supaprastintas.Garsas", + "layout-outlined-volume": "Aptvertas.Garsas", + "layout-default-icon": "Numatytasis.Piktograma", + "layout-simplified-icon": "Supaprastintas.Piktograma", + "layout-outlined-icon": "Aptvertas.Piktograma", + "main": "Pagrindinis", + "background": "Fonas", + "button-icon-on": "Mygtuko piktograma 'Įjungta'", + "button-icon-off": "Mygtuko piktograma 'Išjungta'", + "power-on-colors": "Įjungimo spalvos", + "power-off-colors": "Išjungimo spalvos", + "disabled-colors": "Išjungtos spalvos", + "button": "Mygtukas" + }, + "toggle-button": { + "behavior": "Elgsena", + "checked": "Pažymėta", + "unchecked": "Nepažymėta", + "check": "Pažymėti", + "check-hint": "Veiksmas, atliekamas pažymint komponentą.", + "uncheck": "Nuimti žymėjimą", + "uncheck-hint": "Veiksmas, atliekamas nuimant žymėjimą nuo komponento.", + "auto-scale": "Automatinis mastelis", + "horizontal-fill": "Horizontalus užpildymas", + "vertical-fill": "Vertikalus užpildymas", + "button-appearance": "Mygtuko išvaizda" + }, + "segmented-button": { + "layout": "Išdėstymas", + "layout-squared": "Kampuotas", + "layout-rounded": "Apvalintas", + "card-border": "Kortelės rėmelis", + "button-appearance": "Mygtuko išvaizda", + "first": "Pirmas", + "second": "Antras", + "color-styles": "Spalvų stiliai", + "selected": "Pasirinkta", + "unselected": "Nepasirinkta" + }, + "button": { + "layout": "Išdėstymas", + "outlined": "Aptvertas", + "filled": "Užpildytas", + "underlined": "Pabrauktas", + "basic": "Paprastas", + "auto-scale": "Automatinis mastelis", + "label": "Etiketė", + "icon": "Piktograma", + "border-radius": "Kampų apvalinimas", + "color-palette": "Spalvų paletė", + "main": "Pagrindinis", + "background": "Fonas", + "border": "Rėmelis", + "custom-styles": "Tinkinti stiliai", + "clear-style": "Išvalyti stilių", + "shadow": "Šešėlis", + "enabled": "Įjungta", + "disabled": "Išjungta", + "preview": "Peržiūra", + "copy-style-from": "Kopijuoti stilių iš" + }, + "value-stepper": { + "behavior": "Elgsena", + "simplified": "Supaprastintas", + "filled": "Užpildytas", + "outlined": "Aptvertas", + "volume": "Garsas", + "initial-state": "Pradinė būsena", + "initial-state-hint": "Veiksmas, skirtas gauti pradinę reikšmę.", + "disabled-state": "Išjungta būsena", + "disabled-state-hint": "Nustatykite sąlygą, kada komponentas yra išjungiamas.", + "right-button-click": "Dešinio mygtuko paspaudimas", + "right-button-click-hint": "Veiksmas paspaudus dešinį mygtuką.", + "left-button-click": "Kairio mygtuko paspaudimas", + "left-button-click-hint": "Veiksmas paspaudus kairį mygtuką.", + "auto-scale": "Automatinis mastelis", + "value-range": "Reikšmių intervalas", + "min-range": "Minimali reikšmė", + "max-range": "Maksimali reikšmė", + "value-increment-decrement-step": "Reikšmės didinimo/mažinimo žingsnis", + "value": "Reikšmė", + "value-box-background": "Reikšmės laukelio fonas", + "border": "Rėmelis", + "button-appearance": "Mygtuko išvaizda", + "left": "Kairė", + "right": "Dešinė", + "left-button": "Kairysis mygtukas", + "right-button": "Dešinysis mygtukas", + "icon": "Piktograma", + "color-palette": "Spalvų paletė", + "main": "Pagrindinis", + "background": "Fonas", + "button-icon-on": "Mygtuko piktograma 'Įjungta'", + "button-on-colors": "Įjungimo spalvos", + "disabled-colors": "Išjungtos spalvos" + }, + "button-state": { + "activated-state": "Aktyvuota būsena", + "activated-state-hint": "Nustatykite sąlygą, kada mygtukas yra aktyvus.", + "disabled-state": "Išjungta būsena", + "disabled-state-hint": "Nustatykite sąlygą, kada mygtukas yra išjungiamas.", + "selected-state": "Pasirinkta būsena", + "selected-state-hint": "Nustatykite sąlygą, kada mygtukas yra pasirinktas.", + "enabled": "Įjungta", + "hovered": "Užvestas", + "pressed": "Paspaustas", + "activated": "Aktyvuotas", + "disabled": "Išjungtas", + "initial": "Pirmasis mygtukas", + "first": "Pirmas", + "second": "Antras" + }, + "background": { + "background": "Fonas", + "background-settings": "Fono nustatymai", + "background-type-image": "Įkelti paveikslėlį", + "background-type-color": "Vientisa spalva", + "image-url": "Paveikslėlio URL", + "overlay": "Perdanga", + "enable-overlay": "Įjungti perdangą", + "blur": "Suliejimas", + "preview": "Peržiūra" + }, + "bar-chart": { + "bar-appearance": "Stulpelio išvaizda", + "label-on-bar": "Etiketė ant stulpelio", + "value-on-bar": "Reikšmė ant stulpelio", + "bar-chart-style": "Stulpelinės diagramos stilius", + "bar-axis": "Stulpelio ašis" + }, + "polar-area-chart": { + "polar-axis": "Polinė ašis", + "start-angle": "Pradinis kampas", + "polar-area-chart-style": "Polinės diagramos stilius" + }, + "battery-level": { + "layout": "Išdėstymas", + "layout-vertical-solid": "Vertikalus. Vientisas", + "layout-horizontal-solid": "Horizontalus. Vientisas", + "layout-vertical-divided": "Vertikalus. Padalintas", + "layout-horizontal-divided": "Horizontalus. Padalintas", + "icon": "Piktograma", + "value": "Reikšmė", + "auto-scale": "Automatinis mastelis", + "battery-level-color": "Baterijos lygio spalva", + "battery-shape-color": "Baterijos formos spalva", + "battery-level-card-style": "Baterijos lygio kortelės stilius", + "sections-count": "Sekcijų skaičius" + }, + "signal-strength": { + "value": "Reikšmė", + "last-update": "Paskutinis atnaujinimas", + "no-signal": "Nėra signalo", + "layout": "Išdėstymas", + "layout-wifi": "Wi-Fi", + "layout-cellular-bar": "Mobiliojo ryšio stulpeliai", + "icon": "Piktograma", + "date": "Data", + "active-bars-color": "Aktyvių signalo stulpelių spalva", + "inactive-bars-color": "Neaktyvių signalo stulpelių spalva", + "signal-strength-card-style": "Signalo stiprumo kortelės stilius", + "no-signal-rssi-value": "\"Nėra signalo\" RSSI reikšmė" + }, + "status-widget": { + "behavior": "Elgsena", + "layout": "Išdėstymas", + "layout-default": "Numatytasis", + "layout-center": "Centruotas", + "layout-icon": "Piktograma", + "on": "Įjungta", + "off": "Išjungta", + "label": "Etiketė", + "status": "Būsena", + "icon": "Piktograma", + "color-palette": "Spalvų paletė", + "disabled-color-palette": "Išjungta spalvų paletė", + "primary": "Pagrindinė", + "primary-color-hint": "Piktogramos ir etiketės spalva", + "secondary": "Antrinė", + "secondary-color-hint": "Būsenos spalva", + "background": "Fonas" + }, + "chart": { + "common-settings": "Bendrieji nustatymai", + "enable-stacking-mode": "Įjungti kaupimo režimą", + "selection": "Laiko intervalo pasirinkimas", + "enable-selection-mode": "Įjungti pasirinkimo režimą", + "line-shadow-size": "Linijos šešėlio dydis", + "display-smooth-lines": "Rodyti glotnias (lenktas) linijas", + "default-bar-width": "Numatytasis stulpelio plotis neagreguotiems duomenims (milisekundėmis)", + "bar-alignment": "Stulpelių lygiavimas", + "bar-alignment-left": "Kairėje", + "bar-alignment-right": "Dešinėje", + "bar-alignment-center": "Centre", + "default-font": "Numatytasis šriftas", + "default-font-size": "Numatytasis šrifto dydis", + "default-font-color": "Numatytoji šrifto spalva", + "thresholds-line-width": "Numatytasis ribų linijos plotis", + "tooltip-settings": "Užuominos nustatymai", + "tooltip": "Užuomina", + "show-tooltip": "Rodyti užuominą", + "hover-individual-points": "Užvesti virš atskirų taškų", + "show-cumulative-values": "Rodyti sumines reikšmes kaupimo režime", + "hide-zero-false-values": "Slėpti nulinės/neteisingos reikšmės užuominose", + "tooltip-value-format-function": "Užuominos reikšmės formatavimo funkcija", + "grid-settings": "Tinklelio nustatymai", + "show-vertical-lines": "Rodyti vertikalias linijas", + "show-horizontal-lines": "Rodyti horizontalias linijas", + "grid-outline-border-width": "Tinklelio kontūro/rėmelio plotis (px)", + "primary-color": "Pagrindinė spalva", + "background-color": "Fono spalva", + "ticks-color": "Atskirų padalų spalva", + "xaxis-settings": "X ašies nustatymai", + "axis-title": "Ašies pavadinimas", + "xaxis-tick-labels-settings": "X ašies padalų etikečių nustatymai", + "show-tick-labels": "Rodyti ašies padalų etiketes", + "yaxis-settings": "Y ašies nustatymai", + "min-scale-value": "Minimalioji skalės reikšmė", + "max-scale-value": "Maksimalioji skalės reikšmė", + "yaxis-tick-labels-settings": "Y ašies padalų etikečių nustatymai", + "tick-step-size": "Padalų žingsnio dydis", + "number-of-decimals": "Rodyti dešimtainių skaičių kiekis", + "ticks-formatter-function": "Padalų formatavimo funkcija", + "comparison-settings": "Palyginimo nustatymai", + "enable-comparison": "Įjungti palyginimą", + "time-for-comparison": "Palyginimo laikotarpis", + "time-for-comparison-previous-interval": "Ankstesnis intervalas (numatytasis)", + "time-for-comparison-days": "Prieš dieną", + "time-for-comparison-weeks": "Prieš savaitę", + "time-for-comparison-months": "Prieš mėnesį", + "time-for-comparison-years": "Prieš metus", + "time-for-comparison-custom-interval": "Pasirinktinis intervalas", + "custom-interval-value": "Pasirinktinis intervalo dydis (ms)", + "comparison-x-axis-settings": "Palyginimo X ašies nustatymai", + "axis-position": "Ašies padėtis", + "axis-position-top": "Viršuje (numatyta)", + "axis-position-bottom": "Apačioje", + "custom-legend-settings": "Tinkintos legendos nustatymai", + "enable-custom-legend": "Įjungti tinkintą legendą (leidžia naudoti atributų/laikinių eilučių reikšmes etiketėse)", + "key-name": "Raktinio parametro pavadinimas", + "key-name-required": "Būtina nurodyti raktinio parametro pavadinimą", + "key-type": "Rakto tipas", + "key-type-attribute": "Atributas", + "key-type-timeseries": "Laikinė eilutė", + "label-keys-list": "Etiketėse naudojamų raktų sąrašas", + "no-label-keys": "Nesukonfigūruoti jokie raktai", + "add-label-key": "Pridėti naują raktą", + "line-width": "Linijos plotis", + "color": "Spalva", + "data-is-hidden-by-default": "Duomenys pagal numatymą paslėpti", + "disable-data-hiding": "Išjungti duomenų slėpimą", + "remove-from-legend": "Pašalinti duomenų raktą iš legendos", + "exclude-from-stacking": "Pašalinti iš kaupimo (prieinama tik „Kaupimo“ režime)", + "line-settings": "Linijos nustatymai", + "show-line": "Rodyti liniją", + "fill-line": "Užpildyti liniją", + "fill-line-opacity": "Užpildymo nepermatomumas", + "points-settings": "Taškų nustatymai", + "show-points": "Rodyti taškus", + "points-line-width": "Taškų kontūro plotis", + "points-radius": "Taškų spindulys", + "point-shape": "Taško forma", + "point-shape-circle": "Apskritimas", + "point-shape-cross": "Kryžius", + "point-shape-diamond": "Deimantas", + "point-shape-square": "Kvadratas", + "point-shape-triangle": "Trikampis", + "point-shape-custom": "Tinkinta funkcija", + "point-shape-draw-function": "Taško piešimo funkcija", + "show-separate-axis": "Rodyti atskirą ašį", + "axis-position-left": "Kairėje", + "axis-position-right": "Dešinėje", + "thresholds": "Ribos", + "no-thresholds": "Ribos nesukonfigūruotos", + "add-threshold": "Pridėti ribą", + "show-values-for-comparison": "Rodyti istorines reikšmes palyginimui", + "comparison-values-label": "Istorinių reikšmių etiketė", + "comparison-line-color": "Palyginimo linijos spalva", + "threshold-settings": "Ribų nustatymai", + "use-as-threshold": "Naudoti rakto reikšmę kaip ribą", + "threshold-line-width": "Ribos linijos plotis", + "threshold-color": "Ribos spalva", + "common-pie-settings": "Bendrieji skritulinės diagramos nustatymai", + "radius": "Spindulys", + "inner-radius": "Vidinis spindulys", + "tilt": "Pasvirimas", + "common-pie-settings-range-error": "Reikšmė turi būti nuo 0 iki 1", + "stroke-settings": "Kontūro nustatymai", + "width-pixels": "Plotis (pikseliais)", + "show-labels": "Rodyti etiketes", + "animation-settings": "Animacijos nustatymai", + "animated-pie": "Įjungti skritulinės diagramos animaciją (eksperimentinė funkcija)", + "border-settings": "Rėmelio nustatymai", + "border-width": "Rėmelio plotis", + "border-color": "Rėmelio spalva", + "legend-settings": "Legendos nustatymai", + "display-legend": "Rodyti legendą", + "labels-font-color": "Etikečių šrifto spalva", + "series": "Serijos", + "add-series": "Pridėti seriją", + "series-settings": "Serijos nustatymai", + "remove-series": "Pašalinti seriją", + "no-series": "Nesukonfigūruota jokia serija", + "no-series-error": "Būtina nurodyti bent vieną seriją", + "chart-appearance": "Diagramos išvaizda", + "vertical-grid-lines": "Vertikalios tinklelio linijos", + "horizontal-grid-lines": "Horizontalios tinklelio linijos", + "chart-background": "Diagramos fonas", + "grid-lines-color": "Tinklelio linijų spalva", + "border": "Rėmelis", + "axis": "Ašis", + "vertical-axis": "Vertikali ašis", + "ticks": "Padalos", + "horizontal-axis": "Horizontali ašis", + "shape-empty-circle": "Tuščias apskritimas", + "shape-circle": "Apskritimas", + "shape-rect": "Stačiakampis", + "shape-round-rect": "Apvalintų kampų stačiakampis", + "shape-triangle": "Trikampis", + "shape-diamond": "Deimantas", + "shape-pin": "Žymeklis", + "shape-arrow": "Rodyklė", + "shape-none": "Nėra", + "line-type-solid": "Vientisa", + "line-type-dashed": "Brūkšniuota", + "line-type-dotted": "Taškuota", + "label-position-top": "Viršuje", + "label-position-bottom": "Apačioje", + "label-position-outside": "Išorėje", + "label-position-inside": "Viduje", + "fill": "Užpildas", + "fill-type-none": "Nėra", + "fill-type-solid": "Vientisas", + "fill-type-opacity": "Permatomumas", + "fill-type-gradient": "Gradientas", + "background": "Fonas", + "opacity": "Permatomumas", + "gradient-stops": "Gradiento taškai", + "gradient-start": "pradžia", + "gradient-end": "pabaiga", + "animation": { + "animation": "Animacija", + "animation-threshold": "Animacijos riba", + "animation-duration": "Animacijos trukmė", + "animation-easing": "Animacijos švelninimas", + "animation-delay": "Animacijos delsimas", + "update-animation-duration": "Atnaujinimo animacijos trukmė", + "update-animation-easing": "Atnaujinimo animacijos švelninimas", + "update-animation-delay": "Atnaujinimo animacijos delsimas" + }, + "chart-axis": { + "scale": "Skalė", + "scale-min": "min", + "scale-max": "maks", + "scale-auto": "Automatinė" + }, + "bar": { + "show-border": "Rodyti rėmelį", + "border-width": "Rėmelio plotis", + "border-radius": "Kampų apvalinimas", + "bar-width": "Stulpelio plotis", "label": "Etiketė", - "events": "Įvykiai", - "details": "Informacija", - "copyId": "Kopijuoti įrenginio Id", - "copyAccessToken": "Kopijuoti prieigos raktą", - "copy-mqtt-authentication": "Copy MQTT credentials", - "idCopiedMessage": "Įrenginio Id nukopijuotas į iškarpinę", - "accessTokenCopiedMessage": "Įrenginio prieigos raktas nukopijuotas į iškarpinę", - "mqtt-authentication-copied-message": "Device MQTT authentication has been copied to clipboard", - "assignedToCustomer": "Priskirtas klientui", - "unable-delete-device-alias-title": "Įrenginio pseudonimo panaikinti nepavyko", - "unable-delete-device-alias-text": "Įrenginio pseudonimas '{{deviceAlias}}' nes jis naudojamas šiuose valdikliuose:
{{widgetsList}}", - "is-gateway": "Is gateway", - "overwrite-activity-time": "Overwrite activity time for connected device", - "device-filter": "Įrenginių filtras", - "device-filter-title": "Įrenginių filtras", - "filter-title": "Filtras", - "device-state": "Įrenginio būsena", - "state": "Būsena", - "any": "Visos", - "active": "Aktyvus", - "inactive": "Neaktyvus", - "public": "Viešas", - "device-public": "Įrenginys yra viešas", - "select-device": "Pasirinkite įrenginį", - "select-group-to-add": "Pasirinkite grupę, į kurią norite pridėti pažymėtus įrenginius", - "select-group-to-move": "Pasirinkite grupę, į kurią norite perkelti pažymėtus įrenginius", - "remove-devices-from-group": "Ar tikrai norite iš grupės '{{entityGroup}}' pašalinti { count, plural, =1 {1 įrenginį} other {# įrenginius} }?", - "group": "Įrenginių grupė", - "list-of-groups": "{ count, plural, =1 {Viena įrenginio grupė} other {# įrenginių grupių sąrašas} }", - "group-name-starts-with": "Įrenginių grupės, kurių pavadinimai prasideda '{{prefix}}'", - "import": "Importuoti įrenginį", - "device-file": "Įrenginio failas", - "search": "Įrenginių paieška", - "selected-devices": "Pasirinkta { count, plural, =1 {1 įrenginys} other {# įrenginiai} }", - "device-configuration": "Įrenginių konfigūracija", - "transport-configuration": "Transport configuration", - "wizard": { - "device-details": "Informacija apie įrenginį" - }, - "unassign-devices-from-edge-title": "Are you sure you want to unassign { count, plural, =1 {1 device} other {# devices} }?", - "unassign-devices-from-edge-text": "After the confirmation all selected devices will be unassigned and won't be accessible by the edge.", - "time": "Time", - "connectivity": { - "check-connectivity": "Check connectivity", - "device-created-check-connectivity": "Device created. Let's check connectivity!", - "loading-check-connectivity-command": "Loading check connectivity commands...", - "use-following-instructions": "Use the following instructions for sending telemetry on behalf of the device using shell", - "execute-following-command": "Execute the following command", - "install-curl-windows": "Starting Windows 10 b17063, cURL is available by default", - "install-curl-macos": "Starting Mac OS X 10.2 6C115 (Jaguar), cURL is available by default", - "install-mqtt-windows": "Use the instructions to download, install, setup and run mosquitto_pub", - "install-coap-client": "Use the instructions to download, install, setup and run coap-client", - "install-necessary-client-tools": "Install necessary client tools", - "mqtts-x509-command": "Use the following documentation to connect the device via MQTT with authorization X509", - "coaps-x509-command": "Use the following documentation to connect the device via CoAP over DTLS with authorization X509", - "snmp-command": "Use the following documentation to connect the device through the SNMP.", - "sparkplug-command": "Use the following documentation to connect the device through the MQTT Sparkplug.", - "lwm2m-command": "Use the following documentation to connect the device through the LWM2M." - } + "label-hint": "Rodyti etiketę virš stulpelio.", + "series-label-hint": "Rodyti etiketę su reikšme virš stulpelio.", + "label-background": "Etiketės fonas" + } }, - "asset-profile": { - "asset-profile": "Profilis", - "asset-profiles": "Asset profiles", - "all-asset-profiles": "Visi", - "add": "Add asset profile", - "edit": "Edit asset profile", - "asset-profile-details": "Asset profile details", - "no-asset-profiles-text": "No asset profiles found", - "search": "Search asset profiles", - "selected-asset-profiles": "{ count, plural, =1 {1 asset profile} other {# asset profiles} } selected", - "no-asset-profiles-matching": "No asset profile matching '{{entity}}' were found.", - "asset-profile-required": "Asset profile is required", - "idCopiedMessage": "Asset profile Id has been copied to clipboard", - "set-default": "Make asset profile default", - "delete": "Delete asset profile", - "copyId": "Copy asset profile Id", - "name-max-length": "Name should be less than 256", - "new-device-profile-name": "Asset profile name", - "new-device-profile-name-required": "Asset profile name is required.", - "name": "Name", - "name-required": "Name is required.", - "image": "Asset profile image", - "description": "Description", - "default": "Default", - "default-rule-chain": "Default rule chain", - "default-edge-rule-chain": "Default edge rule chain", - "default-edge-rule-chain-hint": "Used on edge as rule chain to process incoming data for assets of this asset profile", - "mobile-dashboard": "Mobile dashboard", - "mobile-dashboard-hint": "Used by mobile application as a asset details dashboard", - "select-queue-hint": "Select from a drop-down list.", - "delete-asset-profile-title": "Are you sure you want to delete the asset profile '{{assetProfileName}}'?", - "delete-asset-profile-text": "Be careful, after the confirmation the asset profile and all related data will become unrecoverable.", - "delete-asset-profiles-title": "Are you sure you want to delete { count, plural, =1 {1 asset profile} other {# asset profiles} }?", - "delete-asset-profiles-text": "Be careful, after the confirmation all selected asset profiles will be removed and all related data will become unrecoverable.", - "set-default-asset-profile-title": "Are you sure you want to make the asset profile '{{assetProfileName}}' default?", - "set-default-asset-profile-text": "After the confirmation the asset profile will be marked as default and will be used for new assets with no profile specified.", - "no-asset-profiles-found": "No asset profiles found.", - "create-new-asset-profile": "Create a new one!", - "create-asset-profile": "Create new asset profile", - "import": "Import asset profile", - "export": "Export asset profile", - "export-failed-error": "Unable to export asset profile: {{error}}", - "asset-profile-file": "Asset profile file", - "invalid-asset-profile-file-error": "Unable to import asset profile: Invalid asset profile data structure." - }, - "device-profile": { - "device-profile": "Profilis", - "device-profiles": "Device profiles", - "all-device-profiles": "Visi", - "add": "Add device profile", - "edit": "Edit device profile", - "device-profile-details": "Device profile details", - "no-device-profiles-text": "No device profiles found", - "search": "Search device profiles", - "selected-device-profiles": "{ count, plural, =1 {1 device profile} other {# device profiles} } selected", - "no-device-profiles-matching": "No device profile matching '{{entity}}' were found.", - "device-profile-required": "Device profile is required", - "idCopiedMessage": "Device profile Id has been copied to clipboard", - "set-default": "Make device profile default", - "delete": "Delete device profile", - "copyId": "Copy device profile Id", - "name-max-length": "Name should be less than 256", - "name": "Name", - "name-required": "Name is required.", - "type": "Profile type", - "type-required": "Profile type is required.", - "type-default": "Default", - "image": "Device profile image", - "transport-type": "Transport type", - "transport-type-required": "Transport type is required.", - "transport-type-default": "Default", - "transport-type-default-hint": "Supports basic MQTT, HTTP and CoAP transport", - "transport-type-mqtt": "MQTT", - "transport-type-mqtt-hint": "Enables advanced MQTT transport settings", - "transport-type-coap": "CoAP", - "transport-type-coap-hint": "Enables advanced CoAP transport settings", - "transport-type-lwm2m": "LWM2M", - "transport-type-lwm2m-hint": "LWM2M transport type", - "transport-type-snmp": "SNMP", - "transport-type-snmp-hint": "Specify SNMP transport configuration", - "transport-type-http": "HTTP", - "description": "Description", - "default": "Default", - "profile-configuration": "Profile configuration", - "transport-configuration": "Transport configuration", - "default-rule-chain": "Default rule chain", - "default-edge-rule-chain": "Default edge rule chain", - "default-edge-rule-chain-hint": "Used on edge as rule chain to process incoming data for devices of this device profile", - "mobile-dashboard": "Mobile dashboard", - "mobile-dashboard-hint": "Used by mobile application as a device details dashboard", - "select-queue-hint": "Select from a drop-down list.", - "delete-device-profile-title": "Are you sure you want to delete the device profile '{{deviceProfileName}}'?", - "delete-device-profile-text": "Be careful, after the confirmation the device profile and all related data including associated OTA updates will become unrecoverable.", - "delete-device-profiles-title": "Are you sure you want to delete { count, plural, =1 {1 device profile} other {# device profiles} }?", - "delete-device-profiles-text": "Be careful, after the confirmation all selected device profiles will be removed and all related data including associated OTA updates will become unrecoverable.", - "set-default-device-profile-title": "Are you sure you want to make the device profile '{{deviceProfileName}}' default?", - "set-default-device-profile-text": "After the confirmation the device profile will be marked as default and will be used for new devices with no profile specified.", - "no-device-profiles-found": "No device profiles found.", - "create-new-device-profile": "Create a new one!", - "mqtt-device-topic-filters": "MQTT device topic filters", - "mqtt-device-topic-filters-unique": "MQTT device topic filters need to be unique.", - "mqtt-device-topic-filters-spark-plug": "MQTT Sparkplug B Edge of Network (EoN) node.", - "mqtt-device-topic-filters-spark-plug-hint": "Allow connections from EoN nodes with Sparkplug B payload and topic format.", - "mqtt-device-topic-filters-spark-plug-attribute-metric-names": "SparkPlug metrics to store as attributes.", - "mqtt-device-topic-filters-spark-plug-attribute-metric-names-hint": "Names of SparkPlug metrics that will be stored as device attributes. All other metrics will be stored as device telemetry.", - "mqtt-device-payload-type": "MQTT device payload", - "mqtt-device-payload-type-json": "JSON", - "mqtt-device-payload-type-proto": "Protobuf", - "mqtt-enable-compatibility-with-json-payload-format": "Enable compatibility with other payload formats.", - "mqtt-enable-compatibility-with-json-payload-format-hint": "When enabled, the platform will use a Protobuf payload format by default. If parsing fails, the platform will attempt to use JSON payload format. Useful for backward compatibility during firmware updates. For example, the initial release of the firmware uses Json, while the new release uses Protobuf. During the process of firmware update for the fleet of devices, it is required to support both Protobuf and JSON simultaneously. The compatibility mode introduces slight performance degradation, so it is recommended to disable this mode once all devices are updated.", - "mqtt-use-json-format-for-default-downlink-topics": "Use Json format for default downlink topics", - "mqtt-use-json-format-for-default-downlink-topics-hint": "When enabled, the platform will use Json payload format to push attributes and RPC via the following topics: v1/devices/me/attributes/response/$request_id, v1/devices/me/attributes, v1/devices/me/rpc/request/$request_id, v1/devices/me/rpc/response/$request_id. This setting does not impact attribute and rpc subscriptions sent using new (v2) topics: v2/a/res/$request_id, v2/a, v2/r/req/$request_id, v2/r/res/$request_id. Where $request_id is an integer request identifier.", - "mqtt-send-ack-on-validation-exception": "Send PUBACK on PUBLISH message validation failure", - "mqtt-send-ack-on-validation-exception-hint": "By default, the platform will close the MQTT session on message validation failure. When enabled, the platform will send publish acknowledgment instead of closing the session.", - "snmp-add-mapping": "Add SNMP mapping", - "snmp-mapping-not-configured": "No mapping for OID to timeseries/telemetry configured", - "snmp-timseries-or-attribute-name": "Timeseries/attribute name for mapping", - "snmp-timseries-or-attribute-type": "Timeseries/attribute type for mapping", - "snmp-method-pdu-type-get-request": "GetRequest", - "snmp-method-pdu-type-get-next-request": "GetNextRequest", - "snmp-oid": "OID", - "transport-device-payload-type-json": "JSON", - "transport-device-payload-type-proto": "Protobuf", - "mqtt-payload-type-required": "Payload type is required.", - "coap-device-type": "CoAP device type", - "coap-device-payload-type": "CoAP device payload", - "coap-device-type-required": "CoAP device type is required.", - "coap-device-type-default": "Default", - "coap-device-type-efento": "Efento NB-IoT", - "support-level-wildcards": "Single [+] and multi-level [#] wildcards supported.", - "telemetry-topic-filter": "Telemetry topic filter", - "telemetry-topic-filter-required": "Telemetry topic filter is required.", - "attributes-topic-filter": "Attributes publish topic filter", - "attributes-subscribe-topic-filter": "Attributes subscribe topic filter", - "attributes-topic-filter-required": "Attributes publish topic filter is required.", - "attributes-subscribe-topic-filter-required": "Attributes subscribe topic is required", - "telemetry-proto-schema": "Telemetry proto schema", - "telemetry-proto-schema-required": "Telemetry proto schema is required.", - "attributes-proto-schema": "Attributes proto schema", - "attributes-proto-schema-required": "Attributes proto schema is required.", - "rpc-response-proto-schema": "RPC response proto schema", - "rpc-response-proto-schema-required": "RPC response proto schema is required.", - "rpc-response-topic-filter": "RPC response topic filter", - "rpc-response-topic-filter-required": "RPC response topic filter is required.", - "rpc-request-proto-schema": "RPC request proto schema", - "rpc-request-proto-schema-required": "RPC request proto schema is required.", - "rpc-request-proto-schema-hint": "RPC request message should always have fields: string method = 1; int32 requestId = 2; and params = 3 of any data type.", - "not-valid-pattern-topic-filter": "Not valid pattern topic filter", - "not-valid-single-character": "Invalid use of a single-level wildcard character", - "not-valid-multi-character": "Invalid use of a multi-level wildcard character", - "single-level-wildcards-hint": "[+] is suitable for any topic filter level. Ex.: v1/devices/+/telemetry or +/devices/+/attributes.", - "multi-level-wildcards-hint": "[#] can replace the topic filter itself and must be the last symbol of the topic. Ex.: # or v1/devices/me/#.", - "alarm-rules": "Alarm rules", - "alarm-rules-with-count": "Alarm rules ({{count}})", - "no-alarm-rules": "No alarm rules configured", - "add-alarm-rule": "Add alarm rule", - "edit-alarm-rule": "Edit alarm rule", - "alarm-type": "Alarm type", - "alarm-type-required": "Alarm type is required.", - "alarm-type-unique": "Alarm type must be unique within the device profile alarm rules.", - "alarm-type-max-length": "Alarm type should be less than 256", - "create-alarm-pattern": "Create {{alarmType}} alarm", - "create-alarm-rules": "Create alarm rules", - "no-create-alarm-rules": "No create conditions configured", - "add-create-alarm-rule-prompt": "Please add create alarm rule", - "clear-alarm-rule": "Clear alarm rule", - "no-clear-alarm-rule": "No clear condition configured", - "add-create-alarm-rule": "Add create condition", - "add-clear-alarm-rule": "Add clear condition", - "select-alarm-severity": "Select alarm severity", - "alarm-severity-required": "Alarm severity is required.", - "condition-duration": "Condition duration", - "condition-duration-value": "Duration value", - "condition-duration-time-unit": "Time unit", - "condition-duration-value-range": "Duration value should be in a range from 1 to 2147483647.", - "condition-duration-value-pattern": "Duration value should be integers.", - "condition-duration-value-required": "Duration value is required.", - "condition-duration-time-unit-required": "Time unit is required.", - "advanced-settings": "Advanced settings", - "alarm-rule-additional-info": "Papildoma informacija", - "edit-alarm-rule-additional-info": "Redaguoti papildomą informaciją", - "alarm-rule-additional-info-placeholder": "Pateikite savo komentarus ir patikslinimus čia, kad jie būtų rodomi pavojaus signalo detalių skiltyje „Papildoma informacija“.", - "alarm-rule-additional-info-hint": "Hint: use ${keyName} to substitute values of the attribute or telemetry keys that are used in alarm rule condition.", - "alarm-rule-mobile-dashboard": "Mobile dashboard", - "alarm-rule-mobile-dashboard-hint": "Used by mobile application as an alarm details dashboard", - "alarm-rule-no-mobile-dashboard": "No dashboard selected", - "propagate-alarm": "Propagate alarm to related entities", - "alarm-rule-relation-types-list": "Relation types to propagate", - "alarm-rule-relation-types-list-hint": "If Propagate relation types are not selected, alarms will be propagated without filtering by relation type.", - "propagate-alarm-to-owner": "Propagate alarm to entity owner (Customer or Tenant)", - "propagate-alarm-to-owner-hierarchy": "Propagate alarm to entity owners hierarchy", - "propagate-alarm-to-tenant": "Propagate alarm to Tenant", - "alarm-rule-condition": "Alarm rule condition", - "enter-alarm-rule-condition-prompt": "Please add alarm rule condition", - "edit-alarm-rule-condition": "Edit alarm rule condition", - "device-provisioning": "Device provisioning", - "provision-strategy": "Provision strategy", - "provision-strategy-required": "Provision strategy is required.", - "provision-strategy-disabled": "Disabled", - "provision-strategy-created-new": "Allow to create new devices", - "provision-strategy-check-pre-provisioned": "Check for pre-provisioned devices", - "provision-device-key": "Provision device key", - "provision-device-key-required": "Provision device key is required.", - "copy-provision-key": "Copy provision key", - "provision-key-copied-message": "Provision key has been copied to clipboard", - "provision-device-secret": "Provision device secret", - "provision-device-secret-required": "Provision device secret is required.", - "copy-provision-secret": "Copy provision secret", - "provision-secret-copied-message": "Provision secret has been copied to clipboard", - "provision-strategy-x509": { - "certificate-chain": "X509 Certificates Chain", - "certificate-chain-hint": "X.509 certificates strategy is used to provision devices by client certificates in two-way TLS communication.", - "allow-create-new-devices": "Create new devices", - "allow-create-new-devices-hint": "If selected new devices will be created and client certificate will be used as device credentials.", - "certificate-value": "Certificate in PEM format", - "certificate-value-required": "Certificate in PEM format is required", - "cn-regex-variable": "CN Regular Expression variable", - "cn-regex-variable-required": "CN Regular Expression variable is required", - "cn-regex-variable-hint": "Required to fetch device name from device's X509 certificate's common name." - }, - "condition": "Condition", - "condition-type": "Condition type", - "condition-type-simple": "Simple", - "condition-type-duration": "Duration", - "condition-during": "During {{during}}", - "condition-during-dynamic": "During \"{{ attribute }}\" ({{during}})", - "condition-type-repeating": "Repeating", - "condition-type-required": "Condition type is required.", - "condition-repeating-value": "Count of events", - "condition-repeating-value-range": "Count of events should be in a range from 1 to 2147483647.", - "condition-repeating-value-pattern": "Count of events should be integers.", - "condition-repeating-value-required": "Count of events is required.", - "condition-repeat-times": "Repeats { count, plural, =1 {1 time} other {# times} }", - "condition-repeat-times-dynamic": "Repeats \"{ attribute }\" ({ count, plural, =1 {1 time} other {# times} })", - "schedule-type": "Scheduler type", - "schedule-type-required": "Scheduler type is required.", - "schedule": "Schedule", - "edit-schedule": "Edit alarm schedule", - "schedule-any-time": "Active all the time", - "schedule-specific-time": "Active at a specific time", - "schedule-custom": "Custom", - "schedule-day": { - "monday": "Monday", - "tuesday": "Tuesday", - "wednesday": "Wednesday", - "thursday": "Thursday", - "friday": "Friday", - "saturday": "Saturday", - "sunday": "Sunday" - }, - "schedule-days": "Days", - "schedule-time": "Time", - "schedule-time-from": "From", - "schedule-time-to": "To", - "schedule-days-of-week-required": "At least one day of week should be selected.", - "create-device-profile": "Create new device profile", - "import": "Import device profile", - "export": "Export device profile", - "export-failed-error": "Unable to export device profile: {{error}}", - "device-profile-file": "Device profile file", - "invalid-device-profile-file-error": "Unable to import device profile: Invalid device profile data structure.", - "power-saving-mode": "Power Saving Mode", - "power-saving-mode-type": { - "default": "Use device profile power saving mode", - "psm": "Power Saving Mode (PSM)", - "drx": "Discontinuous Reception (DRX)", - "edrx": "Extended Discontinuous Reception (eDRX)" - }, - "edrx-cycle": "eDRX cycle", - "edrx-cycle-required": "eDRX cycle is required.", - "edrx-cycle-pattern": "eDRX cycle must be a positive integer.", - "edrx-cycle-min": "Minimum number of eDRX cycle is {{ min }} seconds.", - "paging-transmission-window": "Paging Transmission Window", - "paging-transmission-window-required": "Paging transmission window is required.", - "paging-transmission-window-pattern": "Paging transmission window must be a positive integer.", - "paging-transmission-window-min": "Minimum number ofpPaging transmission window is {{ min }} seconds.", - "psm-activity-timer": "PSM Activity Timer", - "psm-activity-timer-required": "PSM activity timer is required.", - "psm-activity-timer-pattern": "PSM activity timer must be a positive integer.", - "psm-activity-timer-min": "Minimum number of PSM activity timer is {{ min }} seconds.", - "lwm2m": { - "object-list": "Object list", - "object-list-empty": "No objects selected.", - "no-objects-found": "No objects found.", - "no-objects-matching": "No objects matching '{{object}}' were found.", - "model-tab": "LWM2M Model", - "add-new-instances": "Add new instances", - "instances-list": "Instances list", - "instances-list-required": "Instances list is required.", - "instance-id-pattern": "Instance id must be a positive integer.", - "instance-id-max": "Maximum instance id value {{max}}.", - "instance": "Instance", - "resource-label": "#ID Resource name", - "observe-label": "Observe", - "attribute-label": "Attribute", - "telemetry-label": "Telemetry", - "edit-observe-select": "To edit observe select telemetry or attribute", - "edit-attributes-select": "To edit attributes select telemetry or attribute", - "no-attributes-set": "No attributes set", - "key-name": "Key name", - "key-name-required": "Key name is required", - "attribute-name": "Name attribute", - "attribute-name-required": "Name attribute is required.", - "attribute-value": "Attribute value", - "attribute-value-required": "Attribute value is required.", - "attribute-value-pattern": "Attribute value must be a positive integer.", - "edit-attributes": "Edit attributes: {{ name }}", - "view-attributes": "View attributes: {{ name }}", - "add-attribute": "Add attribute", - "edit-attribute": "Edit attribute", - "view-attribute": "View attribute", - "remove-attribute": "Remove attribute", - "delete-server-text": "Be careful, after the confirmation the server configuration will become unrecoverable.", - "delete-server-title": "Are you sure you want to delete the server?", - "mode": "Security config mode", - "bootstrap-tab": "Bootstrap", - "bootstrap-server-legend": "Bootstrap Server (ShortId...)", - "lwm2m-server-legend": "LwM2M Server (ShortId...)", - "server": "Server", - "short-id": "Short server ID", - "short-id-tooltip": "Server short Id. Used as link to associate server Object Instance.\nThis identifier uniquely identifies each LwM2M Server configured for the LwM2M Client.\nResource MUST be set when the Bootstrap-Server Resource has a value of 'false'.\nThe values ID:0 and ID:65535 values MUST NOT be used for identifying the LwM2M Server.", - "short-id-required": "Short server ID is required.", - "short-id-range": "Short server ID should be in a range from {{ min }} to {{ max }}.", - "short-id-pattern": "Short server ID must be a positive integer.", - "lifetime": "Client registration lifetime", - "lifetime-required": "Client registration lifetime is required.", - "lifetime-pattern": "Client registration lifetime must be a positive integer.", - "default-min-period": "Min period between two notifications (s)", - "default-min-period-tooltip": "The default value the LwM2M Client should use for the Minimum Period of an Observation in the absence of this parameter being included in an Observation.", - "default-min-period-required": "Minimum period is required.", - "default-min-period-pattern": "Minimum period must be a positive integer.", - "notification-storing": "Notification storing when disabled or offline", - "binding": "Binding", - "binding-type": { - "u": "U: Client is reachable via the UDP binding at any time.", - "m": "M: Client is reachable via the MQTT binding at any time.", - "h": "H: Client is reachable via the HTTP binding at any time.", - "t": "T: Client is reachable via the TCP binding at any time.", - "s": "S: Client is reachable via the SMS binding at any time.", - "n": "N: Client MUST send the response to such a request over the Non-IP binding (is supported since LWM2M 1.1).", - "uq": "UQ: UDP connection in queue mode (is not supported since LWM2M 1.1)", - "uqs": "UQS: both UDP and SMS connections active; UDP in queue mode, SMS in standard mode (is not supported since LWM2M 1.1)", - "tq": "TQ: TCP connection in queue mode (is not supported since LWM2M 1.1)", - "tqs": "TQS: both TCP and SMS connections active; TCP in queue mode, SMS in standard mode (is not supported since LWM2M 1.1)", - "sq": "SQ: SMS connection in queue mode (is not supported since LWM2M 1.1)" - }, - "binding-tooltip": "This is the list in the\"binding\" resource of the LwM2M server object - /1/x/7.\nIndicates the supported binding modes in the LwM2M Client.\nThis value SHOULD be the same as the value in the “Supported Binding and Modes” resource in the Device Object (/3/0/16).\nWhile multiple transports are supported, only one transport binding can be used during the entire Transport Session.\nAs an example, when UDP and SMS are both supported, the LwM2M Client and the LwM2M Server can choose to communicate either over UDP or SMS during the entire Transport Session.", - "bootstrap-server": "Bootstrap Server", - "lwm2m-server": "LwM2M Server", - "include-bootstrap-server": "Include Bootstrap Server updates", - "bootstrap-update-title": "You already have configured Bootstrap Server. Are you sure you want to exclude the updates?", - "bootstrap-update-text": "Be careful, after the confirmation the Bootstrap Server configuration data will become unrecoverable.", - "server-host": "Host", - "server-host-required": "Host is required.", - "server-port": "Port", - "server-port-required": "Port is required.", - "server-port-pattern": "Port must be a positive integer.", - "server-port-range": "Port should be in a range from 1 to 65535.", - "server-public-key": "Server Public Key", - "server-public-key-required": "Server Public Key is required.", - "client-hold-off-time": "Hold Off Time", - "client-hold-off-time-required": "Hold Off Time is required.", - "client-hold-off-time-pattern": "Hold Off Time must be a positive integer.", - "client-hold-off-time-tooltip": "Client Hold Off Time for use with a Bootstrap-Server only", - "account-after-timeout": "Account after the timeout", - "account-after-timeout-required": "Account after the timeout is required.", - "account-after-timeout-pattern": "Account after the timeout must be a positive integer.", - "account-after-timeout-tooltip": "Bootstrap-Server Account after the timeout value given by this resource.", - "server-type": "Server type", - "add-new-server-title": "Add new server config", - "add-server-config": "Add server config", - "add-lwm2m-server-config": "Add LwM2M server", - "no-config-servers": "No servers configured", - "others-tab": "Other settings", - "client-strategy": "Client strategy when connecting", - "client-strategy-label": "Strategy", - "client-strategy-only-observe": "Only Observe Request to the client after the initial connection", - "client-strategy-read-all": "Read All Resources & Observe Request to the client after registration", - "fw-update": "Firmware update", - "fw-update-strategy": "Firmware update strategy", - "fw-update-strategy-data": "Push firmware update as binary file using Object 19 and Resource 0 (Data)", - "fw-update-strategy-package": "Push firmware update as binary file using Object 5 and Resource 0 (Package)", - "fw-update-strategy-package-uri": "Auto-generate unique CoAP URL to download the package and push firmware update as Object 5 and Resource 1 (Package URI)", - "sw-update": "Software update", - "sw-update-strategy": "Software update strategy", - "sw-update-strategy-package": "Push binary file using Object 9 and Resource 2 (Package)", - "sw-update-strategy-package-uri": "Auto-generate unique CoAP URL to download the package and push software update using Object 9 and Resource 3 (Package URI)", - "fw-update-resource": "Firmware update CoAP resource", - "fw-update-resource-required": "Firmware update CoAP resource is required.", - "sw-update-resource": "Software update CoAP resource", - "sw-update-resource-required": "Software update CoAP resource is required.", - "config-json-tab": "Json Config Profile Device", - "attributes-name": { - "min-period": "Minimum period", - "max-period": "Maximum period", - "greater-than": "Greater than", - "less-than": "Less than", - "step": "Step", - "min-evaluation-period": "Minimum evaluation period", - "max-evaluation-period": "Maximum evaluation period" - }, - "composite-operations-support": "Supports composite Read/Write/Observe operations" - }, - "snmp": { - "add-communication-config": "Add communication config", - "add-mapping": "Add mapping", - "authentication-passphrase": "Authentication passphrase", - "authentication-passphrase-required": "Authentication passphrase is required.", - "authentication-protocol": "Authentication protocol", - "authentication-protocol-required": "Authentication protocol is required.", - "communication-configs": "Communication configs", - "community": "Community string", - "community-required": "Community string is required.", - "context-name": "Context name", - "data-key": "Data key", - "data-key-required": "Data key is required.", - "data-type": "Data type", - "data-type-required": "Data type is required.", - "engine-id": "Engine ID", - "host": "Host", - "host-required": "Host is required.", - "oid": "OID", - "oid-pattern": "Invalid OID format.", - "oid-required": "OID is required.", - "please-add-communication-config": "Please add communication config", - "please-add-mapping-config": "Please add mapping config", - "port": "Port", - "port-format": "Invalid port format.", - "port-required": "Port is required.", - "privacy-passphrase": "Privacy passphrase", - "privacy-passphrase-required": "Privacy passphrase is required.", - "privacy-protocol": "Privacy protocol", - "privacy-protocol-required": "Privacy protocol is required.", - "protocol-version": "Protocol version", - "protocol-version-required": "Protocol version is required.", - "querying-frequency": "Querying frequency, ms", - "querying-frequency-invalid-format": "Querying frequency must be a positive integer.", - "querying-frequency-required": "Querying frequency is required.", - "retries": "Retries", - "retries-invalid-format": "Retries must be a positive integer.", - "retries-required": "Retries is required.", - "scope": "Scope", - "scope-required": "Scope is required.", - "security-name": "Security name", - "security-name-required": "Security name is required.", - "timeout-ms": "Timeout, ms", - "timeout-ms-invalid-format": "Timeout must be a positive integer.", - "timeout-ms-required": "Timeout is required.", - "user-name": "User name", - "user-name-required": "User name is required." - } + "color": { + "color-settings": "Spalvų nustatymai", + "color-type-constant": "Pastovi", + "color-type-gradient": "Gradientas", + "color-type-range": "Intervalas", + "color-type-function": "Funkcija", + "color": "Spalva", + "value-range": "Reikšmių intervalas", + "from": "Nuo", + "to": "Iki", + "color-function": "Spalvos funkcija", + "copy-color-settings-from": "Kopijuoti spalvų nustatymus iš", + "copy-from": "Kopijuoti iš", + "settings-type": "Nustatymų tipas", + "basic-mode": "Paprastas", + "advanced-mode": "Išplėstinis", + "entity-alias": "Objekto pseudonimas", + "entity-attribute": "Objekto atributas", + "gradient-color": "Gradiento spalva", + "gradient-color-min": "Spalva", + "gradient-start": "Gradiento pradžios spalva", + "gradient-start-min": "Pradžia", + "gradient-end": "Gradiento pabaigos spalva", + "gradient-end-min": "Pabaiga", + "start-value": "Pradinė reikšmė", + "end-value": "Galutinė reikšmė", + "gradient-type": "Gradiento tipas" + }, + "dashboard-state": { + "dashboard-state-settings": "Valdymo skydelio būsenos nustatymai", + "dashboard-state": "Valdymo skydelio būsenos ID", + "autofill-state-layout": "Automatiškai užpildyti būsenos išdėstymo aukštį pagal numatymą", + "default-margin": "Numatytasis valdiklių tarpas", + "default-background-color": "Numatytoji fono spalva", + "sync-parent-state-params": "Sinchronizuoti būsenos parametrus su pagrindiniu valdymo skydeliu" + }, + "date-range-navigator": { + "date-range-picker-settings": "Datų intervalo parinkiklio nustatymai", + "hide-date-range-picker": "Slėpti datų intervalo parinkiklį", + "picker-one-panel": "Datų intervalo parinkiklis viename skydelyje", + "picker-auto-confirm": "Automatinis datų intervalo patvirtinimas", + "picker-show-template": "Rodyti datų intervalo šabloną", + "first-day-of-week": "Pirmoji savaitės diena", + "interval-settings": "Intervalo nustatymai", + "hide-interval": "Slėpti intervalą", + "initial-interval": "Pradinis intervalas", + "interval-hour": "Valanda", + "interval-day": "Diena", + "interval-week": "Savaitė", + "interval-two-weeks": "2 savaitės", + "interval-month": "Mėnuo", + "interval-three-months": "3 mėnesiai", + "interval-six-months": "6 mėnesiai", + "step-settings": "Žingsnio nustatymai", + "hide-step-size": "Slėpti žingsnio dydį", + "initial-step-size": "Pradinis žingsnio dydis", + "hide-labels": "Slėpti etiketes", + "use-session-storage": "Naudoti sesijos saugyklą", + "localizationMap": { + "Sun": "Sek", + "Mon": "Pir", + "Tue": "Ant", + "Wed": "Tre", + "Thu": "Ket", + "Fri": "Pen", + "Sat": "Šeš", + "Jan": "Sau", + "Feb": "Vas", + "Mar": "Kov", + "Apr": "Bal", + "May": "Geg", + "Jun": "Bir", + "Jul": "Lie", + "Aug": "Rgp", + "Sep": "Rgs", + "Oct": "Spa", + "Nov": "Lap", + "Dec": "Grd", + "January": "Sausis", + "February": "Vasaris", + "March": "Kovas", + "April": "Balandis", + "June": "Birželis", + "July": "Liepa", + "August": "Rugpjūtis", + "September": "Rugsėjis", + "October": "Spalis", + "November": "Lapkritis", + "December": "Gruodis", + "Custom Date Range": "Pasirinktinis datų intervalas", + "Date Range Template": "Datų intervalo šablonas", + "Today": "Šiandien", + "Yesterday": "Vakar", + "This Week": "Šią savaitę", + "Last Week": "Praėjusią savaitę", + "This Month": "Šį mėnesį", + "Last Month": "Praėjusį mėnesį", + "Year": "Metai", + "This Year": "Šiais metais", + "Last Year": "Praėjusiais metais", + "Date picker": "Datų parinkiklis", + "Hour": "Valanda", + "Day": "Diena", + "Week": "Savaitė", + "2 weeks": "2 savaitės", + "Month": "Mėnuo", + "3 months": "3 mėnesiai", + "6 months": "6 mėnesiai", + "Custom interval": "Pasirinktinis intervalas", + "Interval": "Intervalas", + "Step size": "Žingsnio dydis", + "Ok": "Gerai" + } }, - "dialog": { - "close": "Uždaryti dialogo langą", - "error-message-title": "Klaidos pranešimas:", - "error-details-title": "Informacija apie klaidą" + "doughnut": { + "doughnut-appearance": "Žiedo diagramos išvaizda", + "layout": "Išdėstymas", + "layout-default": "Numatytasis", + "layout-with-total": "Su suma", + "central-total-value": "Centrinė bendra reikšmė", + "doughnut-card-style": "Žiedo diagramos kortelės stilius" }, - "direction": { - "column": "Stulpelis", - "row": "Eilutė" + "entities-hierarchy": { + "hierarchy-data-settings": "Hierarchijos duomenų nustatymai", + "relations-query-function": "Mazgo ryšių užklausos funkcija", + "has-children-function": "Funkcija, tikrinanti, ar mazgas turi vaikų", + "node-state-settings": "Mazgo būsenos nustatymai", + "node-opened-function": "Numatytoji mazgo atidarymo funkcija", + "node-disabled-function": "Mazgo išjungimo funkcija", + "display-settings": "Atvaizdavimo nustatymai", + "node-icon-function": "Mazgo piktogramos funkcija", + "node-text-function": "Mazgo teksto funkcija", + "sort-settings": "Rikiavimo nustatymai", + "nodes-sort-function": "Mazgų rikiavimo funkcija" }, "edge": { - "all": "All", - "all-edges": "All edges", - "groups": "Groups", - "shared": "Shared", - "edge": "Edge", - "edge-instances": "Edge instances", - "instances": "Instances", - "edge-file": "Edge file", - "name-max-length": "Name should be less than 256", - "label-max-length": "Label should be less than 256", - "type-max-length": "Type should be less than 256", - "management": "Edge management", - "no-edges-matching": "No edges matching '{{entity}}' were found.", - "add": "Add Edge", - "no-edges-text": "No edges found", - "edge-details": "Edge details", - "add-edge-text": "Add new edge", - "delete": "Delete edge", - "delete-edge-title": "Are you sure you want to delete the edge '{{edgeName}}'?", - "delete-edge-text": "Be careful, after the confirmation the edge and all related data will become unrecoverable.", - "delete-edges-title": "Are you sure you want to edge { count, plural, =1 {1 edge} other {# edges} }?", - "delete-edges-text": "Be careful, after the confirmation all selected edges will be removed and all related data will become unrecoverable.", - "name": "Name", - "name-starts-with": "Edge name starts with", - "name-required": "Name is required.", - "edge-license-key": "Edge License Key", - "edge-license-key-required": "Edge License Key is required.", - "edge-license-key-max-length": "Edge License Key should be less than 31", - "edge-license-key-hint": "IMPORTANT NOTE: default edge license key provided only for evaluation purposes.
This key is active only for 30 days after the activation. White-labeling feature is disabled.
To obtain your license key please navigate to the pricing page and select the best license option for your case.", - "cloud-endpoint": "Cloud Endpoint", - "cloud-endpoint-required": "Cloud Endpoint is required.", - "cloud-endpoint-max-length": "Cloud Endpoint should be less than 256", - "cloud-endpoint-hint": "Edge requires HTTP(s) access to Cloud (ThingsBoard PE) to verify the license key. Please specify Cloud URL that Edge is able to connect to.", - "description": "Description", - "details": "Details", - "events": "Events", - "copy-id": "Copy Edge Id", - "id-copied-message": "Edge Id has been copied to clipboard", - "sync": "Sync Edge", - "edge-required": "Edge required", - "edge-type": "Edge type", - "edge-type-required": "Edge type is required.", - "event-action": "Event action", - "entity-id": "Entity ID", - "select-edge-type": "Select edge type", - "assign-to-customer": "Assign to customer", - "assign-to-customer-text": "Please select the customer to assign the edge(s)", - "assign-edge-to-customer": "Assign Edge(s) To Customer", - "assign-edge-to-customer-text": "Please select the edges to assign to the customer", - "assignedToCustomer": "Assigned to customer", - "edge-public": "Edge is public", - "assigned-to-customer": "Assigned to: {{customerTitle}}", - "unassign-from-customer": "Unassign from customer", - "unassign-edge-title": "Are you sure you want to unassign the edge '{{edgeName}}'?", - "unassign-edge-text": "After the confirmation the edge will be unassigned and won't be accessible by the customer.", - "unassign-edges-title": "Are you sure you want to unassign { count, plural, =1 {1 edge} other {# edges} }?", - "unassign-edges-text": "After the confirmation all selected edges will be unassigned and won't be accessible by the customer.", - "make-public": "Make edge public", - "make-public-edge-title": "Are you sure you want to make the edge '{{edgeName}}' public?", - "make-public-edge-text": "After the confirmation the edge and all its data will be made public and accessible by others.", - "make-private": "Make edge private", - "public": "Public", - "make-private-edge-title": "Are you sure you want to make the edge '{{edgeName}}' private?", - "make-private-edge-text": "After the confirmation the edge and all its data will be made private and won't be accessible by others.", - "import": "Import edge", - "install-connect-instructions": "Install & Connect Instructions", - "install-connect-instructions-edge-created": "Edge created! Check Install & Connect Instructions", - "loading-edge-instructions": "Loading edge instructions...", - "label": "Label", - "load-entity-error": "Failed to load data. Entity has been deleted.", - "assign-new-edge": "Assign new edge", - "unassign-from-edge": "Unassign from edge", - "edge-key": "Edge key", - "copy-edge-key": "Copy Edge key", - "edge-key-copied-message": "Edge key has been copied to clipboard", - "edge-secret": "Edge secret", - "copy-edge-secret": "Copy Edge secret", - "edge-secret-copied-message": "Edge secret has been copied to clipboard", - "manage-assets": "Manage assets", - "manage-devices": "Manage devices", - "manage-entity-views": "Manage entity views", - "manage-dashboards": "Manage dashboards", - "manage-rulechains": "Manage rule chains", - "assets": "Edge assets", - "devices": "Edge devices", - "entity-views": "Edge entity views", - "dashboard": "Edge dashboard", - "dashboards": "Edge Dashboards", - "rulechain-templates": "Rule chain templates", - "edge-rulechain-templates": "Edge rule chain templates", - "converter-templates": "Converter templates", - "edge-converter-templates": "Edge converter templates", - "integration-templates": "Integration templates", - "edge-integration-templates": "Edge integration templates", - "rulechains": "Edge rule chains", - "integrations": "Integrations", - "search": "Search edges", - "selected-edges": "{ count, plural, =1 {1 edge} other {# edges} } selected", - "any-edge": "Any edge", - "no-edge-types-matching": "No edge types matching '{{entitySubtype}}' were found.", - "edge-type-list-empty": "No edge types selected.", - "edge-types": "Edge types", - "enter-edge-type": "Enter edge type", - "deployed": "Deployed", - "pending": "Pending", - "downlinks": "Downlinks", - "no-downlinks-prompt": "No downlinks found", - "sync-process-started-successfully": "Sync process started successfully!", - "missing-related-rule-chains-title": "Edge has missing related rule chain(s)", - "missing-related-rule-chains-text": "Assigned to edge rule chain(s) use rule nodes that forward message(s) to rule chain(s) that are not assigned to this edge.

List of missing rule chain(s):
{{missingRuleChains}}", - "widget-datasource-error": "This widget supports only EDGE entity datasource", - "assign-to-edge": "Assign to edge", - "assign-to-edge-title": "Assign Entity Group(s) to Edge", - "manage-edge-user-groups": "Manage edge user groups", - "manage-edge-asset-groups": "Manage edge asset groups", - "manage-edge-device-groups": "Manage edge device groups", - "manage-edge-entity-view-groups": "Manage edge entity view groups", - "manage-edge-dashboard-groups": "Manage edge dashboard groups", - "manage-edge-rule-chains": "Manage edge rule chains", - "manage-edge-integrations": "Manage edge integrations", - "manage-edge-scheduler-events": "Manage edge scheduler events", - "select-group-to-add": "Select target group to add selected edges", - "select-group-to-move": "Select target group to move selected edges", - "remove-edges-from-group": "Are you sure you want to remove { count, plural, =1 {1 edge} other {# edges} } from group '{entityGroup}'?", - "group": "Group of edges", - "list-of-groups": "{ count, plural, =1 {One edge group} other {List of # edge groups} }", - "group-name-starts-with": "Edge groups whose names start with '{{prefix}}'", - "unassign-entity-group-from-edge-title": "Are you sure you want to unassign the entity group '{{ entityGroupName }}'?", - "unassign-entity-group-from-edge-text": "After the confirmation the entity group will be unassigned and won't be accessible by the edge.", - "unassign-entity-group-from-edge": "Unassign entity group from edge", - "unassign-entity-groups-from-edge-title": "Are you sure you want to unassign {{count}} entity groups?", - "unassign-entity-groups-from-edge-text": "After the confirmation entity groups will be unassigned and won't be accessible by the edge.", - "unassign-entity-groups-from-edge": "Unassign entity groups from edge", - "unassign-scheduler-events-from-edge": "Unassign scheduler events from edge", - "unassign-scheduler-event-from-edge-title": "Are you sure you want to unassign scheduler event '{{schedulerEventName}}'?", - "unassign-scheduler-event-from-edge-text": "After the confirmation the scheduler event will be unassigned and won't be accessible by the edge.", - "unassign-scheduler-events-from-edge-title": "Are you sure you want to unassign { count, plural, =1 {1 scheduler event} other {# scheduler events} }?", - "unassign-scheduler-events-from-edge-text": "After the confirmation all selected scheduler events will be unassigned and won't be accessible by the edge.", - "manage-user-groups": "Manage user groups", - "manage-asset-groups": "Manage asset groups", - "manage-device-groups": "Manage device groups", - "manage-dashboard-groups": "Manage dashboard groups", - "manage-entity-view-groups": "Manage entity view groups", - "manage-scheduler-events": "Manage scheduler events", - "manage-integrations": "Manage integrations", - "assign-scheduler-event-to-edge-title": "Assign Scheduler Events To Edge", - "assign-scheduler-event-to-edge-text": "Please select the scheduler events to assign to the edge", - "assign-entity-groups-to-edge-text": "Please select the entity groups to assign to the edge", - "assign-integration-to-edge-title": "Assign Integrations To Edge", - "assign-integration-to-edge-text": "Please select the integrations to assign to the edge", - "missing-attributes-title": "Edge has missing attribute(s)", - "missing-attributes-text": "Integration(s), assigned to edge, have attribute placeholders that are not available on this edge.

List of missing edge attributes(s):
{{missingEdgeAttributes}}", - "missing-all-related-attributes-title": "Edge(s) have missing attribute(s)", - "missing-all-related-attributes-text": "Edge(s), related to integration, don't have attributes that are present inside integration configuration as attribute placeholders.

List of missing edge attributes(s):
{{missingEdgeAttributes}}", - "quick-overview-widget-header": "{{edgeName}} Quick Overview" - }, - "edge-event": { - "type-dashboard": "Dashboard", - "type-asset": "Asset", - "type-device": "Device", - "type-device-profile": "Device Profile", - "type-asset-profile": "Asset Profile", - "type-entity-view": "Entity View", - "type-alarm": "Alarm", - "type-entity-group": "Entity Group", - "type-rule-chain": "Rule Chain", - "type-rule-chain-metadata": "Rule Chain Metadata", - "type-edge": "Edge", - "type-user": "User", - "type-tenant": "Tenant", - "type-tenant-profile": "Tenant Profile", - "type-customer": "Customer", - "type-relation": "Relation", - "type-widgets-bundle": "Widgets Bundle", - "type-widgets-type": "Widgets Type", - "type-admin-settings": "Admin Settings", - "type-ota-package": "Ota Package", - "type-queue": "Queue", - "type-scheduler-event": "Scheduler Event", - "type-white-labeling": "White Labeling", - "type-login-white-labeling": "Login White Labeling", - "type-custom-translation": "Custom Translation", - "type-role": "Role", - "type-group-permission": "Group Permission", - "type-integration": "Integration", - "type-converter": "Converter", - "action-type-added": "Added", - "action-type-deleted": "Deleted", - "action-type-updated": "Updated", - "action-type-post-attributes": "Post Attributes", - "action-type-attributes-updated": "Attributes Updated", - "action-type-attributes-deleted": "Attributes Deleted", - "action-type-timeseries-updated": "Timeseries Updated", - "action-type-credentials-updated": "Credentials Updated", - "action-type-assigned-to-customer": "Assigned to Customer", - "action-type-unassigned-from-customer": "Unassigned from Customer", - "action-type-relation-add-or-update": "Relation Add or Update", - "action-type-relation-deleted": "Relation Deleted", - "action-type-rpc-call": "RPC Call", - "action-type-alarm-ack": "Alarm Ack", - "action-type-alarm-clear": "Alarm Clear", - "action-type-alarm-assigned": "Alarm Assigned", - "action-type-alarm-unassigned": "Alarm Unassigned", - "action-type-assigned-to-edge": "Assigned to Edge", - "action-type-unassigned-from-edge": "Unassigned from Edge", - "action-type-credentials-request": "Credentials Request", - "action-type-entity-merge-request": "Entity Merge Request", - "action-type-added-to-entity-group": "Added to Entity Group", - "action-type-removed-from-entity-group": "Removed from Entity Group", - "action-type-change-owner": "Change owner" + "display-default-title": "Rodyti numatytąjį pavadinimą" }, - "error": { - "unable-to-connect": "Nepavyksta prisijungti prie serverio! Patikrinkite interneto ryšį.", - "unhandled-error-code": "Neapdorotos klaidos kodas: {{errorCode}}", - "unknown-error": "Nežinoma klaida" - }, - "entity": { - "entity": "Subjektas", - "entities": "Subjektai", - "entities-count": "Subjektų kiekis", - "alarms-count": "Įspėjimų kiekis", - "aliases": "Subjektų pseudonimai", - "aliases-short": "Pseudonimai", - "entity-alias": "Subjekto pseudonimas", - "unable-delete-entity-alias-title": "Subjekto pseudonimo panaikinti nepavyko", - "unable-delete-entity-alias-text": "Subjekto pseudonimas '{{entityAlias}}' negali būti panaikintas, nes jis naudojamas valdikliuose:
{{widgetsList}}", - "duplicate-alias-error": "Pseudonimas '{{alias}}' dubliuojasi.
Subjektų pseudonimai skydelyje negali kartotis.", - "missing-entity-filter-error": "Trūksta pseudonimo '{{alias}}' filtro.", - "configure-alias": "Konfigūruoti '{{alias}}' pseudonimą", - "alias": "Pseudonimas", - "alias-required": "Subjekto pseudonimas būtinas.", - "remove-alias": "Panaikinti subjekto pseudonimą", - "add-alias": "Pridėti subjekto pseudonimą", - "entity-list": "Subjektų sąrašas", - "entity-type": "Subjekto tipas", - "entity-types": "Subjektų tipai", - "entity-type-list": "Subjektų tipų sąrašas", - "any-entity": "Bet kuris subjektas", - "add-entity-type": "Pridėti subjekto tipą", - "enter-entity-type": "Įveskitesubjekto tipą", - "no-entities-matching": "Subjektų, atitinkančių '{{entity}}' nėra.", - "no-entity-types-matching": "Subjektų tipų, atitinkančių '{{entityType}}' nėra.", - "name-starts-with": "Pavadinimas prasideda", - "help-text": "naudokite simbolį '%' pagal tai, kaip norite ieškoti: '%subjekto_pavadinimo_fragmentas%', '%subjekto_pavadinimo_pabaiga', 'subjekto_pavadinimo_pradžia%'.", - "use-entity-name-filter": "Naudoti filtrą", - "entity-list-empty": "Subjektai nepasirinkti.", - "entity-type-list-required": "Nors vienas subjekto tipas turi būti pasirinktas.", - "entity-name-filter-required": "Subjekto vardo filtras būtinas.", - "entity-name-filter-no-entity-matched": "Subjektų, kurių pavadinimas prasideda '{{entity}}' nėra.", - "all-subtypes": "Visi", - "select-entities": "Pasirinkte subjektus", - "no-aliases-found": "Pseudonimų nėra.", - "no-alias-matching": "'{{alias}}' nėra.", - "create-new-alias": "Sukurti naują!", - "create-new": "Sukurti naują", - "key": "Raktas", - "key-name": "Rakto pavadinimas", - "no-keys-found": "Rakto nėra.", - "no-key-matching": "'{{key}}' nėra.", - "create-new-key": "Sukurti naują!", - "type": "Tipas", - "type-required": "Subjekto tipas būtinas.", - "type-device": "Įrenginys", - "type-devices": "Įrenginiai", - "list-of-devices": "{ count, plural, =1 {Vienas įrenginys} other {# įrenginių sąrašas} }", - "device-name-starts-with": "Įrenginiai, kurių pavadinimas prasideda '{{prefix}}'", - "type-device-profile": "Įrenginio profilis", - "type-device-profiles": "Device profiles", - "clear-selected-profiles": "Clear selected profiles", - "list-of-device-profiles": "{ count, plural, =1 {One device profile} other {List of # device profiles} }", - "device-profile-name-starts-with": "Device profiles whose names start with '{{prefix}}'", - "type-asset-profile": "Asset profile", - "type-asset-profiles": "Asset profiles", - "list-of-asset-profiles": "{ count, plural, =1 {One asset profile} other {List of # asset profiles} }", - "asset-profile-name-starts-with": "Asset profiles whose names start with '{{prefix}}'", - "type-asset": "Turtas", - "type-assets": "Turtas", - "list-of-assets": "{ count, plural, =1 {Turtas} other {# Turto sąrašas} }", - "asset-name-starts-with": "Turtas, kurio pavadinimas prasideda '{{prefix}}'", - "type-entity-view": "Subjekto rodinys", - "type-entity-views": "Subjektų rodinys", - "list-of-entity-views": "{ count, plural, =1 {Vienas subjekto rodinys} other {# Subjektų rodinių sąrašas} }", - "entity-view-name-starts-with": "Subjektų rodiniai, kurių pavadinimai prasideda '{{prefix}}'", - "type-rule": "Taisyklė", - "type-rules": "Taisyklės", - "list-of-rules": "{ count, plural, =1 {Viena taisyklė} other {# Taisyklių sąrašas} }", - "rule-name-starts-with": "Taisyklės, kurių pavadinimai prasideda '{{prefix}}'", - "type-plugin": "Papildinys", - "type-plugins": "Papildiniai", - "list-of-plugins": "{ count, plural, =1 {Vienas papildinys} other {# Papildinių sąrašas} }", - "plugin-name-starts-with": "Papildiniai, kurių pavadinimai prasideda '{{prefix}}'", - "type-tenant": "Valdytojas", - "type-tenants": "valdytojai", - "list-of-tenants": "{ count, plural, =1 {Vienas valdytojas} other {# Valdytojų sąrašas} }", - "tenant-name-starts-with": "Valdytojai, kurių pavadinimai prasideda '{{prefix}}'", - "type-tenant-profile": "Tenant profile", - "type-tenant-profiles": "Tenant profiles", - "list-of-tenant-profiles": "{ count, plural, =1 {One tenant profile} other {List of # tenant profiles} }", - "tenant-profile-name-starts-with": "Tenant profiles whose names start with '{{prefix}}'", - "type-customer": "Klientas", - "type-customers": "Klientai", - "list-of-customers": "{ count, plural, =1 {Vienas klientas} other {# Klientų sąrašas} }", - "customer-name-starts-with": "Klientai, kurių pavadinimai prasideda '{{prefix}}'", - "type-user": "Vartotojas", - "type-users": "Vartotojai", - "list-of-users": "{ count, plural, =1 {Vienas vartotojas} other {# Vartotojų sąrašas} }", - "user-name-starts-with": "Vartotojai, kurių pavadinimai prasideda '{{prefix}}'", - "type-dashboard": "Skydelis", - "type-dashboards": "Skydeliai", - "list-of-dashboards": "{ count, plural, =1 {Vienas skydelis} other {# Skydelių sąrašas} }", - "dashboard-name-starts-with": "Skydeliai, kurių pavadinimai prasideda '{{prefix}}'", - "type-alarm": "Įspėjimas", - "type-alarms": "Įspėjimai", - "list-of-alarms": "{ count, plural, =1 {Vienas įspėjimas} other {# Įspėjimų sąrašas} }", - "alarm-name-starts-with": "Įspėjimai, kurių pavadinimai prasideda '{{prefix}}'", - "type-rulechain": "Taisyklių grandinė", - "type-rulechains": "Taisyklių grandinės", - "list-of-rulechains": "{ count, plural, =1 {Viena taisyklių grandinė} other {# Taisyklių grandinių sąrašas} }", - "rulechain-name-starts-with": "Taisyklių grandinės, kurų pavadinimai prasideda '{{prefix}}'", - "type-scheduler-event": "Tvarkaraščio įvykis", - "type-scheduler-events": "Tvarkaraščio įvykiai", - "list-of-scheduler-events": "{ count, plural, =1 {Vienas tvarkaraščio įvykis} other {# Tvarkaraščio įvykių sąrašas} }", - "scheduler-event-name-starts-with": "Tvarkaraščio įvykiai, kurių pavadinimai prasideda '{{prefix}}'", - "type-blob-entity": "Blob entity", - "type-blob-entities": "Blob entities", - "list-of-blob-entities": "{ count, plural, =1 {One blob entity} other {List of # blob entities} }", - "blob-entity-name-starts-with": "Blob entities whose names start with '{{prefix}}'", - "type-rulenode": "Tasyklė", - "type-rulenodes": "Taisyklės", - "list-of-rulenodes": "{ count, plural, =1 {Viena taisyklė} other {# Taisyklių sąrašas} }", - "rulenode-name-starts-with": "Taisyklės, kurių pavadinimai prasideda '{{prefix}}'", - "type-current-customer": "Dabartinis klientas", - "type-current-tenant": "Dabartinis valdytojas", - "type-current-user": "Dabartinis vartotojas", - "type-current-user-owner": "Dabartinio vartotojo savininkas", - "type-widgets-bundle": "Valdiklių rinkinys", - "type-widgets-bundles": "Valdiklių rinkiniai", - "list-of-widgets-bundles": "{ count, plural, =1 {Vienas valdiklių rinkinys} other {# Valdiklių rinkinių sąrašas} }", - "type-widget-type": "Valdiklio tipas", - "type-widget-types": "Valdiklių tipai", - "list-of-widget-types": "{ count, plural, =1 {Vienas valdiklio tipas} other {# Valdiklių tipų sąrašas} }", - "search": "Subjektų paieška", - "selected-entities": "Pasirinkta { count, plural, =1 {1 subjektas} other {# subjektai} }", - "entity-name": "Subjekto pavadinimas", - "entity-label": "Subjekto etikelė", - "details": "Informacija apie subjektą", - "no-entities-prompt": "Subjektų nėra", - "no-data": "Duomenų atvaizdavimui nėra", - "columns-to-display": "Rodomi stulpeliai", - "type-api-usage-state": "Api Usage State", - "type-entity-group": "Subjektų grupė", - "type-converter": "Duomenų keitiklis", - "type-converters": "Duomenų keitikliai", - "list-of-converters": "{ count, plural, =1 {Vienas duomenų keitiklis} other {# Duomenų keitiklių sąrašas} }", - "converter-name-starts-with": "Duomenų keitikliai, kurių pavadinimai prasideda '{{prefix}}'", - "type-integration": "Integracija", - "type-integrations": "Integracijos", - "list-of-integrations": "{ count, plural, =1 {Viena integracija} other {# Integracijų sąrašas} }", - "integration-name-starts-with": "Integracijos, kurių pavadinimai prasideda '{{prefix}}'", - "type-role": "Rolė", - "type-roles": "Rolės", - "list-of-roles": "{ count, plural, =1 {Viena rolė} other {# rolių sąrašas} }", - "role-name-starts-with": "Rolės, kurių pavadinimai prasideda '{{prefix}}'", - "type-group-permission": "Grupės leidimai", - "type-edge": "Edge", - "type-edges": "Edges", - "list-of-edges": "{ count, plural, =1 {One edge} other {List of # edges} }", - "edge-name-starts-with": "Edges whose names start with '{{prefix}}'", - "type-tb-resource": "Resource", - "type-ota-package": "OTA package", - "type-rpc": "RPC", - "type-queue": "Queue", - "type-notification": "Notification", - "type-notification-rule": "Notification rule", - "type-notification-rules": "Notification rules", - "list-of-notification-rules": "{ count, plural, =1 {One notification rule} other {List of # notification rules} }", - "type-notification-target": "Notification recipient", - "type-notification-targets": "Notification recipients", - "list-of-notification-targets": "{ count, plural, =1 {One notification recipient} other {List of # notification recipients} }", - "type-notification-request": "Notification request", - "type-notification-template": "Notification template", - "type-notification-templates": "Notification templates", - "list-of-notification-templates": "{ count, plural, =1 {One notification template} other {List of # notification templates} }", - "customer-name": "Klientas", - "sub-customer-name": "Priklausantis klientas", - "parent-customer-name": "Pirminis klientas", - "parent-sub-customer-name": "Pirminis klientas", - "include-customer-entities": "Rodyti klientui priklausančius klientus", - "include-sub-customer-entities": "Rodyti priklausančių klientų subjektus", - "groups": "Grupė" - }, - "entity-group": { - "entity-group": "Subjektų grupė", - "details": "Informacija", - "columns": "Stulpeliai", - "add-column": "Pridėti stulpelį", - "column-value": "Reikšmė", - "column-value-required": "Stulpelio reikšmė būtina.", - "column-title": "Pavadinimas", - "default-sort-order": "Numatytoji rūšiavimo tvarka", - "default-sort-order-required": "Numatytoji rūšiavimo tvarka būtina.", - "hide-in-mobile-view": "Nerodyti mobiliąjame režime", - "use-cell-style-function": "Taikyti langelio stiliaus funkciją", - "use-cell-content-function": "Taikyti langelio turinio funkciją", - "edit-column": "Redaguoti stulpelį", - "column-details": "Stulpelio informacija", - "actions": "Veiksmai", - "settings": "Nustatymai", - "search": "Subjektų grupių paieška", - "delete": "Panaikinti subjektų grupę", - "name": "Pavadinimas", - "name-required": "Pavadinimas būtinas.", - "name-max-length": "Pavadinimas turi būti trumpesnis nei 256 simboliai", - "description": "Aprašymas", - "add": "Pridėti subjektų grupę", - "open-entity-group": "Atverti subjektų grupę", - "add-entity-group-text": "Pridėti naują subjektų grupę", - "no-entity-groups-text": "Subjektų grupių nėra", - "entity-group-details": "Informacija apie subjektų grupę", - "selected-entity-groups": "Pasirinkta { count, plural, =1 {1 subjektų grupė} other {# subjektų grupės} }", - "delete-entity-groups": "Panaikinti subjektų grupes", - "delete-entity-group-title": "Ar tikrai norite panaikinti subjektų grupę '{{entityGroupName}}'?", - "delete-entity-group-text": "Būkite dėmesingi, po patvirtinimo, subjektų grupė ir visa su ja susijusi informacija bus pašalinta ir jų atkurti nebegalėsite.", - "delete-entity-groups-title": "Ar tikrai norite panaikinti { count, plural, =1 {1 subjektų grupę} other {# subjektų grupes} }?", - "delete-entity-groups-action-title": "Panaikinti { count, plural, =1 {1 subjektų grupę} other {# subjektų grupes} }", - "delete-entity-groups-text": "Būkite dėmesingi, po patvirtinimo visos subjektų grupės ir su jomis susijusi informacija bus panaikintos ir jų atkurti nebegalėsite.", - "device-groups": "Įrenginių grupės", - "shared-device-groups": "Bendrinamos įrenginių grupės", - "asset-groups": "Turto grupės", - "shared-asset-groups": "Bendrinamos turto grupės", - "customer-groups": "Klientų grupės", - "shared-customer-groups": "Bendrinamos klientų grupės", - "device-group": "Įrenginių grupė", - "asset-group": "Turto grupė", - "user-group": "Vartotojų grupė", - "user-groups": "Vartotojų grupės", - "customer-group": "Klientų grupė", - "entity-view-groups": "Subjektų rodinių grupė", - "shared-entity-view-groups": "Bendrinamos subjektų rodinių grupės", - "entity-view-group": "Subjektų rodinių grupė", - "edge-groups": "Edge groups", - "shared-edge-groups": "Shared edge groups", - "edge-group": "Edge group", - "dashboard-groups": "Skydelių grupės", - "shared-dashboard-groups": "Bendrinamos skydelių grupės", - "dashboard-group": "Skydelių grupė", - "fetch-more": "Gauti daugiau", - "column-type": { - "column-type": "Stulpelio tipas", - "client-attribute": "Kliento atributas", - "shared-attribute": "Bendrinamas atributas", - "server-attribute": "Serverio atributas", - "timeseries": "Telemetrija", - "entity-field": "Subjekto laukas" + "gateway": { + "general-settings": "Bendrieji nustatymai", + "widget-title": "Valdiklio pavadinimas", + "default-archive-file-name": "Numatytasis archyvo failo pavadinimas", + "device-type-for-new-gateway": "Įrenginio tipas naujam tinklo šliuzui", + "messages-settings": "Pranešimų nustatymai", + "save-config-success-message": "Tekstas, rodomas sėkmingai išsaugojus šliuzo konfigūraciją", + "device-name-exists-message": "Tekstas, rodomas kai įrenginys su įvestu pavadinimu jau egzistuoja", + "gateway-title": "Šliuzo forma", + "read-only": "Tik skaitymui", + "events-title": "Šliuzo įvykių formos pavadinimas", + "events-filter": "Įvykių filtras", + "event-key-contains": "Įvykio rakte yra...", + "show-connector": "Rodyti jungtį", + "connector-state-param-key": "Jungties būsenos parametro raktas", + "message": "Pranešimas", + "level": "Lygis", + "created-time": "Sukūrimo laikas" + }, + "gauge": { + "default-color": "Numatytoji spalva", + "radial-gauge-settings": "Radialinio matuoklio nustatymai", + "ticks-settings": "Padalų nustatymai", + "min-value": "Minimali reikšmė", + "max-value": "Maksimali reikšmė", + "min-value-short": "min", + "max-value-short": "maks", + "start-ticks-angle": "Pradinis padalų kampas", + "ticks-angle": "Padalų kampas", + "major-ticks": "Pagrindinės padalos", + "major-ticks-count": "Pagrindinių padalų skaičius", + "major-ticks-color": "Pagrindinių padalų spalva", + "minor-ticks": "Antrinės padalos", + "minor-ticks-count": "Antrinių padalų skaičius", + "minor-ticks-color": "Antrinių padalų spalva", + "tick-numbers-font": "Padalų numerių šriftas", + "unit-title-settings": "Matavimo vieneto pavadinimo nustatymai", + "show-unit-title": "Rodyti vieneto pavadinimą", + "unit-title": "Vieneto pavadinimas", + "title-font": "Pavadinimo teksto šriftas", + "units-settings": "Vienetų nustatymai", + "units-font": "Vienetų teksto šriftas", + "value-box-settings": "Reikšmės laukelio nustatymai", + "show-value-box": "Rodyti reikšmės laukelį", + "value-box": "Reikšmės laukelis", + "value-int": "Skaitmenų skaičius sveikai reikšmės daliai", + "value-text": "Reikšmės tekstas", + "value-text-shadow": "Reikšmės teksto šešėlis", + "value-font": "Reikšmės teksto šriftas", + "rect-stroke-color-start": "Stačiakampio rėmelio spalva – gradiento pradžia", + "rect-stroke-color-end": "Stačiakampio rėmelio spalva – gradiento pabaiga", + "background-color": "Fono spalva", + "shadow-color": "Šešėlio spalva", + "value-box-rect-stroke-color": "Reikšmės laukelio rėmelio spalva", + "value-box-rect-stroke-color-end": "Reikšmės laukelio rėmelio spalva – gradiento pabaiga", + "value-box-background-color": "Reikšmės laukelio fono spalva", + "value-box-shadow-color": "Reikšmės laukelio šešėlio spalva", + "plate-settings": "Plokštės nustatymai", + "show-plate-border": "Rodyti plokštės rėmelį", + "plate-color": "Plokštės spalva", + "needle-settings": "Rodyklės nustatymai", + "needle-circle-size": "Rodyklės apskritimo dydis", + "needle-color": "Rodyklės spalva", + "needle-color-start": "Rodyklės spalva – gradiento pradžia", + "needle-color-end": "Rodyklės spalva – gradiento pabaiga", + "needle-color-shadow-up": "Viršutinės rodyklės dalies šešėlio spalva", + "needle-color-shadow-down": "Rodyklės metamo šešėlio spalva", + "highlights-settings": "Paryškinimų nustatymai", + "highlights-width": "Paryškinimų plotis", + "highlights": "Paryškinimai", + "highlight-from": "Nuo", + "highlight-to": "Iki", + "highlight-color": "Spalva", + "no-highlights": "Paryškinimai nesukonfigūruoti", + "add-highlight": "Pridėti paryškinimą", + "animation-settings": "Animacijos nustatymai", + "enable-animation": "Įjungti animaciją", + "animation-duration-rule": "Animacijos trukmės ir taisyklių nustatymas", + "animation-duration": "Animacijos trukmė", + "animation-rule": "Animacijos taisyklė", + "animation-linear": "Tiesinė", + "animation-quad": "Kvadratinė", + "animation-quint": "Penktos eilės", + "animation-cycle": "Ciklinė", + "animation-bounce": "Šokčiojanti", + "animation-elastic": "Elastinga", + "animation-dequad": "Atvirkštinė kvadratinė", + "animation-dequint": "Atvirkštinė penktos eilės", + "animation-decycle": "Atvirkštinis ciklas", + "animation-debounce": "Atšokimo mažinimas", + "animation-delastic": "Atvirkštinė elastinga", + "linear-gauge-settings": "Tiesinio matuoklio nustatymai", + "bar-stroke": "Juostos kontūras", + "bar-stroke-width": "Juostos kontūro plotis", + "bar-stroke-color": "Juostos kontūro spalva", + "bar-background-color": "Matuoklio juostos fono spalva", + "bar-background-color-end": "Juostos fono spalva – gradiento pabaiga", + "progress-bar-color": "Progreso juostos spalva", + "progress-bar": "Progreso juosta", + "progress-bar-color-start": "Progreso juostos spalva – gradiento pradžia", + "progress-bar-color-end": "Progreso juostos spalva – gradiento pabaiga", + "major-ticks-names": "Pagrindinių padalų pavadinimai", + "show-stroke-ticks": "Rodyti padalų kontūrus", + "major-ticks-font": "Pagrindinių padalų šriftas", + "border-color": "Rėmelio spalva", + "border-width": "Rėmelio plotis", + "needle-circle": "Rodyklės apskritimas", + "needle-circle-color": "Rodyklės apskritimo spalva", + "animation-target": "Animacijos objektas", + "animation-target-needle": "Rodyklė", + "animation-target-plate": "Plokštė", + "common-settings": "Bendrieji matuoklio nustatymai", + "gauge-type": "Matuoklio tipas", + "gauge-type-arc": "Lankas", + "gauge-type-donut": "Žiedas", + "gauge-type-horizontal-bar": "Horizontali juosta", + "gauge-type-vertical-bar": "Vertikali juosta", + "donut-start-angle": "Pradinis kampas", + "bar-settings": "Matuoklio juostos nustatymai", + "relative-bar-width": "Santykinis juostos plotis", + "neon-glow-brightness": "Neoninio švytėjimo ryškumas (0–100), 0 – išjungta", + "neon-glow-brightness-hint": "0 – išjungia efektą", + "stripes-thickness": "Juostelių storis, 0 – be juostelių", + "stripes-thickness-hint": "0 – be juostelių", + "rounded-line-cap": "Rodyti apvalintą linijos galą", + "bar-color-settings": "Juostos spalvų nustatymai", + "use-precise-level-color-values": "Naudoti tikslias spalvų reikšmes", + "bar-colors": "Juostos spalvos nuo žemiausios iki aukščiausios", + "color": "Spalva", + "no-bar-colors": "Juostos spalvos nesukonfigūruotos", + "add-bar-color": "Pridėti juostos spalvą", + "from": "Nuo", + "to": "Iki", + "fixed-level-colors": "Juostos spalvos pagal ribines reikšmes", + "gauge-title-settings": "Matuoklio pavadinimo nustatymai", + "show-gauge-title": "Rodyti matuoklio pavadinimą", + "gauge-title": "Matuoklio pavadinimas", + "gauge-title-font": "Matuoklio pavadinimo šriftas", + "unit-title-and-timestamp-settings": "Vieneto pavadinimo ir laiko žymos nustatymai", + "show-timestamp": "Rodyti reikšmės laiko žymą", + "timestamp-format": "Laiko žymos formatas", + "label-font": "Etiketės šriftas po reikšme", + "value-settings": "Reikšmės nustatymai", + "show-value": "Rodyti reikšmės tekstą", + "min-max-settings": "Minimalių/maksimalių reikšmių etikečių nustatymai", + "show-min-max": "Rodyti minimalias ir maksimalias reikšmes", + "min-max-font": "Minimalių ir maksimalių reikšmių šriftas", + "show-ticks": "Rodyti padalas", + "tick-width": "Padalos plotis", + "tick-color": "Padalos spalva", + "tick-values": "Padalų reikšmės", + "no-tick-values": "Padalų reikšmės nesukonfigūruotos", + "add-tick-value": "Pridėti padalos reikšmę", + "gauge-appearance": "Matuoklio išvaizda", + "units-title": "Vienetų pavadinimas", + "value": "Reikšmė", + "ticks": "Padalos", + "arrow-and-scale-color": "Rodyklės ir skalės numatytoji spalva", + "scale-settings": "Skalės nustatymai", + "scale": "Skalė", + "scale-color": "Skalės spalvos", + "compass-appearance": "Kompaso išvaizda", + "label": "Etiketė", + "labels": "Etiketės", + "label-style": "Etiketės stilius", + "simple-gauge-type": "Tipas", + "gauge-bar-background": "Matuoklio juostos fonas", + "bar-color": "Juostos spalva", + "min-and-max-value": "Minimalios ir maksimalios reikšmės", + "min-and-max-label": "Minimalios ir maksimalios etiketės", + "font": "Šriftas", + "tick-width-and-color": "Padalų plotis ir spalva", + "min-max-validation-text": "Maksimali reikšmė turi būti didesnė nei minimali" + }, + "gpio": { + "pin": "Kaištis", + "label": "Etiketė", + "row": "Eilutė", + "column": "Stulpelis", + "color": "Spalva", + "panel-settings": "Skydelio nustatymai", + "background-color": "Fono spalva", + "gpio-switches": "GPIO jungikliai", + "no-gpio-switches": "GPIO jungikliai nesukonfigūruoti", + "add-gpio-switch": "Pridėti GPIO jungiklį", + "gpio-status-request": "GPIO būsenos užklausa", + "method-name": "Metodo pavadinimas", + "method-body": "Metodo turinys", + "gpio-status-change-request": "GPIO būsenos keitimo užklausa", + "parse-gpio-status-function": "GPIO būsenos analizės funkcija", + "gpio-leds": "GPIO šviesos diodai", + "no-gpio-leds": "GPIO šviesos diodai nesukonfigūruoti", + "add-gpio-led": "Pridėti GPIO šviesos diodą" + }, + "html-card": { + "html": "HTML", + "css": "CSS" + }, + "input-widgets": { + "attribute-not-allowed": "Atributo parametras negali būti naudojamas šiame valdiklyje", + "blocked-location": "Geolokacija yra užblokuota jūsų naršyklėje", + "claim-device": "Priskirti įrenginį", + "claim-failed": "Nepavyko priskirti įrenginio!", + "claim-not-found": "Įrenginys nerastas!", + "claim-successful": "Įrenginys sėkmingai priskirtas!", + "date": "Data", + "device-name": "Įrenginio pavadinimas", + "device-name-required": "Įrenginio pavadinimas yra privalomas", + "discard-changes": "Atmesti pakeitimus", + "entity-attribute-required": "Objekto atributas yra privalomas", + "entity-coordinate-required": "Reikalingi abu laukai – platuma ir ilguma", + "entity-timeseries-required": "Objekto laiko seka yra privaloma", + "get-location": "Gauti dabartinę vietą", + "invalid-date": "Neteisinga data", + "latitude": "Platuma", + "longitude": "Ilguma", + "min-value-error": "Minimali reikšmė yra {{value}}", + "max-value-error": "Maksimali reikšmė yra {{value}}", + "not-allowed-entity": "Pasirinktas objektas negali turėti bendrų atributų", + "no-attribute-selected": "Nepasirinktas joks atributas", + "no-datakey-selected": "Nepasirinktas joks duomenų raktas", + "no-coordinate-specified": "Nenurodytas duomenų raktas platumai/ilgumai", + "no-entity-selected": "Nepasirinktas joks objektas", + "no-image": "Nėra paveikslėlio", + "no-support-geolocation": "Jūsų naršyklė nepalaiko geolokacijos", + "no-support-web-camera": "Jūsų naršyklė nepalaiko kamerų", + "enable-https-use-widget": "Įjunkite HTTPS, kad galėtumėte naudoti šį valdiklį", + "no-found-your-camera": "Kamera nerasta", + "no-permission-camera": "Naudotojas atmetė prieigą / svetainei nesuteikta leidimo naudoti kamerą", + "no-timeseries-selected": "Nepasirinkta jokia laiko seka", + "secret-key": "Slaptasis raktas", + "secret-key-required": "Slaptasis raktas yra privalomas", + "switch-attribute-value": "Perjungti objekto atributo reikšmę", + "switch-camera": "Perjungti kamerą", + "switch-timeseries-value": "Perjungti objekto laiko sekos reikšmę", + "take-photo": "Padaryti nuotrauką", + "time": "Laikas", + "timeseries-not-allowed": "Laiko sekos parametras negali būti naudojamas šiame valdiklyje", + "update-failed": "Atnaujinimas nepavyko", + "update-successful": "Atnaujinimas sėkmingas", + "update-attribute": "Atnaujinti atributą", + "update-timeseries": "Atnaujinti laiko seką", + "value": "Reikšmė", + "general-settings": "Bendrieji nustatymai", + "widget-title": "Valdiklio pavadinimas", + "claim-button-label": "Priskyrimo mygtuko etiketė", + "show-secret-key-field": "Rodyti laukelį „Slaptasis raktas“", + "labels-settings": "Etikečių nustatymai", + "show-labels": "Rodyti etiketes", + "device-name-label": "Etiketė įrenginio pavadinimo laukui", + "secret-key-label": "Etiketė slaptojo rakto laukui", + "messages-settings": "Pranešimų nustatymai", + "claim-device-success-message": "Tekstas, rodomas sėkmingai priskyrus įrenginį", + "claim-device-not-found-message": "Tekstas, rodomas, kai įrenginys nerastas", + "claim-device-failed-message": "Tekstas, rodomas nepavykus priskirti įrenginio", + "claim-device-name-required-message": "Klaidos pranešimas „Įrenginio pavadinimas privalomas“", + "claim-device-secret-key-required-message": "Klaidos pranešimas „Slaptasis raktas privalomas“", + "show-label": "Rodyti etiketę", + "label": "Etiketė", + "required": "Privaloma", + "required-error-message": "Klaidos pranešimas „Privaloma“", + "show-result-message": "Rodyti rezultatų pranešimą", + "integer-field-settings": "Sveikojo skaičiaus lauko nustatymai", + "min-value": "Minimali reikšmė", + "max-value": "Maksimali reikšmė", + "double-field-settings": "Skaičiaus su kableliu lauko nustatymai", + "text-field-settings": "Teksto lauko nustatymai", + "min-length": "Minimalus ilgis", + "max-length": "Maksimalus ilgis", + "checkbox-settings": "Žymimojo langelio nustatymai", + "true-label": "Pažymėto langelio etiketė", + "false-label": "Nepažymėto langelio etiketė", + "image-input-settings": "Paveikslėlio įvesties nustatymai", + "display-preview": "Rodyti peržiūrą", + "display-clear-button": "Rodyti išvalymo mygtuką", + "display-apply-button": "Rodyti taikymo mygtuką", + "display-discard-button": "Rodyti atmetimo mygtuką", + "datetime-field-settings": "Datos/laiko lauko nustatymai", + "display-time-input": "Rodyti laiko įvedimo lauką", + "latitude-key-name": "Platumos rakto pavadinimas", + "longitude-key-name": "Ilgumos rakto pavadinimas", + "show-get-location-button": "Rodyti mygtuką „Gauti dabartinę vietą“", + "use-high-accuracy": "Naudoti didelį tikslumą", + "location-fields-settings": "Vietos laukų nustatymai", + "latitude-label": "Etiketė platumai", + "longitude-label": "Etiketė ilgumai", + "input-fields-alignment": "Įvesties laukų lygiavimas", + "input-fields-alignment-column": "Stulpeliu (numatytasis)", + "input-fields-alignment-row": "Eilute", + "layout": "Išdėstymas", + "row-gap": "Tarpas tarp eilučių (pikseliais)", + "column-gap": "Tarpas tarp stulpelių (pikseliais)", + "latitude-field-required": "Platumos laukas yra privalomas", + "longitude-field-required": "Ilgumos laukas yra privalomas", + "attribute-settings": "Atributų nustatymai", + "widget-mode": "Valdiklio režimas", + "widget-mode-update-attribute": "Atnaujinti atributą", + "widget-mode-update-timeseries": "Atnaujinti laiko seką", + "attribute-scope": "Atributo sritis", + "attribute-scope-server": "Serverio atributas", + "attribute-scope-shared": "Bendras atributas", + "value-required": "Reikšmė privaloma", + "image-settings": "Paveikslėlio nustatymai", + "image-format": "Paveikslėlio formatas", + "image-format-jpeg": "JPEG", + "image-format-png": "PNG", + "image-format-webp": "WEBP", + "image-quality": "Paveikslėlio kokybė (nuostolinis glaudinimas, pvz., JPEG ar WEBP)", + "max-image-width": "Maksimalus paveikslėlio plotis", + "max-image-height": "Maksimalus paveikslėlio aukštis", + "action-buttons": "Veiksmo mygtukai", + "show-action-buttons": "Rodyti veiksmo mygtukus", + "update-all-values": "Atnaujinti visas reikšmes, o ne tik pakeistas", + "save-button-label": "Mygtuko „IŠSAUGOTI“ etiketė", + "reset-button-label": "Mygtuko „ATŠAUKTI“ etiketė", + "group-settings": "Grupės nustatymai", + "show-group-title": "Rodyti pavadinimą laukų grupei, susijusiai su skirtingais objektais", + "group-title": "Grupės pavadinimas", + "fields-alignment": "Laukų lygiavimas", + "fields-alignment-row": "Eilute (numatytasis)", + "fields-alignment-column": "Stulpeliu", + "fields-in-row": "Laukų skaičius eilutėje", + "option-value": "Reikšmė („null“ – tuščiam pasirinkimui)", + "option-label": "Etiketė", + "hide-input-field": "Slėpti įvesties lauką", + "datakey-type": "Duomenų rakto tipas", + "datakey-type-server": "Serverio atributas (numatytasis)", + "datakey-type-shared": "Bendras atributas", + "datakey-type-timeseries": "Laiko seka", + "datakey-value-type": "Duomenų rakto reikšmės tipas", + "datakey-value-type-string": "Tekstas", + "datakey-value-type-double": "Skaičius su kableliu", + "datakey-value-type-integer": "Sveikasis skaičius", + "datakey-value-type-json": "JSON", + "datakey-value-type-boolean-checkbox": "Loginis (žymimasis langelis)", + "datakey-value-type-boolean-switch": "Loginis (jungiklis)", + "datakey-value-type-date-time": "Data ir laikas", + "datakey-value-type-date": "Data", + "datakey-value-type-time": "Laikas", + "datakey-value-type-select": "Pasirinkimas", + "datakey-value-type-radio": "Pasirinkimo mygtukas", + "datakey-value-type-color": "Spalva", + "value-is-required": "Reikšmė yra privaloma", + "ability-to-edit-attribute": "Atributo redagavimo galimybė", + "ability-to-edit-attribute-editable": "Redaguojamas (numatytasis)", + "ability-to-edit-attribute-disabled": "Išjungtas", + "ability-to-edit-attribute-readonly": "Tik skaitymui", + "disable-on-datakey-name": "Išjungti, jei kito duomenų rakto reikšmė yra neteisinga (nurodykite rakto pavadinimą)", + "field-appearance": "Lauko išvaizda", + "appearance-fill": "Užpildytas", + "appearance-outline": "Kontūrinis", + "subscript-sizing": "Indekso dydis", + "subscript-sizing-fixed": "Fiksuotas", + "subscript-sizing-dynamic": "Dinaminis", + "slide-toggle-settings": "Perjungimo slankiklio nustatymai", + "slide-toggle-label-position": "Perjungimo etiketės padėtis", + "slide-toggle-label-position-after": "Po", + "slide-toggle-label-position-before": "Prieš", + "select-options": "Pasirinkimo parinktys", + "no-select-options": "Pasirinkimo parinktys nesukonfigūruotos", + "add-select-option": "Pridėti pasirinkimo parinktį", + "numeric-field-settings": "Skaitinio lauko nustatymai", + "step-interval": "Reikšmių žingsnio intervalas", + "error-messages": "Klaidų pranešimai", + "min-value-error-message": "Klaidos pranešimas „Minimali reikšmė“", + "max-value-error-message": "Klaidos pranešimas „Maksimali reikšmė“", + "invalid-date-error-message": "Klaidos pranešimas „Neteisinga data“", + "invalid-JSON-error-message": "Klaidos pranešimas „Neteisingas JSON formatas“", + "icon-settings": "Piktogramos nustatymai", + "dialog-editor-settings": "Dialogo redaktoriaus nustatymai", + "use-custom-icon": "Naudoti tinkintą piktogramą", + "input-cell-icon": "Piktograma prieš įvesties laukelį", + "value-conversion-settings": "Reikšmės konvertavimo nustatymai", + "get-value-settings": "Reikšmės gavimo nustatymai", + "use-get-value-function": "Naudoti getValue funkciją", + "get-value-function": "getValue funkcija", + "set-value-settings": "Reikšmės nustatymo nustatymai", + "use-set-value-function": "Naudoti setValue funkciją", + "set-value-function": "setValue funkcija", + "json-invalid": "JSON reikšmė turi neteisingą formatą", + "title": "Pavadinimas", + "cancel-button-label": "Mygtuko „Atšaukti“ etiketė", + "radio-button-settings": "Pasirinkimo mygtuko nustatymai", + "color": "Spalva", + "columns": "Stulpeliai", + "radio-options": "Pasirinkimo parinktys", + "no-radio-options": "Pasirinkimo parinktys nesukonfigūruotos", + "add-radio-option": "Pridėti pasirinkimo parinktį", + "radio-label-position": "Etiketės padėtis", + "radio-label-position-before": "Prieš", + "radio-label-position-after": "Po" + }, + "invalid-qr-code-text": "Neteisingas įvestas tekstas QR kodui. Įvestis turi būti teksto tipo", + "qr-code": { + "use-qr-code-text-function": "Naudoti QR kodo teksto funkciją", + "qr-code-text-pattern": "QR kodo teksto šablonas (pvz. '${entityName} | ${keyName} - papildomas tekstas.')", + "qr-code-text-pattern-hint": "QR kodo teksto šablonas naudoja pirmo rasto rakto reikšmę iš objektų, esančių objekto pseudonime.", + "qr-code-text-pattern-required": "QR kodo teksto šablonas yra privalomas.", + "qr-code-text-function": "QR kodo teksto funkcija" + }, + "label-widget": { + "label-pattern": "Šablonas", + "label-pattern-hint": "Patarimas: pvz. 'Tekstas ${keyName} vienetai.' arba ${#<rakto indeksas>} vienetai'", + "label-pattern-required": "Šablonas yra privalomas", + "label-position": "Padėtis (procentais fone)", + "x-pos": "X", + "y-pos": "Y", + "background-color": "Fono spalva", + "font-settings": "Šrifto nustatymai", + "background-image": "Fono paveikslėlis", + "labels": "Etiketės", + "no-labels": "Etiketės nesukonfigūruotos", + "add-label": "Pridėti etiketę" + }, + "navigation": { + "title": "Pavadinimas", + "navigation-path": "Naršymo kelias", + "filter-type": "Filtro tipas", + "filter-type-all": "Visi elementai", + "filter-type-include": "Įtraukti elementus", + "filter-type-exclude": "Išskirti elementus", + "items": "Elementai", + "enter-urls-to-filter": "Įveskite URL filtravimui..." + }, + "persistent-table": { + "rpc-id": "RPC ID", + "message-type": "Pranešimo tipas", + "method": "Metodas", + "params": "Parametrai", + "created-time": "Sukūrimo laikas", + "expiration-time": "Galiojimo pabaigos laikas", + "retries": "Bandymų skaičius", + "status": "Būsena", + "filter": "Filtras", + "refresh": "Atnaujinti", + "add": "Pridėti RPC užklausą", + "details": "Išsamiau", + "delete": "Ištrinti", + "delete-request-title": "Ištrinti nuolatinę RPC užklausą", + "delete-request-text": "Ar tikrai norite ištrinti šią užklausą?", + "details-title": "Išsami informacija RPC ID: ", + "additional-info": "Papildoma informacija", + "response": "Atsakas", + "any-status": "Bet kuri būsena", + "rpc-status-list": "RPC būsenų sąrašas", + "no-request-prompt": "Nėra rodomų užklausų", + "send-request": "Siųsti užklausą", + "add-title": "Sukurti nuolatinę RPC užklausą", + "method-error": "Metodas yra privalomas.", + "timeout-error": "Minimalus laukimo laikas yra 5000 (5 sekundės).", + "white-space-error": "Tarpai neleidžiami.", + "rpc-status": { + "QUEUED": "EILĖJE", + "SENT": "IŠSIŲSTA", + "DELIVERED": "PRISTATYTA", + "SUCCESSFUL": "SĖKMINGA", + "TIMEOUT": "PASIBAIGĖ LAIKAS", + "EXPIRED": "NEBEGALIOJA", + "FAILED": "NEPAVYKO" + }, + "rpc-search-status-all": "VISOS", + "message-types": { + "false": "Dvipusis", + "true": "Vienpusis" + }, + "general-settings": "Bendrieji nustatymai", + "enable-filter": "Įjungti filtrą", + "enable-sticky-header": "Rodyti antraštę slenkant", + "enable-sticky-action": "Rodyti veiksmų stulpelį slenkant", + "display-request-details": "Rodyti užklausos detales", + "allow-send-request": "Leisti siųsti RPC užklausą", + "allow-delete-request": "Leisti ištrinti RPC užklausą", + "columns-settings": "Stulpelių nustatymai", + "display-columns": "Rodytini stulpeliai", + "column": "Stulpelis", + "no-columns-found": "Nerasta jokių stulpelių", + "no-columns-matching": "„{{column}}“ nerasta." + }, + "range-chart": { + "chart": "Diagrama", + "data-zoom": "Duomenų mastelio keitimas", + "range-chart-appearance": "Intervalinės diagramos išvaizda", + "range-colors": "Intervalo spalvos", + "out-of-range-color": "Už intervalo ribų spalva", + "show-range-thresholds": "Rodyti intervalo ribas", + "range-thresholds-settings": "Intervalo ribų nustatymai", + "fill-area": "Užpildymo sritis", + "fill-area-opacity": "Užpildymo srities nepermatomumas", + "range-chart-style": "Intervalinės diagramos stilius" + }, + "knob": { + "behavior": "Elgsena", + "initial-value": "Pradinė reikšmė", + "initial-value-hint": "Veiksmas, skirtas gauti pradinę rankenėlės reikšmę.", + "on-value-change": "Pasikeitus reikšmei", + "on-value-change-hint": "Veiksmas, vykdomas, kai rankenėlės reikšmė pasikeičia.", + "range": "Intervalas", + "min": "min", + "max": "maks", + "value": "Reikšmė", + "fallback-initial-value": "Atsarginė pradinė reikšmė" + }, + "rpc": { + "value-settings": "Reikšmės nustatymai", + "initial-value": "Pradinė reikšmė", + "retrieve-value-settings": "Įjungimo/išjungimo reikšmės gavimo nustatymai", + "retrieve-value-method": "Reikšmės gavimo metodas", + "retrieve-value-method-none": "Negauti reikšmės", + "retrieve-value-method-rpc": "Gauti reikšmę naudojant RPC metodą", + "retrieve-value-method-attribute": "Prenumeruoti atributą", + "retrieve-value-method-timeseries": "Prenumeruoti laiko seką", + "attribute-value-key": "Atributo raktas", + "timeseries-value-key": "Laiko sekos raktas", + "get-value-method": "RPC reikšmės gavimo metodas", + "parse-value-function": "Reikšmės analizės funkcija", + "update-value-settings": "Reikšmės atnaujinimo nustatymai", + "set-value-method": "RPC reikšmės nustatymo metodas", + "convert-value-function": "Reikšmės konvertavimo funkcija", + "rpc-settings": "RPC nustatymai", + "request-timeout": "RPC užklausos laukimo laikas (ms)", + "persistent-rpc-settings": "Nuolatinės RPC nustatymai", + "request-persistent": "Nuolatinė RPC užklausa", + "persistent-polling-interval": "Apklausos intervalas (ms) nuolatinei RPC komandai gauti", + "common-settings": "Bendrieji nustatymai", + "switch-title": "Jungiklio pavadinimas", + "show-on-off-labels": "Rodyti įjungta/išjungta etiketes", + "slide-toggle-label": "Perjungimo etiketė", + "label-position": "Etiketės padėtis", + "label-position-before": "Prieš", + "label-position-after": "Po", + "slider-color": "Slankiklio spalva", + "slider-color-primary": "Pagrindinė", + "slider-color-accent": "Akcentinė", + "slider-color-warn": "Įspėjamoji", + "button-style": "Mygtuko stilius", + "button-raised": "Iškilęs mygtukas", + "button-primary": "Pagrindinė spalva", + "button-background-color": "Mygtuko fono spalva", + "button-text-color": "Mygtuko teksto spalva", + "widget-title": "Valdiklio pavadinimas", + "button-label": "Mygtuko etiketė", + "device-attribute-scope": "Įrenginio atributo sritis", + "server-attribute": "Serverio atributas", + "shared-attribute": "Bendras atributas", + "device-attribute-parameters": "Įrenginio atributo parametrai", + "is-one-way-command": "Vienpusė komanda", + "rpc-method": "RPC metodas", + "rpc-method-params": "RPC metodo parametrai", + "show-rpc-error": "Rodyti RPC komandos vykdymo klaidą", + "led-title": "LED pavadinimas", + "led-color": "LED spalva", + "check-status-settings": "Būsenos tikrinimo nustatymai", + "perform-rpc-status-check": "Vykdyti RPC įrenginio būsenos patikrinimą", + "retrieve-led-status-value-method": "LED būsenos gavimo metodas", + "led-status-value-attribute": "Įrenginio atributas, kuriame saugoma LED būsena", + "led-status-value-timeseries": "Įrenginio laiko seka, kurioje saugoma LED būsena", + "check-status-method": "RPC įrenginio būsenos tikrinimo metodas", + "parse-led-status-value-function": "LED būsenos reikšmės analizės funkcija", + "knob-title": "Rankenėlės pavadinimas" + }, + "maps": { + "map-type": { + "type": "Žemėlapio tipas", + "map": "Žemėlapis", + "image": "Paveikslėlis" + }, + "image": { + "image-source": "Paveikslėlio šaltinis", + "image-source-image": "Paveikslėlis", + "image-source-entity-key": "Objekto raktas", + "source-entity-alias": "Šaltinio objekto pseudonimas", + "image-url-key": "Paveikslėlio URL raktas", + "image-url-key-required": "Paveikslėlio URL raktas yra privalomas" + }, + "control": { + "map-controls": "Žemėlapio valdikliai", + "position": "Padėtis", + "position-topleft": "Viršuje kairėje", + "position-topright": "Viršuje dešinėje", + "position-bottomleft": "Apačioje kairėje", + "position-bottomright": "Apačioje dešinėje", + "zoom-actions": "Mastelio keitimo veiksmai", + "zoom-scroll": "Slinkimas", + "zoom-double-click": "Dvigubas paspaudimas", + "zoom-control-buttons": "Valdymo mygtukai", + "scale": "Mastelis", + "scale-metric": "Metrinis", + "scale-imperial": "Imperinis", + "switch-to-drag-mode-using-button": "Perjungti į tempimo režimą naudojant mygtuką" + }, + "timeline": { + "control-panel": "Laiko juostos valdymo skydelis", + "time-step": "Laiko žingsnis", + "speed-options": "Greičio parinktys", + "timestamp": "Laiko žyma", + "snap-to-real-location": "Pririšti prie tikros vietos", + "location-snap-filter-function": "Vietos pririšimo filtravimo funkcija", + "no-trips-data-available": "Kelionių duomenų nėra" + }, + "map-action": { + "map-action-buttons": "Žemėlapio veiksmų mygtukai", + "label": "Etiketė", + "icon": "Piktograma", + "color": "Spalva", + "action": "Veiksmas", + "add-button": "Pridėti mygtuką", + "no-action-buttons-configured": "Veiksmų mygtukai nesukonfigūruoti", + "remove-action-button": "Pašalinti veiksmų mygtuką", + "map-action-button": "Žemėlapio veiksmų mygtukas", + "button-requires": "Mygtukui reikalinga etiketė arba piktograma" + }, + "common": { + "common-map-settings": "Bendrieji žemėlapio nustatymai", + "fit-map-bounds": "Pritaikyti žemėlapio ribas, kad apimtų visus žymeklius", + "default-map-center-position": "Numatytoji žemėlapio centro padėtis", + "default-map-zoom-level": "Numatytasis žemėlapio mastelio lygis", + "entities-limit": "Įkeltinų objektų riba" + }, + "layer": { + "label": "Etiketė", + "layer": "Sluoksnis", + "layers": "Sluoksniai", + "map-layers": "Žemėlapio sluoksniai", + "add-layer": "Pridėti sluoksnį", + "layer-settings": "Sluoksnio nustatymai", + "remove-layer": "Pašalinti sluoksnį", + "no-layers": "Sluoksniai nesukonfigūruoti", + "roadmap": "Kelio žemėlapis", + "satellite": "Palydovinis", + "hybrid": "Hibridinis", + "reference": { + "reference-layer": "Etaloninis sluoksnis", + "no-layer": "Nėra sluoksnio", + "openstreetmap-hybrid": "OpenStreetMap hibridinis", + "world-edition-hybrid": "World Edition hibridinis", + "enhanced-contrast-hybrid": "Padidinto kontrasto hibridinis" }, - "column-type-required": "Stulpelio tipas būtinas.", - "entity-field": { - "created-time": "Sukūrimo laikas", - "name": "Pavadinimas", - "type": "Tipas", - "device_profile": "Device profile", - "asset_profile": "Asset profile", - "assigned_customer": "Priskirtas klientas", - "authority": "Authority", - "first_name": "Vardas", - "last_name": "Pavardė", - "email": "El. paštas", - "title": "Pavadinimas", - "country": "Šalis", - "state": "Apskritis/rajonas", - "city": "Miestas", - "address": "Adresas", - "address2": "Adresas 2", - "zip": "Pašto kodas", - "phone": "Tel, numeris", - "label": "Etiketė" + "provider": { + "provider": "Tiekėjas", + "openstreet": { + "title": "OpenStreet", + "mapnik": "Mapnik", + "hot": "HOT", + "esri-street": "WorldStreetMap", + "esri-topo": "WorldTopoMap", + "esri-imagery": "WorldImagery", + "cartodb-positron": "Positron", + "cartodb-dark-matter": "DarkMatter" + }, + "google": { + "title": "Google", + "roadmap": "Kelio žemėlapis", + "satellite": "Palydovinis", + "hybrid": "Hibridinis", + "terrain": "Reljefas" + }, + "here": { + "title": "HERE", + "normal-day": "Įprasta diena", + "normal-night": "Įprasta naktis", + "hybrid-day": "Hibridinė diena", + "terrain-day": "Reljefinė diena" + }, + "tencent": { + "title": "Tencent", + "normal": "Įprastas", + "satellite": "Palydovinis", + "terrain": "Reljefinis" + }, + "custom": { + "title": "Tinkintas", + "tile-url": "Plytelės URL" + } }, - "sort-order": { - "asc": "Didėjanti", - "desc": "Mažėjanti", - "none": "Nėra" + "credentials": { + "credentials": "Prisijungimo duomenys", + "api-key": "API raktas" + } + }, + "overlays": { + "overlays": "Perdangos", + "overlays-hint": "Sukonfigūruokite duomenų šaltinius, išvaizdą, elgseną, redagavimo parinktis ir objektų grupavimą žemėlapyje", + "trips": "Kelionės", + "markers": "Žymekliai", + "polygons": "Daugiakampiai", + "circles": "Apskritimai" + }, + "data-layer": { + "source": "Šaltinis", + "filter": "Filtras", + "additional-data-keys": "Papildomi duomenų raktai", + "additional-datasources": "Papildomi duomenų šaltiniai", + "additional-datasources-hint": "Duomenų šaltinis, skirtas pasiekti atributus ar telemetriją iš objektų, nerodomų žemėlapyje; gali būti naudojamas žemėlapio perdangų funkcijose.", + "more-datasources": "Daugiau duomenų šaltinių", + "data-keys": "Duomenų raktai", + "add-datasource": "Pridėti duomenų šaltinį", + "no-datasources": "Duomenų šaltiniai nesukonfigūruoti", + "remove-datasource": "Pašalinti duomenų šaltinį", + "behavior": "Elgsena", + "on-click": "Paspaudus", + "on-click-hint": "Veiksmas, vykdomas, kai naudotojas paspaudžia ant žemėlapio elemento.", + "groups": "Grupės", + "groups-hint": "Grupių pavadinimų sąrašas, priskirtas perdangai, naudojamas jos matomumui žemėlapyje keisti.", + "color": "Spalva", + "color-settings": "Spalvos nustatymai", + "color-type-constant": "Pastovi", + "color-type-range": "Intervalas", + "color-type-function": "Funkcija", + "color-range-source-key": "Spalvų intervalo šaltinio raktas", + "color-range-source-key-required": "Spalvų intervalo šaltinio raktas yra privalomas", + "color-range": "Spalvų intervalas", + "color-function": "Spalvos funkcija", + "label": "Etiketė", + "tooltip": "Patarimas", + "pattern-type-pattern": "Šablonas", + "pattern-type-function": "Funkcija", + "label-pattern": "Etiketė (šablonų pavyzdžiai: '${entityName}', '${entityName}: (Tekstas ${keyName} vienetai.)')", + "label-function": "Etiketės funkcija", + "tooltip-pattern": "Patarimas (pvz. 'Tekstas ${keyName} vienetai.' arba Nuorodos tekstas)", + "tooltip-function": "Patarimo funkcija", + "tooltip-trigger": "Patarimo aktyvatorius", + "tooltip-trigger-click": "Rodyti patarimą paspaudus", + "tooltip-trigger-hover": "Rodyti patarimą užvedus žymeklį", + "auto-close-tooltips": "Automatiškai uždaryti patarimus", + "tooltip-offset": "Patarimo poslinkis", + "tooltip-offset-horizontal": "Horizontalus", + "tooltip-offset-vertical": "Vertikalus", + "tooltip-tag-actions": "Žymų veiksmai", + "add-tooltip-tag-action": "Pridėti žymos veiksmą", + "edit-tooltip-tag-action": "Redaguoti žymos veiksmą", + "remove-tooltip-tag-action": "Pašalinti žymos veiksmą", + "action-add": "Pridėti", + "action-edit": "Redaguoti", + "action-move": "Perkelti", + "action-remove": "Pašalinti", + "edit-instruments": "Įrankiai", + "persist-location-attribute-scope": "Atributo sritis vietos išsaugojimui", + "enable-snapping": "Įjungti pritraukimą prie kitų viršūnių tiksliam braižymui", + "enable-snapping-hint": "Automatiškai sulygiuoja naujus taškus su esamomis formomis, kad braižymas būtų tikslesnis.", + "drag-drop-mode": "Vilkimo režimas", + "trip": { + "no-trips": "Kelionės nesukonfigūruotos", + "add-trip": "Pridėti kelionę", + "trip-configuration": "Kelionės konfigūracija", + "remove-trip": "Pašalinti kelionę" }, - "details-mode": { - "on-row-click": "Spustelėjus eilutėje", - "on-action-button-click": "Paspaudus informacijos mygtuką", - "disabled": "Išjungta" + "marker": { + "marker": "Žymeklis", + "latitude-key": "Platumos raktas", + "longitude-key": "Ilgumos raktas", + "x-pos-key": "X padėties raktas", + "y-pos-key": "Y padėties raktas", + "latitude-key-required": "Platumos raktas yra privalomas", + "longitude-key-required": "Ilgumos raktas yra privalomas", + "x-pos-key-required": "X padėties raktas yra privalomas", + "y-pos-key-required": "Y padėties raktas yra privalomas", + "no-markers": "Žymekliai nesukonfigūruoti", + "add-marker": "Pridėti žymeklį", + "marker-configuration": "Žymeklio konfigūracija", + "remove-marker": "Pašalinti žymeklį", + "marker-type": "Žymeklio tipas", + "marker-type-shape": "Forma", + "marker-type-icon": "Piktograma", + "marker-type-image": "Paveikslėlis", + "shape": "Forma", + "icon": "Piktograma", + "image": "Paveikslėlis", + "marker-shapes": "Žymeklio formos", + "marker-icon": "Žymeklio piktograma", + "marker-appearance": "Žymeklio išvaizda", + "marker-image": "Žymeklio paveikslėlis", + "marker-image-type-image": "Paveikslėlis", + "marker-image-type-function": "Funkcija", + "custom-marker-image-size": "Tinkintas žymeklio paveikslėlio dydis", + "marker-image-function": "Žymeklio paveikslėlio funkcija", + "marker-images": "Žymeklio paveikslėliai", + "marker-offset": "Žymeklio poslinkis", + "offset-horizontal": "Horizontalus", + "offset-vertical": "Vertikalus", + "rotate-marker": "Pasukti žymeklį", + "offset-angle": "Poslinkio kampas", + "position-conversion": "Padėties konversija", + "position-conversion-function": "Padėties konversijos funkcija, turi grąžinti x,y koordinates (dvigubo tipo) nuo 0 iki 1", + "clustering": { + "use-map-markers-clustering": "Naudoti žemėlapio žymeklių grupavimą", + "zoom-on-cluster-click": "Priartinti paspaudus ant grupės", + "max-zoom": "Didžiausias mastelio lygis, kai žymeklis gali priklausyti grupei (0–18)", + "max-radius": "Didžiausias spindulys, kurį apima grupė", + "zoom-animation": "Žymeklių animacija keičiat mastelį", + "bounds-on-cluster-mouse-over": "Rodyti žymeklių ribas užvedus pelę ant grupės", + "spiderfy-max-zoom-level": "Išskleisti grupės žymeklius esant didžiausiam masteliui (kad matytųsi visi)", + "load-optimization": "Įkėlimo optimizavimas", + "chunked-load": "Naudoti dalinį įkėlimą, kad puslapis neužstrigtų", + "lazy-load": "Naudoti uždelstą įkėlimą žymekliams pridėti", + "use-cluster-marker-color-function": "Naudoti grupės žymeklių spalvos funkciją", + "marker-color-function": "Žymeklio spalvos funkcija" + }, + "edit": "Redaguoti žymeklį", + "remove-marker-for": "Pašalinti žymeklį objektui '{{entityName}}'", + "place-marker": "Padėti žymeklį", + "place-marker-hint": "Spustelėkite, kad padėtumėte žymeklį", + "place-marker-hint-with-entity": "Spustelėkite, kad padėtumėte objektą '{{entityName}}'" }, - "change-owner": "Pakeisti savininką", - "select-target-owner": "Pasirinkite savininką", - "no-owners-matching": "Savinikų atitinkančių '{{owner}}' nėra.", - "target-owner-required": "Savininkas būtinas.", - "confirm-change-owner-title": "Ar tikrai norite pakeisti savininką { count, plural, =1 {1 pasirinktam subjektui} other {# pasirinktiems subjektams} }?", - "confirm-change-owner-text": "Būkite dėmesingi, po patvirtinimo, visi pasirinkti subjektai iš esamo savininko bus perkelti į naujo savininko grupę 'Visi'.", - "add-to-group": "Pridėti į grupę", - "move-to-group": "Perkelti į grupę", - "select-entity-group": "Pasirinkite subjektų grupę", - "no-entity-groups-matching": "Subjektų grupių, atitinkančių '{{entityGroup}}' nėra.", - "create-new-entity-group": "Sukurti naują!", - "target-entity-group-required": "Subjektų grupė būtina.", - "select-user-group": "Pasirinkite vartotojų grupę", - "no-user-groups-matching": "Vartotojų grupių, atitinkančių '{{entityGroup}}' nėra.", - "target-user-group-required": "Vartotojų grupė būtina.", - "remove-from-group": "Pašalinti iš grupės", - "group-table-title": "Grupių lentelės pavadinimas", - "enable-search": "Leisti subjektų paiešką", - "enable-add": "Leisti pridėti subjektus", - "enable-delete": "Leisti panaikinti subjektus", - "enable-selection": "Leisti subjektų pasirinkimą", - "enable-group-transfer": "Leisti perkėlimus tarp grupių", - "display-pagination": "Rodyti dalinimą puslapiais", - "default-page-size": "Numatytasis puslapio dydis", - "enable-assignment-actions": "Leisti priskirti", - "enable-credentials-management": "Leisti valdyti įgaliojimus", - "enable-login-as-user": "Leisti prisijungti kaip vartotojui", - "enable-users-management": "Leisti valdyti vartotojus", - "enable-customers-management": "Leisti valdyti klientus", - "enable-assets-management": "Leisti valdyti turtą", - "enable-devices-management": "Leisti valdyti įrenginius", - "enable-entity-views-management": "Leisti subjektų rodinių valdymą", - "enable-edges-management": "Enable edges management", - "enable-dashboards-management": "Leisti skydelių valdymą", - "enable-scheduler-events-management": "Leisti tvarkaraščio įvykių valdymą", - "open-details-on": "Atverti subjekto informaciją", - "select-existing": "Pasirinkti egzistuojančią subjektų grupę", - "create-new": "Sukurti naują subjektų grupę", - "new-entity-group-name": "Naujos subjektų grupės pavadinimas", - "entity-group-list": "Subjektų grupių sąrašas", - "entity-group-list-empty": "Nepasirinktos subjektų grupės.", - "name-starts-with": "Subjektų grupės pavadinimas prasideda", - "entity-group-name-filter-required": "Subjektų grupės filtras būtinas.", - "roles": "Rolės", - "permissions": "Leidimai", - "public": "Vieša", - "entity-group-public": "Subjektų grupė yra vieša", - "make-public": "Subjektų grupę padaryti vieša", - "make-private": "Subjektų grupę padaryti privačia", - "make-public-entity-group-title": "Ar tikrai norite subjektų grupę '{{entityGroupName}}' padaryti vieša?", - "make-public-entity-group-text": "Po patvirtinimo subjektų grupė ir visi jai priklausantys subjektai taps vieši ir matomi kitiems vartotojams.", - "make-private-entity-group-title": "Ar tikrai norite subjektų grupę '{{entityGroupName}}' padaryti privačia?", - "make-private-entity-group-text": "Po patvirtinimo, subjektų grupė ir visi jai priklausantys subjektai taps privatūs ir nematomi kitiems vartotojams.", - "share": "Pasdalinti grupe", - "copyId": "Kopijuoti subjektų grupės Id", - "idCopiedMessage": "Subjektų grupės Id nukopijuotas į škarpinę", - "entity-group-name": "Subjektų grupės pavadinimas", - "all-users": "Visi vartotojai", - "owner": "Savininkas", - "owner-required": "Savininkas būtinas.", - "manage-owner-and-groups": "Savininkas ir grupės", - "owner-and-groups": "Savininkas ir grupės" - }, - "entity-field": { - "created-time": "Sukūrimo laikas", - "name": "Pavadinimas", - "type": "Tipas", - "first-name": "Vardas", - "last-name": "Pavardė", - "email": "El. paštas", - "title": "Pavadinimas", - "country": "Šalis", - "state": "Rajonas", - "city": "Miestas", - "address": "Addresas", - "address2": "Addresas 2", - "zip": "Pašto kodas", - "phone": "Telefonas", - "label": "Etikelė", - "configuration": "Konfigūracija", - "schedule": "Grafikas", - "originatorId": "Iniciatoriaus Id", - "originatorType": "Iniciatoriaus tipas" - }, - "entity-view": { - "all": "Visi", - "all-entity-views": "Visi subjektų rodiniai", - "groups": "Grupės", - "shared": "bendrinami", - "entity-view": "Subjektų rodiniai", - "entity-view-required": "Subjeto rodinys būtinas.", - "entity-views": "Subjektų rodiniai", - "management": "Subjektų rodinių valdymas", - "view-entity-views": "Peržiūrėti subjektų rodinius", - "entity-view-alias": "Subjektų rodinio pseudonimas", - "aliases": "Subjektų rodinio pseudonimai", - "no-alias-matching": "'{{alias}}' nerastas.", - "no-aliases-found": "Pseudonimų nėra.", - "no-key-matching": "'{{key}}' nerastas.", - "no-keys-found": "Raktų nėra.", - "create-new-alias": "Sukurti naują!", - "create-new-key": "Sukurti naują!", - "duplicate-alias-error": "'{{alias}}' dubliuojasi.
Įrenginio pseudonimai skydelyje turi būti unikalūs.", - "configure-alias": "Konfigūruoti '{{alias}}' pseudonimą", - "no-entity-views-matching": "Subjektų rodinių, atitinkančių '{{entity}}' nėra.", - "public": "Viešas", - "alias": "Pseudonimas", - "alias-required": "Subjekto rodinio pseudonimas būtinas.", - "remove-alias": "Panaikinti subjekto rodinio pseudonimą", - "add-alias": "Pridėti subjekto rodinio pseudonimą", - "name-starts-with": "Subjekto rodinio pavadinimas prasideda", - "help-text": "Naudokite '%' simbolį pagal tai, kaip norite ieškoti: '%subjekto_rodinio_pavadinimo_fragmentas%', '%subjekto_rodinio_pavadinimo_pabaiga', 'subjekto_rodinio_pavadinimo_pradžia%'.", - "entity-view-list": "Subjektų rodinių sąrašas", - "use-entity-view-name-filter": "Naudoti filtrą", - "entity-view-list-empty": "Subjektai nepasirinkti.", - "entity-view-name-filter-required": "Subjekto rodinio pavadinimo filtras būtinas.", - "entity-view-name-filter-no-entity-view-matched": "Subjektų rodinių, kurių pavadinimai prasideda '{{entityView}}' nėra.", - "add": "Pridėti subjektų rodinį", - "entity-view-public": "Subjektų rodnys yra viešas", - "assign-to-customer": "Priskirti klientui", - "assign-entity-view-to-customer": "Subjektų rodinį (-ius) priskirti klientui", - "assign-entity-view-to-customer-text": "Pasirinkite subjektų rodinius, kuriuos norite priskirti klientui", - "no-entity-views-text": "Subjektų rodinių nėra", - "assign-to-customer-text": "Pasirinkite klientą, kuriam priskirti subjektų rodinį (-ius)", - "entity-view-details": "Informacija apie subjektų rodinį", - "add-entity-view-text": "Pridėti naują subjektų rodinį", - "delete": "Panikinti subjektų rodinį", - "assign-entity-views": "Priskirti subjektų rodinius", - "assign-entity-views-text": "Priskirti { count, plural, =1 {1 subjektų rodinį} other {# subjektų rodinius} } klientui", - "delete-entity-views": "Panaikinti subjektų rodinius", - "make-public": "Subjektų rodinį padaryti viešu", - "make-private": "Subjektų rodinį padaryti privačiu", - "unassign-from-customer": "Atsieti nuo kliento", - "unassign-entity-views": "Atsieti subjektų rodinius", - "unassign-entity-views-action-title": "Atsieti { count, plural, =1 {1 subjektų rodinį} other {# subjektų rodinius} } nuo kliento", - "assign-new-entity-view": "Priskirti naują subjektų rodinį", - "delete-entity-view-title": "Ar tikrai norite panaikinti subjektų rodinį '{{entityViewName}}'?", - "delete-entity-view-text": "Būkite dėmesingi, po patvirtinimo, subjektų rodinys ir visa su juo susijusi informacija bus panaikinta ir jų atkurti nebegalėsite.", - "delete-entity-views-title": "Ar tikrai norite panaikinti { count, plural, =1 {1 subketų rodinį} other {# subjektų rodinius} }?", - "delete-entity-views-action-title": "Panaikinti { count, plural, =1 {1 subjektų rodinį} other {# subjektų rodinius} }", - "delete-entity-views-text": "Būkite dėmesingi, po patvirtinimo, visi pasirinkti subjektų rodiniai ir visa su jais susijusi informacija bus panaikinta ir jų atkurti nebegalėsite.", - "make-public-entity-view-title": "Ar tikrai norite subjektų rodinį '{{entityViewName}}' padaryti viešu?", - "make-public-entity-view-text": "Po patvirtinimo subjektų rodinys ir visa su juo susijusi informacija taps vieša ir matoma kitiems vartotojams.", - "make-private-entity-view-title": "Ar tikrai norite subjektų rodinį '{{entityViewName}}' padaryti privačiu?", - "make-private-entity-view-text": "Po patvirtinimo subjektų rodinys ir visa su juo susijusi informacija taps privati ir kiti vartotojai jų nebematys.", - "unassign-entity-view-title": "Ar tikrai norite atsieti subjektų rodinį '{{entityViewName}}'?", - "unassign-entity-view-text": "Po patvirtinimo subjektų rodinys bus atsietas ir klientas jo nebematys.", - "unassign-entity-view": "Atsieti subjektų rodinį", - "unassign-entity-views-title": "Ar tikrai norite atsieti { count, plural, =1 {1 subjektų rodinį} other {# subjektų rodinius} }?", - "unassign-entity-views-text": "Po patvirtinimo visi pasirinkti subjektų rodiniai bus atsieti ir klientas jų nebematys.", - "entity-view-type": "Subjektų rodinio tipas", - "entity-view-type-required": "Subjektų rodinio tipas būtinas.", - "select-entity-view-type": "Pasirinkite subjektų rodinio tipą", - "enter-entity-view-type": "Įveskite subjektų rodinio tipą", - "any-entity-view": "Bet kuris subjektų tipas", - "no-entity-view-types-matching": "Subjektų rodinių, atitinkančių '{{entitySubtype}}' nėra.", - "entity-view-type-list-empty": "Subjektų tipai nepasirinkti.", - "entity-view-types": "Subjektų rodinio tipai", - "created-time": "Sukūrimo laikas", - "name": "Pavadinimas", - "name-required": "Pavadinimas būtinas.", - "name-max-length": "Pavadinimas negali viršyti 256 simbolių", - "type-max-length": "Rodinio tipas negali viršyti 256 simbolių", - "description": "Aprašymas", - "events": "Įvykiai", - "details": "Informacija", - "copyId": "Kopijuoti subjekto rodinio Id", - "idCopiedMessage": "Subjektų rodinio Id nukopjuotas į iškarpinę", - "assignedToCustomer": "Priskirtas klientui", - "unable-entity-view-device-alias-title": "Subjektų rodinio pseudonimo ištrinti nepavyko", - "unable-entity-view-device-alias-text": "Įrenginio pseudonimas '{{entityViewAlias}}' Negali būti ištrintas, nes jis naudojamas valdikliuose:
{{widgetsList}}", - "select-entity-view": "Pasirinkti subjektų rodinį", - "start-date": "Pradžios data", - "start-ts": "Pradžios laikas", - "end-date": "Pabaigos data", - "end-ts": "Pabaigos laikas", - "date-limits": "Datos limitas", - "client-attributes": "Kliento atributai", - "shared-attributes": "Bendrinami atributai", - "server-attributes": "Serverio atributai", - "timeseries": "Telemetrija", - "client-attributes-placeholder": "Kliento atributai", - "shared-attributes-placeholder": "Bendrinami atributai", - "server-attributes-placeholder": "Serverio atributai", - "timeseries-placeholder": "Telemetrija", - "target-entity": "Tikslinis subjektas", - "attributes-propagation": "Atributų paplitimas", - "attributes-propagation-hint": "Subjektų rodinys automatikškai kopijuos nurodytus atributus iš tikslinio subjekto kiekvieną kartą, kai išsaugosite ar atnaujinsite šį rodinį. Norint išsaugoti sistemos spartą, tikslinio subjekto atributai neperkeliami į subjektų rodinį kiekvieną kartą kai jie pasikeičia. Tačiau jūs galite įjungti automatinį atributų reikšmių perdavimą, taisyklių grandinėje sukonfigūravę \"copy to view\" taisyklę ir \"Post attributes\" bei \"Attributes Updated\" žinutes nukreipę į naują taisyklę.", - "timeseries-data": "Temetrijos duomenys", - "timeseries-data-hint": "Sukonfigūruokite tikslinio objekto telemetrijos duomenų raktus, kurie bus pasiekiami objekto rodinyje. Šios telemetrijos duomenys yra tik skaitomi.", - "select-group-to-add": "Pasirinkite grupę į kurią pridėti pažymėtus subjektų rodinius", - "select-group-to-move": "Pasirinkite grupę į kurią perkelti pažymėtus subjektų rodinius", - "remove-entity-views-from-group": "Ar tikrai norite iš '{{entityGroup}}' grupės pašalinti { count, plural, =1 {1 subjektų rodinį} other {# subjektų rodinius} }?", - "group": "Subjektų rodinių grupė", - "list-of-groups": "{ count, plural, =1 {Viena subjektų rodinių grupė} other {# subjektų rodinių grupių sąrašas} }", - "group-name-starts-with": "Subjektų rodinių grupės pavadinimas prasideda '{{prefix}}'", - "search": "Subjektų rodinių paieška", - "selected-entity-views": "Pasirinkta { count, plural, =1 {1 subjektų rodinys} other {# subjektų rodiniai} }", - "assign-entity-view-to-edge": "Assign Entity View(s) To Edge", - "assign-entity-view-to-edge-text": "Please select the entity views to assign to the edge", - "unassign-entity-view-from-edge-title": "Are you sure you want to unassign the entity view '{{entityViewName}}'?", - "unassign-entity-view-from-edge-text": "After the confirmation the entity view will be unassigned and won't be accessible by the edge.", - "unassign-entity-views-from-edge-action-title": "Unassign { count, plural, =1 {1 entity view} other {# entity views} } from edge", - "unassign-entity-view-from-edge": "Unassign entity view", - "unassign-entity-views-from-edge-title": "Are you sure you want to unassign { count, plural, =1 {1 entity view} other {# entity views} }?", - "unassign-entity-views-from-edge-text": "After the confirmation all selected entity views will be unassigned and won't be accessible by the edge." - }, - "event": { - "events": "Įvykiai", - "event-type": "Įvykio tipas", - "events-filter": "Įvykių filtras", - "clean-events": "Įšvalyti įvykius", - "type-error": "Klaida", - "type-lc-event": "Gyvavimo ciklo įvykis", - "type-stats": "Statistika", - "type-debug-converter": "Debug", - "type-debug-integration": "Debug", - "type-debug-rule-node": "Debug", - "type-debug-rule-chain": "Debug", - "no-events-prompt": "Įvykių nėra", - "error": "Klaida", - "alarm": "Įspėjimas", - "event-time": "Įvykio laikas", - "server": "Serveris", - "body": "Body", - "method": "Metodas", - "type": "Tipas", - "in": "Į", - "out": "Iš", - "metadata": "Metadata", - "message": "Message", - "entity": "Entity", - "message-id": "Message Id", - "copy-message-id": "Copy message Id", - "message-type": "Message Type", - "data-type": "Data Type", - "relation-type": "Relation Type", - "data": "Data", - "event": "Event", - "status": "Status", - "success": "Success", - "failed": "Failed", - "messages-processed": "Messages processed", - "max-messages-processed": "Maximum messages processed", - "min-messages-processed": "Minimum messages processed", - "errors-occurred": "Errors occurred", - "max-errors-occurred": "Maximum errors occurred", - "min-errors-occurred": "Minimum errors occurred", - "min-value": "Minimum value is 0.", - "all-events": "All", - "has-error": "Has error", - "entity-id": "Entity Id", - "copy-entity-id": "Copy entity Id", - "entity-type": "Entity type", - "clear-filter": "Clear Filter", - "clear-request-title": "Clear all events", - "clear-request-text": "Are you sure you want to clear all events?", - "started": "Started", - "updated": "Updated", - "stopped": "Stopped" - }, - "extension": { - "extensions": "Extensions", - "selected-extensions": "{ count, plural, =1 {1 extension} other {# extensions} } selected", - "type": "Type", - "key": "Key", - "value": "Value", - "id": "Id", - "extension-id": "Extension id", - "extension-type": "Extension type", - "transformer-json": "JSON *", - "unique-id-required": "Current extension id already exists.", - "delete": "Delete extension", - "add": "Add extension", - "edit": "Edit extension", - "view": "View extension", - "delete-extension-title": "Are you sure you want to delete the extension '{{extensionId}}'?", - "delete-extension-text": "Be careful, after the confirmation the extension and all related data will become unrecoverable.", - "delete-extensions-title": "Are you sure you want to delete { count, plural, =1 {1 extension} other {# extensions} }?", - "delete-extensions-text": "Be careful, after the confirmation all selected extensions will be removed.", - "converters": "Converters", - "converter-id": "Converter id", - "configuration": "Configuration", - "converter-configurations": "Converter configurations", - "token": "Security token", - "add-converter": "Add converter", - "add-config": "Add converter configuration", - "device-name-expression": "Device name expression", - "device-type-expression": "Device type expression", - "custom": "Custom", - "to-double": "To Double", - "transformer": "Transformer", - "json-required": "Transformer json is required.", - "json-parse": "Unable to parse transformer json.", - "attributes": "Attributes", - "add-attribute": "Add attribute", - "add-map": "Add mapping element", - "timeseries": "Timeseries", - "add-timeseries": "Add timeseries", - "field-required": "Field is required", - "brokers": "Brokers", - "add-broker": "Add broker", - "host": "Host", - "port": "Port", - "port-range": "Port should be in a range from 1 to 65535.", - "ssl": "Ssl", - "credentials": "Credentials", - "username": "Username", - "password": "Password", - "retry-interval": "Retry interval in milliseconds", - "sas": "Shared Access Signature", - "anonymous": "Anonymous", - "basic": "Basic", - "pem": "PEM", - "ca-cert": "CA certificate file *", - "private-key": "Private key file *", - "cert": "Certificate file *", - "no-file": "No file selected.", - "drop-file": "Drop a file or click to select a file to upload.", - "mapping": "Mapping", - "topic-filter": "Topic filter", - "converter-type": "Converter type", - "converter-json": "Json", - "json-name-expression": "Device name json expression", - "topic-name-expression": "Device name topic expression", - "json-type-expression": "Device type json expression", - "topic-type-expression": "Device type topic expression", - "attribute-key-expression": "Attribute key expression", - "attr-json-key-expression": "Attribute key json expression", - "attr-topic-key-expression": "Attribute key topic expression", - "request-id-expression": "Request id expression", - "request-id-json-expression": "Request id json expression", - "request-id-topic-expression": "Request id topic expression", - "response-topic-expression": "Response topic expression", - "value-expression": "Value expression", - "topic": "Topic", - "timeout": "Timeout in milliseconds", - "converter-json-required": "Converter json is required.", - "converter-json-parse": "Unable to parse converter json.", - "filter-expression": "Filter expression", - "connect-requests": "Connect requests", - "add-connect-request": "Add connect request", - "disconnect-requests": "Disconnect requests", - "add-disconnect-request": "Add disconnect request", - "attribute-requests": "Attribute requests", - "add-attribute-request": "Add attribute request", - "attribute-updates": "Attribute updates", - "add-attribute-update": "Add attribute update", - "server-side-rpc": "Server side RPC", - "add-server-side-rpc-request": "Add server-side RPC request", - "device-name-filter": "Device name filter", - "attribute-filter": "Attribute filter", - "method-filter": "Method filter", - "request-topic-expression": "Request topic expression", - "response-timeout": "Response timeout in milliseconds", - "topic-expression": "Topic expression", - "client-scope": "Client scope", - "add-device": "Add device", - "opc-server": "Servers", - "opc-add-server": "Add server", - "opc-add-server-prompt": "Please add server", - "opc-application-name": "Application name", - "opc-application-uri": "Application uri", - "opc-scan-period-in-seconds": "Scan period in seconds", - "opc-security": "Security", - "opc-identity": "Identity", - "opc-keystore": "Keystore", - "opc-type": "Type", - "opc-keystore-type": "Type", - "opc-keystore-location": "Location *", - "opc-keystore-password": "Password", - "opc-keystore-alias": "Alias", - "opc-keystore-key-password": "Key password", - "opc-device-node-pattern": "Device node pattern", - "opc-device-name-pattern": "Device name pattern", - "modbus-server": "Servers/slaves", - "modbus-add-server": "Add server/slave", - "modbus-add-server-prompt": "Please add server/slave", - "modbus-transport": "Transport", - "modbus-tcp-reconnect": "Automatically reconnect", - "modbus-rtu-over-tcp": "RTU over TCP", - "modbus-port-name": "Serial port name", - "modbus-encoding": "Encoding", - "modbus-parity": "Parity", - "modbus-baudrate": "Baud rate", - "modbus-databits": "Data bits", - "modbus-stopbits": "Stop bits", - "modbus-databits-range": "Data bits should be in a range from 7 to 8.", - "modbus-stopbits-range": "Stop bits should be in a range from 1 to 2.", - "modbus-unit-id": "Unit ID", - "modbus-unit-id-range": "Unit ID should be in a range from 1 to 247.", - "modbus-device-name": "Device name", - "modbus-poll-period": "Poll period (ms)", - "modbus-attributes-poll-period": "Attributes poll period (ms)", - "modbus-timeseries-poll-period": "Timeseries poll period (ms)", - "modbus-poll-period-range": "Poll period should be positive value.", - "modbus-tag": "Tag", - "modbus-function": "Function", - "modbus-register-address": "Register address", - "modbus-register-address-range": "Register address should be in a range from 0 to 65535.", - "modbus-register-bit-index": "Bit index", - "modbus-register-bit-index-range": "Bit index should be in a range from 0 to 15.", - "modbus-register-count": "Register count", - "modbus-register-count-range": "Register count should be a positive value.", - "modbus-byte-order": "Byte order", - "sync": { - "status": "Status", - "sync": "Sync", - "not-sync": "Not sync", - "last-sync-time": "Last sync time", - "not-available": "Not available" + "path": { + "path": "Kelias", + "path-decorator": "Kelio dekoratorius", + "decorator-symbol": "Dekoratoriaus simbolis", + "decorator-symbol-arrow-head": "Rodyklė", + "decorator-symbol-dash": "Brūkšnys", + "decorator-arrangement": "Dekoratoriaus išdėstymas", + "decorator-offset": "Pradžia", + "decorator-end-offset": "Pabaiga", + "decorator-repeat": "Kartojimas" + }, + "points": { + "points": "Taškai", + "point-tooltip": "Taško patarimas" }, - "export-extensions-configuration": "Export extensions configuration", - "import-extensions-configuration": "Import extensions configuration", - "import-extensions": "Import extensions", - "import-extension": "Import extension", - "export-extension": "Export extension", - "file": "Extensions file", - "invalid-file-error": "Invalid extension file", - "text": "TEXT", - "json": "JSON", - "binary": "BINARY", - "hex": "HEX" - }, - "feature": { - "advanced-features": "Advanced features" - }, - "filter": { - "add": "Add filter", - "edit": "Edit filter", - "name": "Filter name", - "name-required": "Filter name is required.", - "duplicate-filter": "Filter with same name is already exists.", - "filters": "Filters", - "unable-delete-filter-title": "Unable to delete filter", - "unable-delete-filter-text": "Filter '{{filter}}' can't be deleted as it used by the following widget(s):
{{widgetsList}}", - "duplicate-filter-error": "Duplicate filter found '{{filter}}'.
Filters must be unique within the dashboard.", - "missing-key-filters-error": "Key filters is missing for filter '{{filter}}'.", - "filter": "Filter", - "editable": "Editable", - "no-filters-found": "No filters found.", - "no-filter-text": "No filter specified", - "add-filter-prompt": "Please add filter", - "no-filter-matching": "'{{filter}}' not found.", - "create-new-filter": "Create a new one!", - "create-new": "Create new", - "filter-required": "Filter is required.", - "operation": { - "operation": "Operation", - "equal": "equal", - "not-equal": "not equal", - "starts-with": "starts with", - "ends-with": "ends with", - "contains": "contains", - "not-contains": "not contains", - "greater": "greater than", - "less": "less than", - "greater-or-equal": "greater or equal", - "less-or-equal": "less or equal", - "and": "and", - "or": "or", - "in": "in", - "not-in": "not in" + "shape": { + "fill": "Užpildymas", + "fill-type-color": "Spalva", + "fill-type-stripe": "Dryžis", + "fill-type-image": "Paveikslėlis", + "color": "Spalva", + "stripe": "Dryžis", + "image": "Paveikslėlis", + "stroke": "Kontūras", + "fill-image": "Užpildo paveikslėlis", + "fill-image-type-image": "Paveikslėlis", + "fill-image-type-function": "Funkcija", + "preserve-aspect-ratio": "Išlaikyti proporcijas", + "opacity": "Nepermatomumas", + "angle": "Pasukimo kampas", + "scale": "Mastelis", + "fill-image-function": "Formos užpildo paveikslėlio funkcija", + "fill-images": "Formos užpildo paveikslėliai", + "stripe-pattern": "Dryžių raštas", + "first-stripe": "Pirmas dryžis", + "second-stripe": "Antras dryžis" }, - "ignore-case": "ignore case", - "value": "Value", - "remove-filter": "Remove filter", - "duplicate-filter-action": "Duplicate filter", - "preview": "Filter preview", - "no-filters": "No filters configured", - "add-filter": "Add filter", - "add-complex-filter": "Add complex filter", - "add-complex": "Add complex", - "complex-filter": "Complex filter", - "edit-complex-filter": "Edit complex filter", - "edit-filter-user-params": "Edit filter predicate user parameters", - "filter-user-params": "Filter predicate user parameters", - "user-parameters": "User parameters", - "display-label": "Label to display", - "order-priority": "Field order priority", - "key-filter": "Key filter", - "key-filters": "Key filters", - "key-name": "Key name", - "key-name-required": "Key name is required.", - "key-type": { - "key-type": "Key type", - "attribute": "Attribute", - "timeseries": "Timeseries", - "entity-field": "Entity field", - "constant": "Constant" + "polygon": { + "polygon-key": "Daugiakampio raktas", + "polygon-key-required": "Daugiakampio raktas yra privalomas", + "no-polygons": "Daugiakampiai nesukonfigūruoti", + "add-polygon": "Pridėti daugiakampį", + "polygon-configuration": "Daugiakampio konfigūracija", + "remove-polygon": "Pašalinti daugiakampį", + "edit": "Redaguoti daugiakampį", + "remove-polygon-for": "Pašalinti daugiakampį objektui '{{entityName}}'", + "cut": "Iškirpti daugiakampio sritį", + "rotate": "Pasukti daugiakampį", + "draw-rectangle": "Nubrėžti stačiakampį", + "draw-polygon": "Nubrėžti daugiakampį", + "polygon-place-first-point-cut-hint": "Spustelėkite, kad padėtumėte pirmą tašką", + "continue-polygon-cut-hint": "Spustelėkite, kad tęstumėte braižymą", + "finish-polygon-cut-hint": "Spustelėkite pirmą žymeklį, kad baigtumėte ir išsaugotumėte", + "polygon-place-first-point-hint": "Daugiakampis: spustelėkite, kad padėtumėte pirmą tašką", + "polygon-place-first-point-hint-with-entity": "Daugiakampis objektui '{{entityName}}': spustelėkite, kad padėtumėte pirmą tašką", + "continue-polygon-hint": "Daugiakampis: spustelėkite, kad tęstumėte braižymą", + "continue-polygon-hint-with-entity": "Daugiakampis objektui '{{entityName}}': spustelėkite, kad tęstumėte braižymą", + "finish-polygon-hint": "Daugiakampis: spustelėkite pirmą žymeklį, kad baigtumėte braižymą", + "finish-polygon-hint-with-entity": "Daugiakampis objektui '{{entityName}}': spustelėkite pirmą žymeklį, kad baigtumėte ir išsaugotumėte", + "rectangle-place-first-point-hint": "Stačiakampis: spustelėkite, kad padėtumėte pirmą tašką", + "rectangle-place-first-point-hint-with-entity": "Stačiakampis objektui '{{entityName}}': spustelėkite, kad padėtumėte pirmą tašką", + "finish-rectangle-hint": "Stačiakampis: spustelėkite, kad baigtumėte braižymą", + "finish-rectangle-hint-with-entity": "Stačiakampis objektui '{{entityName}}': spustelėkite, kad baigtumėte ir išsaugotumėte" }, - "value-type": { - "value-type": "Value type", - "string": "String", - "numeric": "Numeric", - "boolean": "Boolean", - "date-time": "Datetime" + "circle": { + "circle-key": "Apskritimo raktas", + "circle-key-required": "Apskritimo raktas yra privalomas", + "no-circles": "Apskritimai nesukonfigūruoti", + "add-circle": "Pridėti apskritimą", + "circle-configuration": "Apskritimo konfigūracija", + "remove-circle": "Pašalinti apskritimą", + "edit": "Redaguoti apskritimą", + "remove-circle-for": "Pašalinti apskritimą objektui '{{entityName}}'", + "draw-circle": "Nubrėžti apskritimą", + "place-circle-center-hint-with-entity": "Apskritimas objektui '{{entityName}}': spustelėkite, kad padėtumėte apskritimo centrą", + "place-circle-center-hint": "Apskritimas: spustelėkite, kad padėtumėte apskritimo centrą", + "finish-circle-hint-with-entity": "Apskritimas objektui '{{entityName}}': spustelėkite, kad baigtumėte ir išsaugotumėte", + "finish-circle-hint": "Apskritimas: spustelėkite, kad baigtumėte braižymą" }, - "value-type-required": "Key value type is required.", - "key-value-type-change-title": "Are you sure you want to change key value type?", - "key-value-type-change-message": "If you confirm new value type all entered key filters will be removed.", - "no-key-filters": "No key filters configured", - "add-key-filter": "Add key filter", - "remove-key-filter": "Remove key filter", - "edit-key-filter": "Edit key filter", - "date": "Date", - "time": "Time", - "current-tenant": "Current tenant", - "current-customer": "Current customer", - "current-user": "Current user", - "current-device": "Current device", - "default-value": "Default value", - "dynamic-source-type": "Dynamic source type", - "dynamic-value": "Dynamic value", - "no-dynamic-value": "No dynamic value", - "source-attribute": "Source attribute", - "switch-to-dynamic-value": "Switch to dynamic value", - "switch-to-default-value": "Switch to default value", - "inherit-owner": "Inherit from owner", - "source-attribute-not-set": "If source attribute isn't set" - }, - "fullscreen": { - "expand": "Rodyti per visą ekraną", - "exit": "Išjungti rodymą per visą ekraną", - "toggle": "Rodyti per visą ekraną", - "fullscreen": "Rodyti per visą ekraną" - }, - "function": { - "function": "Funkcija" + "select-entity": "Pasirinkti objektą", + "select-entity-hint": "Patarimas: po pasirinkimo spustelėkite žemėlapyje, kad nustatytumėte padėtį" + }, + "select-entity": "Pasirinkti objektą", + "select-entity-hint": "Patarimas: po pasirinkimo spustelėkite žemėlapyje, kad nustatytumėte padėtį", + "tooltips": { + "placeMarker": "Spustelėkite, kad padėtumėte objektą '{{entityName}}'", + "firstVertex": "Daugiakampis objektui '{{entityName}}': spustelėkite, kad padėtumėte pirmą tašką", + "firstVertex-cut": "Spustelėkite, kad padėtumėte pirmą tašką", + "continueLine": "Daugiakampis objektui '{{entityName}}': spustelėkite, kad tęstumėte braižymą", + "continueLine-cut": "Spustelėkite, kad tęstumėte braižymą", + "finishLine": "Spustelėkite bet kurį esamą žymeklį, kad baigtumėte", + "finishPoly": "Daugiakampis objektui '{{entityName}}': spustelėkite pirmą žymeklį, kad baigtumėte ir išsaugotumėte", + "finishPoly-cut": "Spustelėkite pirmą žymeklį, kad baigtumėte ir išsaugotumėte", + "finishRect": "Daugiakampis objektui '{{entityName}}': spustelėkite, kad baigtumėte ir išsaugotumėte", + "startCircle": "Apskritimas objektui '{{entityName}}': spustelėkite, kad padėtumėte apskritimo centrą", + "finishCircle": "Apskritimas objektui '{{entityName}}': spustelėkite, kad baigtumėte apskritimą", + "placeCircleMarker": "Spustelėkite, kad padėtumėte apskritimo žymeklį" + }, + "actions": { + "finish": "Baigti", + "cancel": "Atšaukti", + "removeLastVertex": "Pašalinti paskutinį tašką" + }, + "buttonTitles": { + "drawMarkerButton": "Padėti objektą", + "drawPolyButton": "Sukurti daugiakampį", + "drawLineButton": "Sukurti liniją", + "drawCircleButton": "Sukurti apskritimą", + "drawRectButton": "Sukurti stačiakampį", + "editButton": "Redagavimo režimas", + "dragButton": "Vilkimo režimas", + "cutButton": "Iškirpti daugiakampio sritį", + "deleteButton": "Pašalinti", + "drawCircleMarkerButton": "Sukurti apskritimo žymeklį", + "rotateButton": "Pasukti daugiakampį" + }, + "map-provider-settings": "Žemėlapio tiekėjo nustatymai", + "map-provider": "Žemėlapio tiekėjas", + "map-provider-google": "Google žemėlapiai", + "map-provider-openstreet": "OpenStreet žemėlapiai", + "map-provider-here": "HERE žemėlapiai", + "map-provider-image": "Paveikslėlio žemėlapis", + "map-provider-tencent": "Tencent žemėlapiai", + "openstreet-provider": "OpenStreet žemėlapių tiekėjas", + "openstreet-provider-mapnik": "OpenStreetMap.Mapnik (numatytasis)", + "openstreet-provider-hot": "OpenStreetMap.HOT", + "openstreet-provider-esri-street": "Esri.WorldStreetMap", + "openstreet-provider-esri-topo": "Esri.WorldTopoMap", + "openstreet-provider-esri-imagery": "Esri.WorldImagery", + "openstreet-provider-cartodb-positron": "CartoDB.Positron", + "openstreet-provider-cartodb-dark-matter": "CartoDB.DarkMatter", + "use-custom-provider": "Naudoti pasirinktinį tiekėją", + "custom-provider-tile-url": "Pasirinktinio tiekėjo plytelių URL", + "google-maps-api-key": "Google Maps API raktas", + "default-map-type": "Numatytasis žemėlapio tipas", + "google-map-type-roadmap": "Keliai", + "google-map-type-satelite": "Palydovas", + "google-map-type-hybrid": "Hibridinis", + "google-map-type-terrain": "Reljefas", + "map-layer": "Žemėlapio sluoksnis", + "here-map-normal-day": "HERE.normalDay (numatytasis)", + "here-map-normal-night": "HERE.normalNight", + "here-map-hybrid-day": "HERE.hybridDay", + "here-map-terrain-day": "HERE.terrainDay", + "credentials": "Prisijungimo duomenys", + "here-app-id": "HERE programos ID", + "here-app-code": "HERE programos kodas", + "here-api-key": "HERE API raktas", + "here-use-new-version-api-3": "Naudoti API 3 versiją", + "tencent-maps-api-key": "Tencent Maps API raktas", + "tencent-map-type-roadmap": "Keliai", + "tencent-map-type-satelite": "Palydovas", + "tencent-map-type-hybrid": "Hibridinis", + "image-map-background": "Paveikslėlio žemėlapio fonas", + "image-map-background-from-entity-attribute": "Naudoti paveikslėlį iš objekto atributo kaip žemėlapio foną", + "image-url-source-entity-alias": "Paveikslėlio URL šaltinio objekto pseudonimas", + "image-url-source-entity-attribute": "Paveikslėlio URL šaltinio objekto atributas", + "common-map-settings": "Bendrieji žemėlapio nustatymai", + "x-pos-key-name": "X padėties rakto pavadinimas", + "y-pos-key-name": "Y padėties rakto pavadinimas", + "latitude-key-name": "Platumos rakto pavadinimas", + "longitude-key-name": "Ilgumos rakto pavadinimas", + "default-map-zoom-level": "Numatytasis priartinimo lygis (0–20)", + "default-map-center-position": "Numatytoji žemėlapio centro padėtis (0,0)", + "disable-scroll-zooming": "Išjungti priartinimą slenkant", + "disable-double-click-zooming": "Išjungti priartinimą dukart spustelėjus", + "disable-zoom-control-buttons": "Išjungti priartinimo valdymo mygtukus", + "fit-map-bounds": "Pritaikyti žemėlapio ribas, kad apimtų visus žymeklius", + "use-default-map-center-position": "Naudoti numatytąją žemėlapio centro padėtį", + "entities-limit": "Objektų įkėlimo riba", + "markers-settings": "Žymeklių nustatymai", + "marker-offset-x": "Žymeklio X poslinkis, lyginant su padėtimi (daugiklis žymeklio pločiui)", + "marker-offset-y": "Žymeklio Y poslinkis, lyginant su padėtimi (daugiklis žymeklio aukščiui)", + "position-function": "Padėties konversijos funkcija, grąžinanti x,y koordinates nuo 0 iki 1", + "draggable-marker": "Vilkiojamas žymeklis", + "label": "Etiketė", + "show-label": "Rodyti etiketę", + "use-label-function": "Naudoti etiketės funkciją", + "label-pattern": "Etiketė (pavyzdžiai: '${entityName}', '${entityName}: (Tekstas ${keyName} vienetai.)')", + "label-function": "Etiketės funkcija", + "tooltip": "Patarimas", + "show-tooltip": "Rodyti patarimą", + "show-tooltip-action": "Veiksmas, kai rodomas patarimas", + "show-tooltip-action-click": "Rodyti spustelėjus (numatytasis)", + "show-tooltip-action-hover": "Rodyti užvedus žymeklį", + "auto-close-tooltips": "Automatiškai uždaryti patarimus", + "use-tooltip-function": "Naudoti patarimo funkciją", + "tooltip-pattern": "Patarimas (pvz.: 'Tekstas ${keyName} vienetai.' arba Nuorodos tekstas)", + "tooltip-function": "Patarimo funkcija", + "tooltip-offset-x": "Patarimo X poslinkis (pagal žymeklio inkarą, dauginamas iš pločio)", + "tooltip-offset-y": "Patarimo Y poslinkis (pagal žymeklio inkarą, dauginamas iš aukščio)", + "color": "Spalva", + "use-color-function": "Naudoti spalvos funkciją", + "color-function": "Spalvos funkcija", + "marker-image": "Žymeklio paveikslėlis", + "use-marker-image-function": "Naudoti žymeklio paveikslėlio funkciją", + "custom-marker-image": "Pasirinktinis žymeklio paveikslėlis", + "custom-marker-image-size": "Pasirinktinio žymeklio paveikslėlio dydis (px)", + "marker-image-function": "Žymeklio paveikslėlio funkcija", + "marker-images": "Žymeklio paveikslėliai", + "polygon-settings": "Daugiakampio nustatymai", + "show-polygon": "Rodyti daugiakampį", + "polygon-key-name": "Daugiakampio rakto pavadinimas", + "enable-polygon-edit": "Įjungti daugiakampio redagavimą", + "polygon-label": "Daugiakampio etiketė", + "show-polygon-label": "Rodyti daugiakampio etiketę", + "use-polygon-label-function": "Naudoti daugiakampio etiketės funkciją", + "polygon-label-pattern": "Daugiakampio etiketė (pavyzdžiai: '${entityName}', '${entityName}: (Tekstas ${keyName} vienetai.)')", + "polygon-label-function": "Daugiakampio etiketės funkcija", + "polygon-tooltip": "Daugiakampio patarimas", + "show-polygon-tooltip": "Rodyti daugiakampio patarimą", + "auto-close-polygon-tooltips": "Automatiškai uždaryti daugiakampio patarimus", + "use-polygon-tooltip-function": "Naudoti daugiakampio patarimo funkciją", + "polygon-tooltip-pattern": "Patarimas (pvz.: 'Tekstas ${keyName} vienetai.' arba Nuorodos tekstas)", + "polygon-tooltip-function": "Daugiakampio patarimo funkcija", + "polygon-color": "Daugiakampio spalva", + "polygon-opacity": "Daugiakampio permatomumas", + "use-polygon-color-function": "Naudoti daugiakampio spalvos funkciją", + "polygon-color-function": "Daugiakampio spalvos funkcija", + "polygon-stroke": "Daugiakampio brūkšnys", + "stroke-color": "Brūkšnio spalva", + "stroke-opacity": "Brūkšnio permatomumas", + "stroke-weight": "Brūkšnio storis", + "use-polygon-stroke-color-function": "Naudoti daugiakampio brūkšnio spalvos funkciją", + "polygon-stroke-color-function": "Daugiakampio brūkšnio spalvos funkcija", + "circle-settings": "Apskritimo nustatymai", + "show-circle": "Rodyti apskritimą", + "circle-key-name": "Apskritimo rakto pavadinimas", + "enable-circle-edit": "Įjungti apskritimo redagavimą", + "circle-label": "Apskritimo etiketė", + "show-circle-label": "Rodyti apskritimo etiketę", + "use-circle-label-function": "Naudoti apskritimo etiketės funkciją", + "circle-label-pattern": "Apskritimo etiketė (pavyzdžiai: '${entityName}', '${entityName}: (Tekstas ${keyName} vienetai.)')", + "circle-label-function": "Apskritimo etiketės funkcija", + "circle-tooltip": "Apskritimo patarimas", + "show-circle-tooltip": "Rodyti apskritimo patarimą", + "auto-close-circle-tooltips": "Automatiškai uždaryti apskritimo patarimus", + "use-circle-tooltip-function": "Naudoti apskritimo patarimo funkciją", + "circle-tooltip-pattern": "Patarimas (pvz.: 'Tekstas ${keyName} vienetai.' arba Nuorodos tekstas)", + "circle-tooltip-function": "Apskritimo patarimo funkcija", + "circle-fill-color": "Apskritimo užpildo spalva", + "circle-fill-color-opacity": "Apskritimo užpildo permatomumas", + "use-circle-fill-color-function": "Naudoti apskritimo užpildo spalvos funkciją", + "circle-fill-color-function": "Apskritimo užpildo spalvos funkcija", + "circle-stroke": "Apskritimo brūkšnys", + "use-circle-stroke-color-function": "Naudoti apskritimo brūkšnio spalvos funkciją", + "circle-stroke-color-function": "Apskritimo brūkšnio spalvos funkcija", + "markers-clustering-settings": "Žymeklių grupavimo nustatymai", + "use-map-markers-clustering": "Naudoti žymeklių grupavimą", + "zoom-on-cluster-click": "Priartinti paspaudus ant grupės", + "max-cluster-zoom": "Didžiausias priartinimo lygis, kuriame žymeklis gali priklausyti grupei (0–18)", + "max-cluster-radius-pixels": "Didžiausias grupės spindulys (pikseliais)", + "cluster-zoom-animation": "Rodyti animaciją žymekliams priartinant", + "show-markers-bounds-on-cluster-mouse-over": "Rodyti žymeklių ribas užvedus pelę ant grupės", + "spiderfy-max-zoom-level": "Išskleisti (spiderfy) didžiausiame priartinimo lygyje, kad matytųsi visi žymekliai", + "load-optimization": "Įkėlimo optimizavimas", + "cluster-chunked-loading": "Naudoti dalinį žymeklių įkėlimą, kad puslapis neužstrigtų", + "cluster-markers-lazy-load": "Naudoti „lazy load“ žymeklių įkėlimui", + "editor-settings": "Redaktoriaus nustatymai", + "enable-snapping": "Įjungti pritraukimą prie kitų viršūnių tikslumui", + "init-draggable-mode": "Paleisti žemėlapį vilkiojimo režimu", + "hide-all-edit-buttons": "Slėpti visus redagavimo valdiklius", + "hide-draw-buttons": "Slėpti braižymo mygtukus", + "hide-edit-buttons": "Slėpti redagavimo mygtukus", + "hide-remove-button": "Slėpti šalinimo mygtuką", + "route-map-settings": "Maršruto žemėlapio nustatymai", + "trip-animation-settings": "Kelionės animacijos nustatymai", + "normalization-step": "Normalizavimo žingsnis (ms)", + "tooltip-background-color": "Patarimo fono spalva", + "tooltip-font-color": "Patarimo teksto spalva", + "tooltip-opacity": "Patarimo permatomumas (0–1)", + "auto-close-tooltip": "Automatiškai uždaryti patarimą", + "rotation-angle": "Papildomas žymeklio pasukimo kampas (laipsniais)", + "path-settings": "Kelio nustatymai", + "path-color": "Kelio spalva", + "use-path-color-function": "Naudoti kelio spalvos funkciją", + "path-color-function": "Kelio spalvos funkcija", + "path-decorator": "Kelio dekoratorius", + "use-path-decorator": "Naudoti kelio dekoratorių", + "decorator-symbol": "Dekoratoriaus simbolis", + "decorator-symbol-arrow-head": "Rodyklė", + "decorator-symbol-dash": "Brūkšnys", + "decorator-symbol-size": "Dekoratoriaus simbolio dydis (px)", + "use-path-decorator-custom-color": "Naudoti pasirinktinę dekoratoriaus spalvą", + "decorator-custom-color": "Dekoratoriaus pasirinktinė spalva", + "decorator-offset": "Dekoratoriaus poslinkis", + "end-decorator-offset": "Dekoratoriaus pabaigos poslinkis", + "decorator-repeat": "Dekoratoriaus kartojimas", + "points-settings": "Taškų nustatymai", + "show-points": "Rodyti taškus", + "point-color": "Taško spalva", + "point-size": "Taško dydis (px)", + "use-point-color-function": "Naudoti taško spalvos funkciją", + "point-color-function": "Taško spalvos funkcija", + "use-point-as-anchor": "Naudoti tašką kaip inkarą", + "point-as-anchor-function": "Taško kaip inkaro funkcija", + "independent-point-tooltip": "Nepriklausomas taško patarimas", + "clustering-markers": "Žymeklių grupavimas", + "use-icon-create-function": "Naudoti žymeklių spalvos funkciją", + "marker-color-function": "Žymeklio spalvos funkcija" }, - "gateway": { - "gateway-exists": "Device with same name is already exists.", - "gateway-name": "Gateway name", - "gateway-name-required": "Gateway name is required.", - "gateway-saved": "Gateway configuration successfully saved.", - "gateway": "Gateway", - "create-new-gateway": "Create a new gateway", - "create-new-gateway-text": "Are you sure you want create a new gateway with name: '{{gatewayName}}'?", - "no-gateway-found": "No gateway found.", - "no-gateway-matching": " '{{item}}' not found." - }, - "grid": { - "delete-item-title": "Ar tikrai norite pašalinti šį elementą?", - "delete-item-text": "Būkite dėmesingi, po patvirtinimo šio elemento ir visos su juo susijusios informacijos atkurti nebegalėsite.", - "delete-items-title": "Ar tikrai norite pašalinti { count, plural, =1 {1 elementą} other {# elementus} }?", - "delete-items-action-title": "Panaikinti { count, plural, =1 {1 elementą} other {# elementus} }", - "delete-items-text": "Būkite dėmesingi, po patvirtinimo visi pasirinkti elementai ir su jais susijusi informacija bus pašalinti ir jų atkurti nebegalėsite.", - "add-item-text": "Pridėti naują elementą", - "no-items-text": "Elementų nėra", - "item-details": "Informacija apie elementą", - "delete-item": "Panaikinti elementą", - "delete-items": "Panaikinti elmentus", - "scroll-to-top": "Slinkti į viršų" - }, - "help": { - "goto-help-page": "Pagalba", - "show-help": "Pagalba" + "markdown": { + "use-markdown-text-function": "Naudoti markdown/HTML reikšmės funkciją", + "markdown-text-function": "Markdown/HTML reikšmės funkcija", + "markdown-text-pattern": "Markdown/HTML šablonas (markdown arba HTML su kintamaisiais, pvz.: '${entityName} arba ${keyName} - kažkoks tekstas.')", + "apply-default-markdown-style": "Taikyti numatytąjį markdown stilių", + "markdown-css": "Markdown/HTML CSS" }, - "home": { - "home": "Pagrindinis", - "profile": "Profilis", - "logout": "Atsijungti", - "menu": "Meniu", - "avatar": "Paveiksliukas", - "open-user-menu": "Atverti vartoto meniu" - }, - "file-input": { - "browse-file": "Pasirinkti failą", - "browse-files": "Pasirinkti failus" - }, - "image-input": { - "drop-images-or": "Užvilkite paveikslėlį arba", - "drag-and-drop": "Užvilkite", - "or": "arba", - "browse": "Pasirinkite", - "no-images": "Paveikslėlis nepasirinktas", - "images": "paveikslėliai" - }, - "import": { - "no-file": "Nepasirinktas failas", - "drop-file": "Nuvilkite JSON failą arba spustelėkite, kad pasirinktumėte failą, kurį norite įkelti.", - "drop-csv-file": "Nuvilkite CSV failą arba spustelėkite, kad pasirinktumėte failą, kurį norite įkelti.", - "drop-json-file-or": "Nuvilkite JSON failą arba", - "drop-file-csv": "Nuvilkite CSV failą arba spustelėkite, kad pasirinktumėte failą, kurį norite įkelti.", - "drop-file-csv-or": "Nuvilkite CSV failą arba", - "column-value": "Reikšmė", - "column-title": "Pavadinimas", - "column-example": "Duomenų pavyzdys", - "column-key": "Atributo/telemetrijos raktas", - "credentials": "Įgaliojimai", - "csv-delimiter": "CSV skyriklis", - "csv-first-line-header": "Pirmoje eilutėje stulpelių pavadinimai", - "csv-update-data": "Atnaujinti artibutą/telemetriją", - "details": "Informacija", - "import-csv-number-columns-error": "Faile turi būti bent du stulpeliai", - "import-csv-invalid-format-error": "Neteisingas failo formatas. Elutė: '{{line}}'", - "column-type": { - "name": "Pavadinimas", - "type": "Tipas", - "label": "Etiketė", - "column-type": "Stulpelio tipas", - "client-attribute": "Kliento atributas", - "shared-attribute": "Bendrinamas atributas", - "server-attribute": "Serverio atributas", - "timeseries": "Telemetrija", - "entity-field": "Subjekto laukas", - "access-token": "Prieigos raktas", - "x509": "X.509", - "mqtt": { - "client-id": "MQTT client ID", - "user-name": "MQTT user name", - "password": "MQTT password" - }, - "lwm2m": { - "client-endpoint": "LwM2M endpoint client name", - "security-config-mode": "LwM2M security config mode", - "client-identity": "LwM2M client identity", - "client-key": "LwM2M client key", - "client-cert": "LwM2M client public key", - "bootstrap-server-security-mode": "LwM2M bootstrap server security mode", - "bootstrap-server-secret-key": "LwM2M bootstrap server secret key", - "bootstrap-server-public-key-id": "LwM2M bootstrap server public key or id", - "lwm2m-server-security-mode": "LwM2M server security mode", - "lwm2m-server-secret-key": "LwM2M server secret key", - "lwm2m-server-public-key-id": "LwM2M server public key or id" - }, - "snmp": { - "host": "SNMP host", - "port": "SNMP port", - "version": "SNMP version (v1, v2c or v3)", - "community-string": "SNMP community string" - }, - "isgateway": "Is Gateway", - "activity-time-from-gateway-device": "Activity time from gateway device", - "description": "Description", - "edge-license-key": "License Key", - "cloud-endpoint": "Cloud Endpoint", - "routing-key": "Edge key", - "secret": "Edge secret" - }, - "stepper-text": { - "select-file": "Pasirinkite failą", - "configuration": "Importo konfigūracija", - "column-type": "Pasirinkite stulpelių tipus", - "creat-entities": "Sukurti naujus subjektus" - }, - "message": { - "create-entities": "Sukurti {{count}} nauji subjektai.", - "update-entities": "Atnaujinti {{count}} subjektai.", - "error-entities": "Kuriant {{count}} subjektų įvyko klaidų." - } + "simple-card": { + "label": "Etiketė", + "label-position": "Etiketės padėtis", + "label-position-left": "Kairėje", + "label-position-top": "Viršuje" }, - "integration": { - "integration": "Integration", - "integrations": "Integrations", - "integrations-center": "Integrations center", - "select-integration": "Select integration", - "no-integrations-matching": "No integrations matching '{{entity}}' were found.", - "integration-required": "Integration is required", - "delete": "Delete integration", - "management": "Integrations management", - "add-integration-text": "Add new integration", - "no-integrations-text": "No integrations found", - "data-convertor-name": "{{convertorType}} data converter for {{integrationName}}", - "integration-name": "{{integrationType}} integration", - "selected-integrations": "{ count, plural, =1 {1 integration} other {# integrations} } selected", - "delete-integration-title": "Are you sure you want to delete the integration '{{integrationName}}'?", - "delete-integration-text": "Be careful, after the confirmation the integration and all related data will become unrecoverable.", - "delete-integrations-title": "Are you sure you want to delete { count, plural, =1 {1 integration} other {# integrations} }?", - "delete-integrations-action-title": "Delete { count, plural, =1 {1 integration} other {# integrations} }", - "delete-integrations-text": "Be careful, after the confirmation all selected integrations will be removed and all related data will become unrecoverable.", - "events": "Events", - "enabled": "Enable integration", - "allow-create-devices-or-assets": "Allow create devices or assets", - "all-types": "All integration types", - "add": "Add Integration", - "search": "Search integrations", - "integration-details": "Integration details", - "details": "Details", - "copyId": "Copy integration Id", - "idCopiedMessage": "Integration Id has been copied to clipboard", - "debug-mode": "Debug mode", - "enable-security": "Enable security", - "enable-security-new": "Enable security for automatic token updates", - "headers-filter": "Headers filter", - "header": "Header", - "no-headers-filter": "No headers filter", - "downlink-url": "Downlink URL", - "downlink-url-required": "Downlink URL is required", - "create-loriot-output": "Create Loriot Application output", - "send-downlink": "Send downlink", - "allow-downlink": "Allow downlink", - "server": "Server", - "server-required": "Server is required", - "domain": "Domain", - "app-id": "Application ID", - "app-id-required": "Application ID is required", - "app-token": "Application Access Token", - "app-token-required": "Application Access Token is required", - "email": "Email", - "email-required": "Email is required", - "application-uri": "Application URI", - "as-id": "AS ID", - "as-id-required": "AS ID is required.", - "as-key": "AS Key", - "as-key-required": "AS Key is required.", - "client-id-new": "Client Id", - "client-id-new-required": "Client Id (login) is required (login).", - "client-secret": "Client Secret", - "client-secret-required": "Client Secret (password) is required (password).", - "max-time-diff-in-seconds": "Maximum time difference (seconds)", - "max-time-diff-in-seconds-required": "Maximum time difference is required.", - "created-time": "Created time", - "name": "Name", - "name-required": "Name is required.", - "name-max-length": "Name should be less than 256", - "description": "Description", - "base-url": "Base URL", - "base-url-required": "Base URL is required", - "security-key": "Security key", - "http-endpoint": "HTTP endpoint URL", - "replace-no-content-to-ok": "Replace response status from 'No-Content' to 'OK'", - "copy-http-endpoint-url": "Copy HTTP endpoint URL", - "http-endpoint-url-copied-message": "HTTP endpoint URL has been copied to clipboard", - "host": "Host", - "host-required": "Host is required.", - "host-private": "Host must be in the public network.", - "url-private": "URL must be in the public network.", - "host-type": "Host type", - "host-type-required": "Host type is required.", - "api-version": "Use API v3", - "custom-host": "Custom host", - "custom-host-required": "Custom host is required.", - "port": "Port", - "port-required": "Port is required.", - "port-range": "Port should be in a range from 1 to 65535.", - "connect-timeout": "Connection timeout (sec)", - "connect-timeout-required": "Connection timeout is required.", - "connect-timeout-range": "Connection timeout should be in a range from 1 to 200.", - "client-id": "Client ID", - "client-id-required": "Client ID is required.", - "client-id-hint": "Hint: Optional. Leave empty for auto-generated client ID. Be careful when specifying the Client ID. Majority of the MQTT brokers will not allow multiple connections with the same client ID. To connect to such brokers, your MQTT client ID must be unique.", - "max-bytes-in-message": "Max bytes in message", - "max-bytes-in-message-range": "Max bytes in message should be in a range from 1 to 256000000.", - "device-id": "Device ID", - "device-id-required": "Device ID is required.", - "device-id-range": "Device ID should be in a range from 1 to 65535 characters.", - "device-id-pattern": "Device ID should consist of numbers, upper and lower case letters. [MQTT-3.1.3-5]", - "group-id": "Group ID", - "group-id-required": "Group ID is required.", - "topics": "Topics", - "topics-required": "Topic is required.", - "routing-keys": "Routing keys", - "routing-keys-required": "Routing key is required.", - "queues": "Queues", - "queues-required": "Queue name is required.", - "durable": "Durable", - "exclusive": "Exclusive", - "autoDelete": "Auto delete", - "exchange-name": "Exchange name", - "exchange-name-required": "Exchange name is required.", - "downlink-topic": "Downlink topic", - "connection-timeout": "Connection timeout, ms", - "connection-timeout-min": "Invalid connection timeout value.", - "handshake-timeout": "Handshake timeout, ms", - "handshake-timeout-min": "Invalid handshake timeout value.", - "virtual-host": "Virtual host", - "rabbit-mq-poll-interval": "Poll interval, ms", - "rabbit-mq-poll-interval-min": "Invalid poll interval value.", - "application-server-url": "Application server URL", - "application-server-url-required": "Application server URL is required.", - "application-server-api-token": "Application server API Token", - "application-server-api-token-required": "Application server API Token is required.", - "use-api-four-plus": "Use API for ChirpStack 4+", - "bootstrap-servers": "Bootstrap servers", - "bootstrap-servers-required": "Bootstrap servers is required.", - "poll-interval": "Poll interval", - "poll-interval-required": "Poll interval is required.", - "poll-interval-min-value": "Poll interval value can't be less then 1", - "auto-create-topics": "Auto create topics", - "clean-session": "Clean session", - "enable-ssl": "Enable SSL", - "credentials": "Credentials", - "credentials-type": "Credentials type", - "credentials-type-required": "Credentials type is required.", - "username": "Username", - "username-required": "Username is required.", - "password": "Password", - "password-required": "Password is required.", - "azure-ca-cert": "CA certificate file", - "ca-cert": "CA certificate file", - "private-key": "Private key file", - "private-key-password": "Private key password", - "cert": "Certificate file", - "no-file": "No file selected.", - "drop-file": "Drop a file or click to select a file to upload.", - "drop-file-or": "Drag and drop a file or", - "check-connection": "Check connection", - "check-success": "Connection established.", - "topic-filters": "Topic filters", - "remove-topic-filter": "Remove topic filter", - "add-topic-filter": "Add topic filter", - "add-topic-filter-prompt": "Please add topic filter", - "topic": "Topic", - "mqtt-qos": "QoS", - "mqtt-qos-required": "QoS is required", - "mqtt-qos-range": "QoS values range is from 0 to 2", - "mqtt-qos-at-most-once": "At most once", - "mqtt-qos-at-least-once": "At least once", - "mqtt-qos-exactly-once": "Exactly once", - "downlink-topic-pattern": "Downlink topic pattern", - "downlink-topic-pattern-required": "Downlink topic pattern is required.", - "retained-message": "Retained", - "aws-access-key-id": "AWS access key Id", - "aws-secret-access-key": "AWS secret access key", - "aws-region": "Region", - "aws-iot-endpoint": "AWS IoT Endpoint", - "aws-iot-endpoint-required": "AWS IoT Endpoint is required.", - "aws-iot-credentials": "AWS IoT Credentials", - "aws-sqs-polling-period-in-seconds": "Polling period in seconds", - "aws-sqs-queue-url": "SQS Queue URL", - "aws-sqs-queue-url-required": "SQS Queue URL is required", - "aws-sqs-access-key-id-required": "Access Key Id is required", - "aws-sqs-secret-access-key-required": "Secret Access Key is required", - "application-credentials": "Application Credentials", - "api-key": "API Key", - "api-key-required": "API Key is required.", - "api-key-format": "Invalid API Key format.", - "auth-token": "Authentication Token", - "auth-token-required": "Authentication Token is required.", - "region": "Region", - "region-required": "Region is required.", - "application-id": "Application ID", - "application-id-required": "Application ID is required.", - "access-id": "Access Id", - "access-id-required": "Access Id is required.", - "access-key": "Access Key", - "access-key-required": "Access Key is required.", - "access-key-min-length": "Access Key is too short.", - "access-key-max-length": "Access Key is too long.", - "connection-parameters": "Connection parameters", - "service-bus-namespace-name": "Service Bus Namespace Name", - "service-bus-namespace-name-required": "Service Bus Namespace Name is required.", - "connection-string": "Connection string", - "consumer-group": "Consumer group", - "connection-string-required": "Connection string required!", - "event-hub-name": "Event Hub Name", - "event-hub-name-required": "Event Hub Name is required.", - "event-iot-hub-name-required": "Iot Hub Name is required for downlink", - "sas-key-name": "SAS Key Name", - "sas-key-name-required": "SAS Key Name is required.", - "sas-key": "SAS Key", - "sas-key-required": "SAS Key is required.", - "iot-hub-name": "IoT Hub Name (required for downlink)", - "hostname": "Hostname", - "hostname-required": "Hostname is required", - "integration-clazz": "Integration class", - "integration-clazz-required": "Integration class is required", - "integration-configuration": "Integration JSON configuration", - "metadata": "Metadata", - "type": "Integration type", - "select-integration-type": "Select integration type", - "type-required": "Integration type is required.", - "type-not-found": "Integration type not found", - "uplink-converter": "Uplink data converter", - "uplink-converter-required": "Uplink data converter is required.", - "downlink-converter": "Downlink data converter", - "type-http": "HTTP", - "type-http-description": "Transferring text or multimedia files protocol.", - "type-ocean-connect": "OceanConnect", - "type-ocean-connect-description": "Integration of devices with different capabilities with the IoT platform.", - "type-sigfox": "SigFox", - "type-sigfox-description": "Lightweight protocol to handle small data transmissions.", - "type-thingpark": "ThingPark", - "type-thingpark-description": "Message-oriented transport layer protocol.", - "type-loriot": "Loriot", - "type-loriot-description": "Distributed LoRaWAN infrastructure.", - "type-thingpark-enterprise": "ThingParkEnterprise", - "type-thingpark-enterprise-description": "Messaging platform for the LPWA network.", - "type-tmobile-iot-cdp": "iotcreators.com (T-Mobile – IoT CDP)", - "type-tmobile-iot-cdp-description": "Mobile IoT connectivity service.", - "type-mqtt": "MQTT", - "type-mqtt-description": "Machine to machine network protocol.", - "type-aws-iot": "AWS IoT", - "type-aws-iot-description": "Management, storage, and analytics service.", - "type-aws-sqs": "AWS SQS", - "type-aws-sqs-description": "Fully managed message queuing service.", - "type-aws-kinesis": "AWS Kinesis", - "type-aws-kinesis-description": "Service for real-time video and data streams.", - "type-ibm-watson-iot": "IBM Watson IoT", - "type-ibm-watson-iot-description": "Fully managed, cloud-hosted service.", - "type-ttn": "The Things Stack Community", - "type-ttn-description": "Open and decentralized LoRaWAN network.", - "type-tti": "The Things Stack Industries", - "type-tti-description": "Software to operate private LoRaWAN networks at scale.", - "type-chirpstack": "ChirpStack", - "type-chirpstack-description": "LoRaWAN network configuration server.", - "type-particle": "Particle", - "type-particle-description": "IoT enablement platform-as-a-service.", - "type-azure-event-hub": "Azure Event Hub", - "type-azure-event-hub-description": "Big data streaming platform and event ingestion service.", - "type-azure-iot-hub": "Azure IoT Hub", - "type-azure-iot-hub-description": "Cloud-hosted messaging service.", - "type-opc-ua": "OPC-UA", - "type-opc-ua-description": "Cross-platform for data exchange from sensors to cloud apps.", - "type-custom": "Custom", - "type-coap": "CoAP", - "type-coap-description": "Machine to machine network protocol for constrained devices.", - "type-udp": "UDP", - "type-udp-description": "Message-oriented transport layer protocol.", - "type-tcp": "TCP", - "type-tcp-description": "Connection-oriented protocol.", - "type-kafka": "Kafka", - "type-kafka-description": "Streaming analytics, data integration streaming platform.", - "type-rabbitmq": "RabbitMQ", - "type-rabbitmq-description": "Message broker that supports multiple messaging protocols.", - "type-pubsub": "Pub/Sub", - "type-pubsub-description": "Service for asynchronous messaging between apps.", - "type-apache-pulsar": "Apache Pulsar", - "type-apache-pulsar-description": "Distributed pub-sub messaging and streaming platform.", - "type-tuya": "Tuya", - "type-tuya-description": "Cloud-hosted messaging. device platform.", - "type-azure-service-bus": "Azure Service Bus", - "type-azure-service-bus-description": "Fully managed enterprise message broker with message queues and publish-subscribe topics.", - "opc-ua-application-name": "Application name", - "opc-ua-application-uri": "Application uri", - "opc-ua-scan-period-in-seconds": "Scan period in seconds", - "opc-ua-scan-period-in-seconds-required": "Scan period is required", - "opc-ua-timeout": "Timeout in milliseconds", - "opc-ua-timeout-required": "Timeout is required", - "opc-ua-security": "Security", - "opc-ua-security-required": "Security is required", - "opc-ua-identity": "Identity", - "opc-ua-identity-required": "Identity is required", - "opc-ua-keystore": "Keystore", - "add-opc-ua-keystore-prompt": "Please add keystore file", - "opc-ua-keystore-required": "Keystore is required", - "opc-ua-type": "Type", - "opc-ua-keystore-type": "Type", - "opc-ua-keystore-type-required": "Type is required", - "opc-ua-keystore-location": "Location *", - "opc-ua-keystore-password": "Password", - "opc-ua-keystore-password-required": "Password is required", - "opc-ua-keystore-alias": "Alias", - "opc-ua-keystore-alias-required": "Alias is required", - "opc-ua-keystore-key-password": "Key password", - "opc-ua-keystore-key-password-required": "Key password is required", - "opc-ua-mapping": "Mapping", - "add-opc-ua-mapping-prompt": "Please add mapping", - "opc-ua-mapping-type": "Mapping type", - "opc-ua-mapping-type-required": "Mapping type is required", - "opc-ua-device-node-pattern": "Device Node Pattern", - "opc-ua-device-node-pattern-required": "Device Node Pattern is required", - "opc-ua-namespace": "Namespace", - "opc-ua-add-map": "Add mapping element", - "kinesis-stream-name": "Stream name", - "kinesis-stream-name-required": "Stream name is required", - "kinesis-region": "Region", - "kinesis-region-required": "Region is required", - "kinesis-access-key-id": "Access Key Id", - "kinesis-access-key-id-required": "Access Key Id is required", - "kinesis-secret-access-key": "Secret Access Key", - "kinesis-secret-access-key-required": "Secret Access Key is required", - "kinesis-use-consumers-with-enhanced-fan-out": "Use Consumers with Enhanced Fan-Out", - "kinesis-use-credentials-from-instance-metadata": "Use credentials from the Amazon EC2 Instance Metadata Service", - "kinesis-application-name": "Application name (by default equals Stream name)", - "kinesis-initial-position-in-stream": "Initial position in stream", - "kinesis-initial-position-in-stream-required": "Initial position in stream required", - "kinesis-max-records": "Max records", - "kinesis-max-records-required": "Max records is required", - "kinesis-max-records-length-range": "Max records length should be in a range from 1 to 10000", - "kinesis-request-timeout": "Request timeout in seconds", - "kinesis-request-timeout-required": "Request timeout is required", - "other-properties": "Other properties", - "subscription-tags": "Subscription tags", - "remove-subscription-tag": "Remove subscription tag", - "add-subscription-tag": "Add subscription tag", - "add-subscription-tag-prompt": "Please add subscription tag", - "key": "Key", - "path": "Path", - "required": "Required", - "integration-key": "Integration key", - "copy-integration-key": "Copy integration key", - "integration-key-copied-message": "Integration key has been copied to clipboard", - "integration-secret": "Integration secret", - "copy-integration-secret": "Copy integration secret", - "integration-secret-copied-message": "Integration secret has been copied to clipboard", - "execute-remotely": "Execute remotely", - "remote": "Remote", - "handler-configuration": "Handler Configuration", - "handler-configuration-type": "Handler Type", - "so-broadcast": "Enable broadcast - integration will accepts broadcast address packets", - "so-keepalive-option": "Enable sending of keep-alive messages on connection-oriented sockets", - "so-reuse-addr": "Bind the process to a port", - "tcp-no-delay": "Forces a socket to send the data without buffering (disable Nagle's buffering algorithm)", - "fail-fast": "Thrown exception soon as the decoder notices the length of the frame will exceed max size", - "strip-delimiter": "Strip Delimiter", - "length-field-offset": "Length Field Offset", - "length-field-offset-required": "Length Field Offset is required.", - "length-field-offset-range": "Length Field Offset should be in a range from 0 to 8.", - "length-field-length": "Length Field Length", - "length-field-length-required": "Length Field Length is required.", - "length-field-length-range": "Length Field Length should be in a range from 0 to 8.", - "length-adjustment": "Length Adjustment (the compensation value to add to the value of the length field)", - "length-adjustment-required": "Length Adjustment is required.", - "length-adjustment-range": "Length Adjustment should be in a range from 0 to 8.", - "byte-order": "Byte Order of the length field", - "initial-bytes-to-strip": "Number of first bytes to strip out from the decoded frame", - "initial-bytes-to-strip-required": "Number of first bytes to strip out from the decoded frame is required.", - "initial-bytes-to-strip-range": "Number of first bytes to strip out from the decoded frame should be in a range from 0 to 8.", - "so-backlog-option": "Max number of pending connects on the socket", - "so-backlog-option-required": "The max number of pending connects on the socket is required.", - "so-backlog-option-range": "The max number of pending connects on the socket should be in a range from 1 to 65535.", - "so-rcv-buf": "Size of the buffer for inbound socket (in KB)", - "so-rcv-buf-required": "Size of the buffer for inbound socket (in KB) is required.", - "so-rcv-buf-range": "Size of the buffer for inbound socket (in KB) should be in a range from 1 to 65535.", - "so-snd-buf": "Size of the buffer for outbound socket (in KB)", - "so-snd-buf-required": "Size of the buffer for outbound socket (in KB) is required.", - "so-snd-buf-range": "Size of the buffer for outbound socket (in KB) should be in a range from 1 to 65535.", - "charset-name": "Charset Name", - "charset-name-required": "Charset Name is required.", - "message-separator": "Message Separator", - "message-separator-required": "Message Separator is required.", - "character-sequence": "Character Sequence", - "character-sequence-required": "Character Sequence is required.", - "max-frame-length": "Max Frame Length (in bytes)", - "max-frame-length-required": "Max Frame Length (in bytes) is required.", - "max-frame-length-range": "Max Frame Length (in bytes) should be in a range from 1 to 65535.", - "handler-type": "Handler Type", - "message-size": "Message Size", - "message-size-required": "Message Size is required.", - "service-url": "Service URL", - "service-url-required": "Service URL is required.", - "subscription-name": "Subscription name", - "subscription-name-required": "Subscription name is required.", - "max-num-messages": "Max number of messages", - "max-num-messages-required": "Max number of messages is required.", - "max-num-bytes": "Max number of bytes", - "max-num-bytes-required": "Max number of bytes required.", - "timeout-in-ms": "Timeout in milliseconds", - "timeout-in-ms-required": "Timeout in milliseconds is required.", - "user-id": "User ID", - "user-id-required": "User ID is required.", - "token": "Token", - "token-required": "Token is required.", - "project-id": "Project ID", - "project-id-required": "Project ID is required.", - "subscription-id": "Subscription ID", - "subscription-id-required": "Subscription ID is required.", - "service-account-key": "Service Account key file", - "service-account-key-required": "Service Account key file is required.", - "tcp": { - "system-line-separator": "System Line Separator", - "nul-delimiter": "Nul Delimiter", - "byte-order-little-endian": "Little Endian", - "byte-order-big-endian": "Big Endian" - }, - "cache-size": "Cache Size", - "cache-time-to-live": "Cache time to live in minutes", - "min-cache-size": "Cache size can't be lower 0", - "min-cache-time-to-live": "Cache time to live can't be lower 0", - "max-cache-time-to-live": "Invalid time of cache live, select between 0 and 525600", - "coap-security-mode": "Security mode", - "coap-security-mode-required": "CoAP security mode is required", - "coap-security-mode-no-secure": "NO SECURE", - "coap-security-mode-dtls": "DTLS", - "coap-security-mode-mixed": "MIXED", - "coap-endpoint": "CoAP endpoint URL", - "coap-endpoint-url-copied-message": "CoAP endpoint URL has been copied to clipboard", - "copy-coap-endpoint-url": "Copy CoAP endpoint URL", - "copy-coap-dtls-endpoint-url": "Copy CoAP DTLS endpoint URL", - "coap-dtls-base-url": "DTLS Base URL", - "coap-dtls-base-url-required": "DTLS Base URL is required", - "coap-dtls-endpoint": "CoAP DTLS endpoint URL", - "coap-dtls-endpoint-url-copied-message": "CoAP DTLS endpoint URL has been copied to clipboard", - "unassign-integration-title": "Are you sure you want to unassign the integration '{{integrationName}}'?", - "unassign-integration-from-edge-text": "After the confirmation the integration will be unassigned and won't be accessible by the edge.", - "unassign-integrations-from-edge-title": "Are you sure you want to unassign { count, plural, =1 {1 integration} other {# integrations} }?", - "unassign-integrations-from-edge-text": "After the confirmation all selected integrations will be unassigned and won't be accessible by the edge.", - "unassign-integrations": "Unassign integrations", - "edge-placeholder-hint": "You can use placeholder ${{ATTRIBUTE_KEY}} to substitute integration field with attribute value from specific Edge entity. For example, 'Edge A' has attribute 'baseUrl' that equals to 'http://localhost:9999'. You can set ${{baseUrl}} as one of the integration fields, and it is going to be replaced to 'http://localhost:9999' during the assignment of this integration to 'Edge A'. Additionally, if 'Edge A' attribute 'baseUrl' is going to be updated - integration with new updated value is going to be automatically provisioned to 'Edge A'.", - "status": { - "status": "Status", - "active": "Active", - "disabled": "Disabled", - "failed": "Failed", - "pending": "Pending" - }, - "daily-activity": "Daily activity", - "enable-debug-mode": "Enable debug mode", - "disable-debug-mode": "Disable debug mode", - "advanced-settings": "Advanced settings", - "basic-settings": "Basic settings", - "existing-converter": "Select existing", - "new-converter": "Create new", - "connection": "Connection", - "connected": "Connected", - "not-connected": "Not connected", - "environment": "Environment", - "environment-required": "Environment is required.", - "region-cn": "China", - "region-us": "United States", - "region-eu": "Europe", - "region-in": "India", - "topic-name": "Topic name", - "topic-name-required": "Topic name is required", - "sub-name": "Subscription name", - "sub-name-required": "Subscription name is required", - "downlink-connection-string": "Downlink connection string", - "downlink-connection-string-required": "Downlink connection string is required", - "downlink-topic-name": "Downlink topic name", - "downlink-topic-name-required": "Downlink topic name is required" - }, - "item": { - "selected": "Pasirinkta" - }, - "js-func": { - "no-return-error": "Funkcija privalo grąžinti reikšmę!", - "return-type-mismatch": "Funkcijos grąžinama reikšmė privalo būti '{{type}}' tipo!", - "tidy": "Tidy", - "mini": "Mini" + "single-switch": { + "behavior": "Elgsena", + "layout": "Išdėstymas", + "layout-right": "Dešinėje", + "layout-left": "Kairėje", + "layout-centered": "Centruota", + "auto-scale": "Automatinis mastelis", + "label": "Etiketė", + "icon": "Piktograma", + "switch-color": "Jungiklio spalva", + "on": "Įjungta", + "off": "Išjungta", + "disabled": "Išjungta būsena", + "tumbler-color": "Perjungiklio spalva", + "on-label": "Įjungta etiketė", + "off-label": "Išjungta etiketė", + "switch": "Jungiklis" }, - "key-val": { - "key": "Raktas", - "value": "Reikšmė", - "remove-entry": "Panaiknti įrašą", - "add-entry": "Pridėti įrašą", - "no-data": "Įrašų nėra" - }, - "layout": { - "layout": "Maketas", - "layouts": "Maketai", - "manage": "Valdyti maketus", - "settings": "Maketų nustatymai", - "color": "Spalva", - "main": "Pagrindinis", - "right": "Į dešinę", - "left": "Į kairę", - "select": "Pasirinkti maketą", - "percentage-width": "Procentinis plotis (%)", - "fixed-width": "Fiksuotas plotis (px)", - "left-width": "Kairysis stulpelis (%)", - "right-width": "Dešinysis stulpelis (%)", - "pick-fixed-side": "Fiksuota pusė: ", - "layout-fixed-width": "Fiksuotas plotis (px)", - "value-min-error": "Reikšmė turi būti dedesnė nei {{min}}{{unit}}", - "value-max-error": "Reikšmė turi būti mažesnė nei {{max}}{{unit}}", - "layout-fixed-width-required": "Fiksuotas plotis būtinas", - "right-width-percentage-required": "Dešinės pusės procentas būtinas", - "left-width-percentage-required": "kairės pusės procentas būtinas", - "divider": "Daliklis", - "right-side": "Dešinės pusės maketas", - "left-side": "Kairės pusės maketas" - }, - "legend": { - "direction": "Elementų išdėstymo kryptis", - "position": "Legendos pozicija", - "show-values": "Rodyti reikšmes", - "min-option": "Min", - "max-option": "Max", - "average-option": "Vidurkis", - "total-option": "Viso", - "latest-option": "Naujausi", - "sort-legend": "Legendoje rodyti duomenų raktus", - "show-max": "Rodyti didžiausią reišmę", - "show-min": "Rodyti mažiausią reikšmę", - "show-avg": "Rodyti vidutinę reikšmę", - "show-total": "Rodyti suminę rekšmę", - "show-latest": "Rodyti naujausią reikšmę", - "settings": "Legendos nustatymai", - "min": "Min", - "max": "Max", - "avg": "Vidurkis", - "total": "Viso", - "latest": "Naujausia", - "comparison-time-ago": { - "previousInterval": "(previous interval)", - "customInterval": "(custom interval)", - "days": "(day ago)", - "weeks": "(week ago)", - "months": "(month ago)", - "years": "(year ago)" - } + "slider": { + "behavior": "Elgsena", + "initial-value": "Pradinė reikšmė", + "initial-value-hint": "Veiksmas, skirtas gauti pradinę slankiklio reikšmę.", + "on-value-change": "Keičiantis reikšmei", + "on-value-change-hint": "Veiksmas, paleidžiamas, kai pasikeičia slankiklio reikšmė.", + "layout": "Išdėstymas", + "layout-default": "Numatytasis", + "layout-extended": "Išplėstinis", + "layout-simplified": "Supaprastintas", + "auto-scale": "Automatinis mastelis", + "icon": "Piktograma", + "value": "Reikšmė", + "range": "Intervalas", + "min": "min", + "max": "maks", + "range-ticks": "Intervalo žymės", + "tick-marks": "Padalos", + "colors": "Spalvos", + "main": "Pagrindinė", + "background": "Fonas", + "left-icon": "Kairioji piktograma", + "right-icon": "Dešinioji piktograma", + "slider": "Slankiklis" }, - "login": { - "login": "Prisijungti", - "request-password-reset": "Prašyti atstatyti slaptažodį", - "reset-password": "Atstatyti slaptažodį", - "create-password": "Nustatyti slaptažodį", - "two-factor-authentication": "Dviejų veiksnių autentifikavimas", - "passwords-mismatch-error": "Įvesti slaptažodžiai turi sutapti!", - "password-again": "Slaptažodį įveskite dar kartą", - "sign-in": "Prisijunkite", - "username": "Vartoto vardas (el. paštas)", - "remember-me": "Prisiminti mane", - "forgot-password": "Pamiršote slaptažodį?", - "password-reset": "Slaptažodis atstatytas", - "expired-password-reset-message": "Jūsų slaptažodio galiojimas baigėsi! Nustatykite naują slaptažodį.", - "new-password": "Naujas slaptažodis", - "new-password-again": "Pakartokite naują slaptažodį", - "password-link-sent-message": "Atstatymo nuoroda išsiųsta", - "email": "El. paštas", - "no-account": "Neturi paskyros?", - "create-account": "Sukurti paskyrą", - "login-with": "Prisijungti kaip {{name}}", - "or": "arba", - "error": "Login error", - "verify-your-identity": "Verify your identity", - "select-way-to-verify": "Select a way to verify", - "resend-code": "Resend code", - "resend-code-wait": "Resend code in { time, plural, =1 {1 second} other {# seconds} }", - "try-another-way": "Try another way", - "totp-auth-description": "Please enter the security code from your authenticator app.", - "totp-auth-placeholder": "Code", - "sms-auth-description": "A security code has been sent to your phone at {{contact}}.", - "sms-auth-placeholder": "SMS code", - "email-auth-description": "A security code has been sent to your email address at {{contact}}.", - "email-auth-placeholder": "Email code", - "backup-code-auth-description": "Please enter one of your backup codes.", - "backup-code-auth-placeholder": "Backup code" - }, - "signup": { - "firstname": "Vardas", - "lastname": "Pavardė", - "email": "El. paštas", - "signup": "Registracija", - "create-password": "nustatyti slaptažodį", - "repeat-password": "Pakartokite slaptažodį", - "have-account": "Jau turite paskyrą?", - "signin": "Prisijungti", - "no-captcha-message": "Turite patvirtinti, jog nesate robotas", - "password-length-message": "Jūsų slaptažodis turi būti ne nei 6 simboliai", - "email-verification": "El. pašto adreso patvirtinimas", - "email-verification-message": "El. laiškas su patvirtinimo informacija išsiųstas nurodytu el. pašto adresu.
Sekite laiške pateiktas intrukcijas ir atlikite prisijungimui reikalingus veiksmus.
Pastaba: Jei nematote el. laiško, patikrinkite 'Šlamšto' katalogą arba bandykite dar kartą siųsti laišką paspausdami 'Siųsti dar kartą' mygtuką", - "account-activation-title": "Paskyros aktyvavimas", - "account-activated": "Paskyra aktyvuota!", - "account-activated-text": "Sveikiname!
Jūsų paskyra aktyvuota.", - "resend": "Siųsti dar kartą", - "inactive-user-exists-title": "Neaktyvuotas vartotojas sistemoje jau yra", - "inactive-user-exists-text": "Vartotojas su tokiu el. pašto adresu jau užregistruotas, tačiau šis adresas nepatvirtintas.
Paspauskite 'Siųsti dar kartą' mygtuką jei norite išsiųsti patvirtinimo laišką.", - "activating-account": "Paskyra aktyvuojama...", - "activating-account-text": "Jūsų paskyra aktyvuojama. Palaukite...", - "accept-privacy-policy": "Sutikti su privatumo politika", - "accept": "Sutikti", - "privacy-policy": "Privatumo politika", - "accept-privacy-policy-message": "You must accept our Privacy Policy", - "recaptcha-title": "reCAPTCHA", - "terms-of-use": "Terms of Use", - "accept-terms-of-use-message": "You must accept our Terms Of Use" + "value-card": { + "layout": "Išdėstymas", + "layout-square": "Kvadratinis", + "layout-vertical": "Vertikalus", + "layout-centered": "Centruotas", + "layout-simplified": "Supaprastintas", + "layout-horizontal": "Horizontalus", + "layout-horizontal-reversed": "Apverstas horizontalus", + "label": "Etiketė", + "icon": "Piktograma", + "value": "Reikšmė", + "date": "Data", + "value-card-style": "Reikšmės kortelės stilius", + "auto-scale": "Automatinis mastelis" + }, + "label-card": { + "auto-scale": "Automatinis mastelis", + "label": "Etiketė", + "icon": "Piktograma", + "label-card-style": "Etiketės kortelės stilius" + }, + "label-value-card": { + "value": "Reikšmė", + "label-value-card-style": "Etiketės ir reikšmės kortelės stilius" + }, + "liquid-level-card": { + "layout-simple": "Paprastas", + "layout-percentage": "Procentinis", + "layout-absolute": "Absoliutus", + "layout": "Išdėstymas", + "background-overlay": "Reikšmės fono perdanga", + "total-volume": "Bendras tūris", + "total-volume-units": "Bendro tūrio vienetai", + "tank": "Talpa", + "shape": "Forma", + "datasource-units": "Šaltinio vienetai", + "widget-units": "Valdiklio vienetai", + "decimals": "Dešimtainės", + "liquid": "Skystis", + "liquid-color": "Skysčio spalva", + "value": "Reikšmė", + "value-font": "Reikšmės šriftas", + "level": "Lygis", + "last-update": "Paskutinis atnaujinimas", + "shape-by-attribute": "Nustatyti talpos formą pagal atributo pavadinimą", + "tooltip-background": "Fono spalva", + "background-blur": "Fono suliejimas", + "tank-color": "Talpos spalva", + "static": "Statinis", + "see-examples": "Peržiūrėti pavyzdžius", + "attribute": "Atributas", + "shape-type": "Tipas", + "v-oval": "Vertikali ovalo forma", + "v-cylinder": "Vertikalus cilindras", + "v-capsule": "Vertikali kapsulė", + "rectangle": "Stačiakampis", + "h-oval": "Horizontalus ovalas", + "h-ellipse": "Horizontali elipsė", + "h-dish-ends": "Horizontalūs išgaubti galai", + "h-cylinder": "Horizontalus cilindras", + "h-capsule": "Horizontali kapsulė", + "h-elliptical_2_1": "Horizontalus 2:1 elipsinis", + "icon": "Kortelės piktograma", + "title": "Kortelės pavadinimas", + "units": "Vienetai", + "color-and-font": "Spalva ir šriftas", + "shape-attribute-name": "Atributo pavadinimas", + "total-volume-required": "Bendras tūris yra privalomas.", + "attribute-name-required": "Atributo pavadinimas yra privalomas.", + "attribute-key-not-set": "Atributo '{{attributeName}}' raktas nenustatytas", + "attribute-key-invalid": "Atributo '{{attributeName}}' raktas neteisingas" + }, + "aggregated-value-card": { + "subtitle": "Paantraštė", + "chart": "Diagrama", + "values": "Reikšmės", + "value-appearance": "Reikšmės išvaizda", + "position": "Padėtis", + "position-center": "Centre", + "position-right-top": "Dešinėje viršuje", + "position-right-bottom": "Dešinėje apačioje", + "position-left-top": "Kairėje viršuje", + "position-left-bottom": "Kairėje apačioje", + "font": "Šriftas", + "color": "Spalva", + "arrow": "Rodyklė", + "display-up-down-arrow": "Rodyti aukštyn/žemyn rodyklę", + "add-value": "Pridėti reikšmę", + "remove-value": "Pašalinti reikšmę", + "no-values": "Reikšmės nesukonfigūruotos", + "aggregation": "Agregavimas", + "aggregated-value-card-style": "Agreguotų reikšmių kortelės stilius", + "auto-scale": "Automatinis mastelis" + }, + "value-chart-card": { + "layout": "Išdėstymas", + "layout-left": "Kairėje", + "layout-right": "Dešinėje", + "auto-scale": "Automatinis mastelis", + "icon": "Piktograma", + "value": "Reikšmė", + "chart": "Diagrama", + "value-chart-card-style": "Reikšmės ir diagramos kortelės stilius" + }, + "progress-bar": { + "layout": "Išdėstymas", + "layout-default": "Numatytasis", + "layout-simplified": "Supaprastintas", + "auto-scale": "Automatinis mastelis", + "icon": "Piktograma", + "value": "Reikšmė", + "range": "Intervalas", + "min": "min", + "max": "maks", + "range-ticks": "Intervalo žymės", + "bar": "Juosta", + "bar-color": "Juostos spalva", + "bar-background": "Juostos fonas", + "progress-bar-card-style": "Progreso juostos kortelės stilius" }, "notification": { - "action-button": "Action button", - "action-type": "Action type", - "active": "Active", - "add-notification-recipients-group": "Add notification recipients group", - "add-notification-template": "Add notification template", - "add-recipient": "Add recipient", - "add-recipients": "Add recipients", - "add-rule": "Add rule", - "add-stage": "Add stage", - "add-template": "Add template", - "after": "After", - "alarm-assignment-trigger-settings": "Alarm assignment trigger settings", - "alarm-comment-trigger-settings": "Alarm comment trigger settings", - "alarm-trigger-settings": "Alarm trigger settings", - "all": "All", - "api-feature-hint": "If the field is empty, the trigger will be applied to all api features", - "api-usage-trigger-settings": "API usage trigger settings", - "new-platform-version-trigger-settings": "New platform version trigger settings", - "rate-limits-trigger-settings": "Exceeded rate limits trigger settings", - "at-least-one-should-be-selected": "At least one should be selected", - "basic-settings": "Basic settings", - "button-text": "Button text", - "button-text-required": "Button text is required", - "button-text-max-length": "Button text should be less than or equal to {{ length }} characters", - "compose": "Compose", - "conversation": "Conversation", - "conversation-required": "Conversation is required", - "copy-notification-template": "Copy notification template", - "copy-rule": "Copy rule", - "copy-template": "Copy template", - "create-new": "Create new", - "created": "Created", - "delete-notification-text": "Be careful, after the confirmation the notification will become unrecoverable.", - "delete-notification-title": "Are you sure you want to delete the notification?", - "delete-notifications-text": "Be careful, after the confirmation notifications will become unrecoverable.", - "delete-notifications-title": "Are you sure you want to delete { count, plural, =1 {1 notification} other {# notifications} }?", - "delete-recipient-text": "Be careful, after the confirmation the recipient will become unrecoverable.", - "delete-recipient-title": "Are you sure you want to delete recipient '{{recipientName}}'?", - "delete-recipients-text": "Be careful, after the confirmation recipients will become unrecoverable.", - "delete-recipients-title": "Are you sure you want to delete { count, plural, =1 {1 recipient} other {# recipients} }?", - "delete-request-text": "Be careful, after the confirmation request will become unrecoverable.", - "delete-request-title": "Are you sure you want to delete request?", - "delete-requests-text": "Be careful, after the confirmation requests will become unrecoverable.", - "delete-requests-title": "Are you sure you want to delete { count, plural, =1 {1 request} other {# requests} }?", - "delete-rule-text": "Be careful, after the confirmation rule will become unrecoverable.", - "delete-rule-title": "Are you sure you want to delete rule '{{ruleName}}'?", - "delete-rules-text": "Be careful, after the confirmation rules will become unrecoverable.", - "delete-rules-title": "Are you sure you want to delete { count, plural, =1 {1 rule} other {# rules} }?", - "delete-template-text": "Be careful, after the confirmation template will become unrecoverable.", - "delete-template-title": "Are you sure you want to delete template '{{templateName}}'?", - "delete-templates-text": "Be careful, after the confirmation templates will become unrecoverable.", - "delete-templates-title": "Are you sure you want to delete { count, plural, =1 {1 template} other {# templates} }?", - "deleted": "Deleted", - "delivery-method": { - "delivery-method": "Delivery method", - "email": "Email", - "email-preview": "Email notification preview", - "slack": "Slack", - "slack-preview": "Slack notification preview", - "microsoft-teams": "Microsoft Teams", - "microsoft-teams-preview": "Microsoft Teams notification preview", - "sms": "SMS", - "sms-preview": "SMS notification preview", - "web": "Web", - "web-preview": "Web notification preview" - }, - "delivery-method-not-configure-click": "Delivery method is not configured. Click to setup.", - "delivery-method-not-configure-contact": "Delivery method is not configured. Contact your system administrator.", - "delivery-methods": "Delivery methods", - "description": "Description", - "device-activity-trigger-settings": "Device active trigger settings", - "device-list-rule-hint": "If the field is empty, the trigger will be applied to all devices", - "device-profiles-list-rule-hint": "If the field is empty, the trigger will be applied to all device profiles", - "disabled": "Disabled", - "edit-notification-recipients-group": "Edit notification recipients group", - "edit-notification-template": "Edit notification template", - "edit-rule": "Edit rule", - "edit-template": "Edit template", - "enabled": "Enabled", - "entities-limit-trigger-settings": "Entities limit trigger settings", - "entity-action-trigger-settings": "Entity action trigger settings", - "entity-type": "Entity type", - "escalation-chain": "Escalation chain", - "failed-send": "Sending failures", - "fails": "{ count, plural, =1 {1 fail} other {# fails} }", - "filter": "Filter", - "first-recipient": "First recipient", - "inactive": "Inactive", - "inbox": "Inbox", - "notification-inbox": "Notifications / Inbox", - "input-field-support-templatization": "Input field support templatization.", - "input-fields-support-templatization": "Input fields support templatization.", - "integration-action-trigger-settings": "Integration events trigger settings", - "integration-list-rule-hint": "If the field is empty, the trigger will be applied to all integrations", - "link": "Link", - "link-required": "Link is required", - "link-type": { - "dashboard": "Open dashboard", - "link": "Open URL link" - }, - "loading-notifications": "Loading notifications...", - "management": "Notification management", - "mark-all-as-read": "Mark all as read", - "mark-as-read": "Mark as read", - "message": "Message", - "message-required": "Message is required", - "message-max-length": "Message should be less than or equal to {{ length }} characters", - "name": "Name", - "name-required": "Name is required", - "new-notification": "New notification", - "no-inbox-notification": "No notification found", - "no-notification-request": "No notification request", - "no-notification-templates": "No notification templates found", - "no-notifications-yet": "No notifications yet", - "no-recipients-notification": "No recipients notification", - "no-rule": "No rule configured", - "no-rules-notification": "No rules notification", - "no-severity-found": "No severity found", - "no-severity-matching": "'{{severity}}' not found.", - "no-template-matching": "No resource matching '{{template}}' were found.", - "not-found-slack-recipient": "Slack recipient not found", - "notification": "Notification", - "notification-center": "Notification center", - "notify": "notify", - "notify-again": "Notify again", - "notify-alarm-action": { - "acknowledged": "Alarm acknowledged", - "assigned": "Alarm assigned", - "cleared": "Alarm cleared", - "created": "Alarm created", - "severity-changed": "Alarm severity changed", - "unassigned": "Alarm unassigned" - }, - "notify-on": "Notify on", - "notify-on-comment-update": "Notify on comment update", - "notify-on-required": "Notify on is required", - "notify-on-unassign": "Notify on unassign", - "notify-only-integrations-errors": "Only notify on error", - "notify-only-user-comments": "Notify only user comments", - "only-rule-chain-lifecycle-failures": "Only rule chain lifecycle failures", - "only-rule-node-lifecycle-failures": "Only rule node lifecycle failures", - "platform-users": "Platform users", - "rate-limits": "Rate limits", - "rate-limits-hint": "If the field is empty, the trigger will be applied to all rate limits", - "recipient": "Recipient", - "recipient-group": "Recipient group", - "recipient-type": { - "affected-tenant-administrators": "Affected tenant administrators", - "affected-user": "Affected user", - "affected-user-hint": "Affected user hint", - "all-users": "All users", - "customer-users": "Customer users", - "system-administrators": "System administrators", - "tenant-administrators": "Tenant administrators", - "user-filters": "User filter", - "user-group-list": "User group list", - "user-list": "User list", - "user-role": "User role", - "users-entity-owner": "Users of the entity owner", - "users-entity-owner-hint": "Users of the entity owner hint" - }, - "recipients": "Recipients", - "notification-recipients": "Notifications / Recipients", - "recipients-count": "{ count, plural, =1 {1 recipient} other {# recipients} }", - "recipients-required": "Recipients are required", - "refresh-allow-delivery-method": "Refresh allow delivery method", - "request-search": "Request search", - "request-status": { - "processing": "Processing", - "scheduled": "Scheduled", - "sent": "Sent" - }, - "review": "Review", - "rule": "Rule", - "rule-chain-list-rule-hint": "If the field is empty, the trigger will be applied to all rule chains", - "rule-engine-events-trigger-settings": "Rule engine events trigger settings", - "rule-engine-filter": "Rule engine filter", - "rule-name": "Rule name", - "rule-name-required": "Name is required", - "rule-disable": "Disable notification rule", - "rule-enable": "Enable notification rule", - "rule-node-filter": "Rule node filter", - "rules": "Rules", - "notification-rules": "Notifications / Rules", - "scheduler-later": "Schedule for later", - "search-notification": "Search notifications", - "search-recipients": "Search recipients", - "search-rules": "Search rules", - "search-templates": "Search templates", - "see-documentation": "See documentation", - "selected-notifications": "{ count, plural, =1 {1 notification} other {# notifications} } selected", - "selected-recipients": "{ count, plural, =1 {1 recipient} other {# recipients} } selected", - "selected-requests": "{ count, plural, =1 {1 request} other {# requests} } selected", - "selected-rules": "{ count, plural, =1 {1 rule} other {# rules} } selected", - "selected-template": "{ count, plural, =1 {1 template} other {# templates} } selected", - "send-notification": "Send notification", - "sent": "Sent", - "notification-sent": "Notifications / Sent", - "set-entity-from-notification": "Set entity from notification to dashboard state", - "slack-chanel-type": "Slack channel type", - "slack-chanel-types": { - "direct": "Direct message", - "private-channel": "Private channel", - "public-channel": "Public channel" - }, - "start-from-scratch": "Start from scratch", - "status": "Status", - "stop-escalation-alarm-status-become": "Stop the escalation on the alarm status become:", - "subject": "Subject", - "subject-required": "Subject is required", - "template": "Template", - "template-name": "Template name", - "template-required": "Template is required", - "template-type": { - "alarm": "Alarm", - "alarm-assignment": "Alarm assignment", - "alarm-comment": "Alarm comment", - "api-usage-limit": "API usage limit", - "device-activity": "Device activity", - "entities-limit": "Entities limit", - "entity-action": "Entity action", - "general": "General", - "integration-lifecycle-event": "Integration lifecycle event", - "rule-engine-lifecycle-event": "Rule engine lifecycle event", - "rule-node": "Rule node", - "new-platform-version": "New platform version", - "rate-limits": "Exceeded rate limits" - }, - "templates": "Templates", - "notification-templates": "Notifications / Templates", - "tenant-profiles-list-rule-hint": "If the field is empty, the trigger will be applied to all tenant profiles", - "tenants-list-rule-hint": "If the field is empty, the trigger will be applied to all tenants", - "threshold": "Threshold", - "theme-color": "Theme color", - "time": "Time", - "track-rule-node-events": "Track rule node events", - "trigger": { - "alarm": "Alarm", - "alarm-assignment": "Alarm assignment", - "alarm-comment": "Alarm comment", - "api-usage-limit": "API usage limit", - "device-activity": "Device activity", - "entities-limit": "Entities limit", - "entity-action": "Entity action", - "integration-lifecycle-event": "Integration lifecycle event", - "rule-engine-lifecycle-event": "Rule engine lifecycle event", - "new-platform-version": "New platform version", - "rate-limits": "Exceeded rate limits", - "trigger": "Trigger", - "trigger-required": "Trigger is required" - }, - "type": "Type", - "unread": "Unread", - "updated": "Updated", - "use-template": "Use template", - "view-all": "View all", - "view-notification-recipients-group": "View notification recipients group", - "view-notification-template": "View notification template", - "view-rule": "View rule", - "warning": "Warning", - "webhook-url": "Webhook URL", - "webhook-url-required": "Webhook URL is required", - "channel-name": "Channel name", - "channel-name-required": "Channel name is required", - "settings": { - "notification-settings": "Notification settings", - "reset-all": "Reset all settings", - "reset-all-title": "Are you sure you want to reset form?", - "reset-all-text": "After the confirmation, the settings form will reset to the default value and save.", - "type": "Type", - "enable-all": "Enable all", - "disable-all": "Disable all", - "delivery-not-configured": "Delivery method is not configured" - } + "max-notification-display": "Maksimalus rodomų pranešimų skaičius", + "counter": "Skaitiklis", + "counter-hint": "Skaitiklis bus rodomas, jei įjungtas „Valdiklio pavadinimas“", + "icon": "Piktograma", + "counter-value": "Reikšmė", + "counter-color": "Spalva", + "notification-button": "Pranešimų mygtukai", + "button-view-all": "Peržiūrėti visus", + "button-filter": "Filtruoti", + "type-filter": "Tipų filtras", + "button-mark-read": "Pažymėti visus kaip skaitytus", + "notification-types": "Pranešimų tipai", + "notification-type": "Pranešimo tipas", + "search-type": "Paieškos tipas", + "any-type": "Bet koks tipas" }, - "ota-update": { - "add": "Add package", - "assign-firmware": "Assigned firmware", - "assign-firmware-required": "Assigned firmware is required", - "assign-software": "Assigned software", - "assign-software-required": "Assigned software is required", - "auto-generate-checksum": "Auto-generate checksum", - "cant-applied-group-all": "Can't be applied for group All", - "checksum": "Checksum", - "checksum-hint": "If checksum is empty, it will be generated automatically", - "checksum-algorithm": "Checksum algorithm", - "checksum-copied-message": "Package checksum has been copied to clipboard", - "change-firmware": "Change of the firmware may cause update of { count, plural, =1 {1 device} other {# devices} }.", - "change-software": "Change of the software may cause update of { count, plural, =1 {1 device} other {# devices} }.", - "chose-compatible-device-profile": "The uploaded package will be available only for devices with the chosen profile.", - "chose-firmware-distributed-device": "Choose firmware that will be distributed to the devices", - "chose-software-distributed-device": "Choose software that will be distributed to the devices", - "content-type": "Content type", - "copy-checksum": "Copy checksum", - "copy-direct-url": "Copy direct URL", - "copyId": "Copy package Id", - "copied": "Copied!", - "delete": "Delete package", - "delete-ota-update-text": "Be careful, after the confirmation the OTA update will become unrecoverable.", - "delete-ota-update-title": "Are you sure you want to delete the OTA update '{{title}}'?", - "delete-ota-updates-text": "Be careful, after the confirmation all selected OTA updates will be removed.", - "delete-ota-updates-title": "Are you sure you want to delete { count, plural, =1 {1 OTA update} other {# OTA updates} }?", - "description": "Description", - "direct-url": "Direct URL", - "direct-url-copied-message": "Package direct URL has been copied to clipboard", - "direct-url-required": "Direct URL is required", - "download": "Download package", - "drop-file": "Drop a package file or click to select a file to upload.", - "drop-package-file-or": "Drag and drop a package file or", - "file-name": "File name", - "file-size": "File size", - "file-size-bytes": "File size in bytes", - "idCopiedMessage": "Package Id has been copied to clipboard", - "no-firmware-matching": "No compatible Firmware OTA Update packages matching '{{entity}}' were found.", - "no-firmware-text": "No compatible Firmware OTA Update packages provisioned.", - "no-packages-text": "No packages found", - "no-software-matching": "No compatible Software OTA Update packages matching '{{entity}}' were found.", - "no-software-text": "No compatible Software OTA Update packages provisioned.", - "ota-update": "OTA update", - "ota-update-details": "OTA update details", - "ota-updates": "OTA updates", - "package-type": "Package type", - "packages-repository": "Packages repository", - "search": "Search packages", - "selected-package": "{ count, plural, =1 {1 package} other {# packages} } selected", - "title": "Title", - "title-required": "Title is required.", - "title-max-length": "Title should be less than 256", - "types": { - "firmware": "Firmware", - "software": "Software" - }, - "upload-binary-file": "Upload binary file", - "use-external-url": "Use external URL", - "version": "Version", - "version-required": "Version is required.", - "version-tag": "Version Tag", - "version-tag-hint": "Custom tag should match the package version reported by your device.", - "version-max-length": "Version should be less than 256", - "warning-after-save-no-edit": "Once the package is uploaded, you will not be able to modify title, version, device profile and package type." - }, - "position": { - "top": "Viršus", - "bottom": "Apačia", - "left": "Kairioji pusė", - "right": "Dešinioji pusė" - }, - "profile": { - "profile": "Profilis", - "last-login-time": "Paskutinio prisijungimo laikas", - "change-password": "Pakeisti slaptažodį", - "current-password": "Dabartinis slaptažodis", - "copy-jwt-token": "Copy JWT token", - "jwt-token": "JWT token", - "token-valid-till": "Token is valid till", - "tokenCopiedSuccessMessage": "JWT token has been copied to clipboard", - "tokenCopiedWarnMessage": "JWT token is expired! Please, refresh the page." - }, - "profiles": { - "profiles": "Profiles" - }, - "security": { - "security": "Security", - "general-settings": "General security settings", - "access-token": "Access token", - "access-token-required": "Access token is required", - "clientId": "Client ID", - "clientId-required": "Client ID is required", - "username": "Username", - "username-required": "Username is required", - "ca-cert": "CA certificate", - "2fa": { - "2fa": "Two-factor authentication", - "2fa-description": "Two-factor authentication protects your account from unauthorized access. All you have to do is enter a security code when you log in.", - "authenticate-with": "You can authenticate with:", - "disable-2fa-provider-text": "Disabling {{name}} will make your account less secure", - "disable-2fa-provider-title": "Are you sure you want to disable {{name}}?", - "get-new-code": "Get new code", - "main-2fa-method": "Use as main two-factor authentication method", - "dialog": { - "activation-step-description-email": "The next time you login in, you will be prompted to enter the security code that will be sent to your email address.", - "activation-step-description-sms": "The next time you login in, you will be prompted to enter the security code that will be sent to the phone number.", - "activation-step-description-totp": "The next time you login in, you will need to provide a two-factor authentication code.", - "activation-step-label": "Activation", - "backup-code-description": "Print out the codes so you have them handy when you need to use them to log in to your account. You can use each backup code once.", - "backup-code-warn": "Once you leave this page, these codes cannot be shown again. Store them safely using the options below.", - "download-txt": "Download (txt)", - "email-step-description": "Enter an email to use as your authenticator.", - "email-step-label": "Email", - "enable-email-title": "Enable email authenticator", - "enable-sms-title": "Enable SMS authenticator", - "enable-totp-title": "Enable authenticator app", - "enter-verification-code": "Enter the 6-digit code here", - "get-backup-code-title": "Get backup code", - "next": "Next", - "scan-qr-code": "Scan this QR code with your verification app", - "send-code": "Send code", - "sms-step-description": "Enter a phone number to use as your authenticator.", - "sms-step-label": "Phone Number", - "success": "Success!", - "totp-step-description-install": "You can install apps like Google Authenticator, Authy, or Duo.", - "totp-step-description-open": "Open the authenticator app on your mobile phone.", - "totp-step-label": "Get app", - "verification-code": "6-digit code", - "verification-code-invalid": "Invalid verification code format", - "verification-code-incorrect": "Verification code is incorrect", - "verification-code-many-request": "Too many requests check verification code", - "verification-step-description": "Enter a 6-digit code we just sent to {{address}}", - "verification-step-label": "Verification" - }, - "provider": { - "email": "Email", - "email-description": "Use a security code sent to your email address to authenticate.", - "email-hint": "Authentication codes are sent via email to {{ info }}", - "sms": "SMS", - "sms-description": "Use your phone to authenticate. We'll send you a security code via SMS message when you log in.", - "sms-hint": "Authentication codes are sent by text message to {{ info }}", - "totp": "Authenticator app", - "totp-description": "Use apps like Google Authenticator, Authy, or Duo on your phone to authenticate. It will generate a security code for logging in.", - "totp-hint": "Authenticator app is set up for your account", - "backup_code": "Backup code", - "backup-code-description": "These printable one-time passcodes allow you to sign in when away from your phone, like when you’re traveling.", - "backup-code-hint": "{{ info }} single-use codes are active at this time" - } - }, - "password-requirement": { - "at-least": "At least:", - "character": "{ count, plural, =1 {1 character} other {# characters} }", - "digit": "{ count, plural, =1 {1 digit} other {# digits} }", - "incorrect-password-try-again": "Incorrect password. Try again", - "lowercase-letter": "{ count, plural, =1 {1 lowercase letter} other {# lowercase letters} }", - "new-passwords-not-match": "New password didn't match", - "password-should-not-contain-spaces": "Your password should not contain spaces", - "password-not-meet-requirements": "Password didn't meet requirements", - "password-requirements": "Password requirements", - "password-should-difference": "New password should be different from current", - "special-character": "{ count, plural, =1 {1 special character} other {# special characters} }", - "uppercase-letter": "{ count, plural, =1 {1 uppercase letter} other {# uppercase letters} }" - } + "alarm-count": { + "alarm-count-card-style": "Signalizacijų skaičiaus kortelės stilius" }, - "relation": { - "relations": "Ryšiai", - "direction": "Direction", - "clear-relation-type": "Clear relation type", - "search-direction": { - "FROM": "Iš", - "TO": "Į" - }, - "direction-type": { - "FROM": "iš", - "TO": "į" - }, - "from-relations": "Išeinantys ryšiai", - "to-relations": "įeinantys ryšiai", - "selected-relations": "Pasirinkta { count, plural, =1 {1 ryšys} other {# ryšiai} } selected", - "type": "Tipas", - "to-entity-type": "Į subjekto tipą", - "to-entity-name": "Į subjektą", - "from-entity-type": "iš subjektų tipo", - "from-entity-name": "Iš subjekto", - "to-entity": "į subjektą", - "from-entity": "Iš subjekto", - "delete": "panaikinti ryšį", - "relation-type": "Ryšio tipas", - "relation-type-required": "Ryšio tipas būtinas.", - "relation-type-max-length": "Ryšio tipas negali viršyti 256 simbolių", - "any-relation-type": "Bet kuris tipas", - "add": "pridėti ryšį", - "edit": "Redaguoti ryšį", - "view": "peržiūrėti ryšį", - "delete-to-relation-title": "Ar tikrai norite panaikinti ryšį su '{{entityName}}' subjektu?", - "delete-to-relation-text": "Būkite dėmesingi, po patvirtinimo '{{entityName}}' subjektas neteks ryšio su dabartiniu subjektu.", - "delete-to-relations-title": "Ar tikrai norite panaikinti { count, plural, =1 {1 ryšį} other {# ryšius} }?", - "delete-to-relations-text": "Būkite dėmesingi, po patvirtinimo visi pasirinkti ryšiai bus panaikinti ir atitinkami subjektai neteks ryšių su dabartiniu subjektu.", - "delete-from-relation-title": "Ar tikrai norite panaikinti ryšį iš '{{entityName}}' subjekto?", - "delete-from-relation-text": "Būkite dėmesingi, po patvirtinimo, dabartinis subjektas neteks ryšio su '{{entityName}}' subjektu.", - "delete-from-relations-title": "Ar tikrai norite panaikinti { count, plural, =1 {1 ryšį} other {# ryšius} }?", - "delete-from-relations-text": "Būkite dėmesingi, po patvirtinimo, visi pasirinkti ryšiai bus panaikinti ir dabartinis subjektas neteks ryšių su atitinkamais subjektais.", - "remove-relation-filter": "Panaikinti ryšių filtrą", - "remove-filter": "Panakinti filtrą", - "add-relation-filter": "Pridėti ryšių filtrą", - "any-relation": "Bet kuris ryšys", - "relation-filters": "Ryšių filtrai", - "additional-info": "Papildoma informacija (JSON)", - "invalid-additional-info": "Papildomos JSON informacijos išanalizuoti nepavyko.", - "no-relations-text": "Ryšių nėra" - }, - "resource": { - "add": "Add Resource", - "all-types": "All", - "copyId": "Copy resource Id", - "delete": "Delete resource", - "delete-resource-text": "Be careful, after the confirmation the resource will become unrecoverable.", - "delete-resource-title": "Are you sure you want to delete the resource '{{resourceTitle}}'?", - "delete-resources-action-title": "Delete { count, plural, =1 {1 resource} other {# resources} }", - "delete-resources-text": "Please note that the selected resources, even if they are used in device profiles, will be deleted.", - "delete-resources-title": "Are you sure you want to delete { count, plural, =1 {1 resource} other {# resources} }?", - "download": "Download resource", - "drop-file": "Drop a resource file or click to select a file to upload.", - "drop-resource-file-or": "Drag and drop a resource file or", - "empty": "Resource is empty", - "file-name": "File name", - "idCopiedMessage": "Resource Id has been copied to clipboard", - "no-resource-matching": "No resource matching '{{widgetsBundle}}' were found.", - "no-resource-text": "No resources found", - "open-widgets-bundle": "Open widgets bundle", - "resource": "Resource", - "resource-library-details": "Resource details", - "resource-type": "Resource type", - "resources-library": "Resources library", - "search": "Search resources", - "selected-resources": "{ count, plural, =1 {1 resource} other {# resources} } selected", - "system": "System", - "title": "Title", - "title-required": "Title is required.", - "title-max-length": "Title should be less than 256", - "type": { - "jks": "JKS", - "js-module": "JS module", - "lwm2m-model": "LWM2M model", - "pkcs-12": "PKCS #12" - } + "entity-count": { + "entity-count-card-style": "Objektų skaičiaus kortelės stilius" }, - "rulechain": { - "rulechain": "Rule chain", - "rulechain-events": "Rule chain events", - "rulechains": "Rule chains", - "root": "Root", - "delete": "Delete rule chain", - "name": "Name", - "name-required": "Name is required.", - "name-max-length": "Name should be less than 256", - "description": "Description", - "add": "Add Rule Chain", - "set-root": "Make rule chain root", - "set-root-rulechain-title": "Are you sure you want to make the rule chain '{{ruleChainName}}' root?", - "set-root-rulechain-text": "After the confirmation the rule chain will become root and will handle all incoming transport messages.", - "delete-rulechain-title": "Are you sure you want to delete the rule chain '{{ruleChainName}}'?", - "delete-rulechain-text": "Be careful, after the confirmation the rule chain and all related data will become unrecoverable.", - "delete-rulechains-title": "Are you sure you want to delete { count, plural, =1 {1 rule chain} other {# rule chains} }?", - "delete-rulechains-action-title": "Delete { count, plural, =1 {1 rule chain} other {# rule chains} }", - "delete-rulechains-text": "Be careful, after the confirmation all selected rule chains will be removed and all related data will become unrecoverable.", - "add-rulechain-text": "Add new rule chain", - "no-rulechains-text": "No rule chains found", - "rulechain-details": "Rule chain details", - "details": "Details", - "events": "Events", - "system": "System", - "import": "Import rule chain", - "export": "Export rule chain", - "export-failed-error": "Unable to export rule chain: {{error}}", - "create-new-rulechain": "Create new rule chain", - "rulechain-file": "Rule chain file", - "invalid-rulechain-file-error": "Unable to import rule chain: Invalid rule chain data structure.", - "copyId": "Copy rule chain Id", - "idCopiedMessage": "Rule chain Id has been copied to clipboard", - "select-rulechain": "Select rule chain", - "no-rulechains-matching": "No rule chains matching '{{entity}}' were found.", - "rulechain-required": "Rule chain is required", - "management": "Rules management", - "debug-mode": "Debug mode", - "search": "Search rule chains", - "selected-rulechains": "{ count, plural, =1 {1 rule chain} other {# rule chains} } selected", - "open-rulechain": "Open rule chain", - "edge-template-root": "Template Root", - "assign-to-edge": "Assign to Edge", - "edge-rulechain": "Edge rule chain", - "unassign-rulechain-from-edge-text": "After the confirmation the rulechain will be unassigned and won't be accessible by the edge.", - "unassign-rulechains-from-edge-title": "Are you sure you want to unassign { count, plural, =1 {1 rulechain} other {# rulechains} }?", - "unassign-rulechains-from-edge-text": "After the confirmation all selected rulechains will be unassigned and won't be accessible by the edge.", - "assign-rulechain-to-edge-title": "Assign Rule Chain(s) To Edge", - "assign-rulechain-to-edge-text": "Please select the rulechains to assign to the edge", - "set-edge-template-root-rulechain": "Make rule chain as edge template root", - "set-edge-tscheduler-eventemplate-root-rulechain": "Make rule chain as edge template root", - "set-edge-template-root-rulechain-title": "Are you sure you want to make the rule chain '{{ruleChainName}}' edge template root?", - "set-edge-template-root-rulechain-text": "After the confirmation the rule chain will become edge template root and will be root rule chain for a newly created edges.", - "invalid-rulechain-type-error": "Unable to import rule chain: Invalid rule chain type. Expected type is {{expectedRuleChainType}}.", - "set-auto-assign-to-edge": "Assign rule chain to edge(s) on creation", - "set-auto-assign-to-edge-title": "Are you sure you want to assign the edge rule chain '{{ruleChainName}}' to edge(s) on creation?", - "set-auto-assign-to-edge-text": "After the confirmation the edge rule chain will be automatically assigned to edge(s) on creation.", - "unset-auto-assign-to-edge": "Do not assign rule chain to edge(s) on creation", - "unset-auto-assign-to-edge-title": "Are you sure you do not want to assign the edge rule chain '{{ruleChainName}}' to edge(s) on creation?", - "unset-auto-assign-to-edge-text": "After the confirmation the edge rule chain will no longer be automatically assigned to edge(s) on creation.", - "unassign-rulechain-title": "Are you sure you want to unassign the rulechain '{{ruleChainName}}'?", - "unassign-rulechains": "Unassign rulechains" - }, - "rulenode": { - "rule-node-events": "Rule node events", - "details": "Details", - "events": "Events", - "search": "Search nodes", - "open-node-library": "Open node library", - "close-node-library": "Close node library", - "add": "Add rule node", - "name": "Name", - "name-required": "Name is required.", - "name-max-length": "Name should be less than 256", - "type": "Type", - "rule-node-description": "Rule node description", - "delete": "Delete rule node", - "select-all-objects": "Select all nodes and connections", - "deselect-all-objects": "Deselect all nodes and connections", - "delete-selected-objects": "Delete selected nodes and connections", - "delete-selected": "Delete selected", - "create-nested-rulechain": "Create nested rule chain", - "select-all": "Select all", - "copy-selected": "Copy selected", - "deselect-all": "Deselect all", - "rulenode-details": "Rule node details", - "debug-mode": "Debug mode", - "configuration": "Configuration", - "link": "Link", - "link-details": "Rule node link details", - "add-link": "Add link", - "link-label": "Link label", - "link-label-required": "Link label is required.", - "custom-link-label": "Custom link label", - "custom-link-label-required": "Custom link label is required.", - "link-labels": "Link labels", - "link-labels-required": "Link labels is required.", - "no-link-labels-found": "No link labels found", - "no-link-label-matching": "'{{label}}' not found.", - "create-new-link-label": "Create a new one!", - "type-filter": "Filter", - "type-filter-details": "Filter incoming messages with configured conditions", - "type-enrichment": "Enrichment", - "type-enrichment-details": "Add additional information into Message Metadata", - "type-transformation": "Transformation", - "type-transformation-details": "Change Message payload and Metadata", - "type-action": "Action", - "type-action-details": "Perform special action", - "type-analytics": "Analytics", - "type-analytics-details": "Perform analysis of streamed or persisted data", - "type-external": "External", - "type-external-details": "Interacts with external system", - "type-rule-chain": "Rule Chain", - "type-rule-chain-details": "Forwards incoming messages to specified Rule Chain", - "type-flow": "Flow", - "type-flow-details": "Organizes message flow", - "type-input": "Input", - "type-input-details": "Logical input of Rule Chain, forwards incoming messages to next related Rule Node", - "type-unknown": "Unknown", - "type-unknown-details": "Unresolved Rule Node", - "directive-is-not-loaded": "Defined configuration directive '{{directiveName}}' is not available.", - "ui-resources-load-error": "Failed to load configuration ui resources.", - "invalid-target-rulechain": "Unable to resolve target rule chain!", - "test-script-function": "Test script function", - "script-lang-java-script": "Java Script", - "script-lang-tbel": "TBEL", - "message": "Message", - "message-type": "Message type", - "select-message-type": "Select message type", - "message-type-required": "Message type is required", - "metadata": "Metadata", - "metadata-required": "Metadata entries can't be empty.", - "output": "Output", - "test": "Test", - "help": "Help", - "test-with-this-message": "{{test}} with this message" - }, - "role": { - "role": "Rolė", - "roles": "Rolės", - "management": "Rolių valdymas", - "view-roles": "Peržiūrėti roles", - "no-roles-matching": "Rolių, atitinkančių '{{entity}}' nėra.", - "role-list": "Rolių sąrašas", - "role-list-required": "Rolių sąrašas būtinas", - "add": "Pridėti rolę", - "view": "Peržiūrėti rolę", - "search": "Rolių paieška", - "selected-roles": "Pasirinkta { count, plural, =1 {1 rolė} other {# rolės} }", - "no-roles-text": "Rolių nėra", - "role-details": "Informacija apie rolę", - "add-role-text": "Pridėti naują rolę", - "delete": "Panaikinti rolę", - "delete-roles": "Panaikinti roles", - "delete-role-title": "Ar tikrai norite panaikinti '{{roleName}}' rolę?", - "delete-role-text": "Būkite dėmesingi, po patvirtinimo, rolė ir visa su ja susijusi informacija bus pašalinta.", - "delete-roles-title": "Ar tikrai norite panaikinti { count, plural, =1 {1 rolę} other {# roles} }?", - "delete-roles-action-title": "Panaikinti { count, plural, =1 {1 rolę} other {# roles} }", - "delete-roles-text": "Būkite dėmesingi, po patvirtinimo, visos pasirinktos rolės ir su jomis susijusi informacija bus pašalintos.", - "role-type": "Tipas", - "role-type-required": "Rolės tipas būtinas.", - "select-role-type": "Pasirinkite rolės tipą", - "enter-role-type": "Įveskite rolės tipą", - "any-role": "Bet kuri rolė", - "no-role-types-matching": "Rolių tipų, atitinkančių '{{entitySubtype}}' nėra.", - "role-type-list-empty": "Nepasirinktas rolės tipas.", - "role-types": "Rolių tipais", - "created-time": "Sukųrimo laikas", - "name": "Pavadinimas", - "name-required": "Pavadinimas būtinas.", - "name-max-length": "Pavadinimas negali viršyti 256 simbolių", - "description": "Aprašymas", - "events": "Įvykiai", - "details": "Informacija", - "copyId": "Kopijuoti rolės Id", - "idCopiedMessage": "Rolės Id nukopijuotas į iškarpinę", - "permissions": "Leidimai", - "role-required": "Rolė būtina", - "roles-required": "Rolės būtinos", - "display-type": { - "GENERIC": "Bendroji", - "GROUP": "Grupinė" - } + "count": { + "layout": "Išdėstymas", + "layout-column": "Stulpelis", + "layout-row": "Eilutė", + "label": "Etiketė", + "icon": "Piktograma", + "icon-background": "Piktogramos fonas", + "value": "Reikšmė", + "chevron": "Rodyklė", + "auto-scale": "Automatinis mastelis" }, - "group-permission": { - "user-group-roles": "Vartotojų grupės rolės", - "entity-group-permissions": "Subjektų grupės leidimai", - "role-type": "Rolės tipas", - "role-name": "Rolės pavadinimas", - "group-type": "Grupės tipas", - "group-name": "Grupės pavadinimas", - "group-owner": "Grupės savininkas", - "user-group-name": "Vartotojų grupės pavadinimas", - "user-group-owner": "Vartotojų grupės savininkas", - "edit": "Redaguoti leidimus", - "delete": "Naikinti leidimus", - "selected-group-permissions": "Pasirinkta { count, plural, =1 {1 grupinis leidimas} other {# grupiniai leidimai} }", - "delete-group-permission-title": "Ar tikrai norite panaikinti '{{roleName}}' grupinį leidimą?", - "delete-group-permission-text": "Būkite dėmesingi, po patvirtinimo, grupinis leidimas ir visa su juo sisijusi informacija bus pašalinta.", - "delete-group-permission": "Panaikinti grupinį leidima", - "delete-group-permissions-title": "Ar tikrai norite panaikinti { count, plural, =1 {1 grupinį leidimą} other {# grupinius leidimus} }?", - "delete-group-permissions-text": "Būkite dėmesingi, po patvirtinimo, pasirinkti grupiniai leidimai ir visa su jais susijusi informacija bus panaikinta ir atitinkami vartotojai neteks prieigos prie tam tikrų resursų.", - "delete-group-permissions": "Panaikinti grupinius leidimus", - "add-group-permission": "Pridėti grupinį leidimą", - "edit-group-permission": "Redaguoti grupinį leidimą", - "entity-group": "Subjektų grupė", - "user-group": "Vartotojų grupė", - "no-owners-matching": "Savininkų, atitinkančių '{{owner}}' nėra.", - "target-owner-required": "Subjektų grupės savininkas būtinas.", - "target-user-group-owner-required": "Vartotojų grupės savininkas būtinas.", - "no-group-permissions-text": "Grupinių leidimų nėra" - }, - "permission": { - "permissions-required": "Turi būti nurodytas nors vienas leidimas.", - "remove-permission": "Panaikinti leidimą", - "add-permission": "Pridėti leidimą", - "other": "Kita", - "resource": { - "resource": "Resursas", - "select-resource": "Pasirinkite resursą", - "resource-required": "Resursas būtinas", - "no-resources-matching": "Resursų, atitinkančių '{{resource}}' nėra.", - "display-type": { - "ALL": "Visi", - "PROFILE": "Profilis", - "ADMIN_SETTINGS": "Administratoriaus nustatymai", - "ALARM": "Įspėjimai", - "DEVICE": "Įrenginys", - "DEVICE_PROFILE": "Įrenginio profilis", - "ASSET": "Turtas", - "CUSTOMER": "Klientas", - "DASHBOARD": "Skydelis", - "ENTITY_VIEW": "Subjekto rodinys", - "EDGE": "Edge", - "TENANT": "Valdytojas", - "TENANT_PROFILE": "Valdytojo profilis", - "RULE_CHAIN": "Taisyklių grandinė", - "USER": "Vartotojas", - "WIDGETS_BUNDLE": "Valdiklių rinkinys", - "WIDGET_TYPE": "Valdiklio tipas", - "CONVERTER": "Keitiklis", - "INTEGRATION": "Integracija", - "SCHEDULER_EVENT": "Tvarkaraščio įvykis", - "BLOB_ENTITY": "Blob subjektas", - "CUSTOMER_GROUP": "Klientų grupė", - "DEVICE_GROUP": "Įrenginių grupė", - "ASSET_GROUP": "Turto grupė", - "USER_GROUP": "Vartotojų grupė", - "ENTITY_VIEW_GROUP": "Subjektų rodinių grupė", - "DASHBOARD_GROUP": "Skydelių grupė", - "ROLE": "Rolė", - "GROUP_PERMISSION": "Grupinis leidimas", - "WHITE_LABELING": "Tinkinimas", - "AUDIT_LOG": "Audito žurnalas", - "API_USAGE_STATE": "API Usage State", - "TB_RESOURCE": "Resource", - "EDGE_GROUP": "Edge Group", - "OTA_PACKAGE": "Ota package", - "QUEUE": "Queue", - "VERSION_CONTROL": "Version control", - "ASSET_PROFILE": "Asset Profile", - "NOTIFICATION": "Notification" - } - }, - "operation": { - "operation": "Operacija", - "operations": "Operacijos", - "operations-required": "Turi būti nurodyta nors viena operacija.", - "enter-operation": "Įveskite operaciją", - "no-operations-matching": "Operacijų, atitinkančių '{{operation}}' nėra.", - "display-type": { - "ALL": "Visi", - "CREATE": "Sukurti", - "READ": "Skaityti", - "WRITE": "Rašyti", - "DELETE": "Panaikinti", - "ASSIGN_TO_CUSTOMER": "Priskirti klientui", - "UNASSIGN_FROM_CUSTOMER": "Atsieti nuo kliento", - "RPC_CALL": "RPC kvietimas", - "READ_CREDENTIALS": "Skaityti įgaliojimus", - "WRITE_CREDENTIALS": "Rašyti įgaliojimus", - "READ_ATTRIBUTES": "Skaityti atributus", - "WRITE_ATTRIBUTES": "Rašyti atributus", - "READ_TELEMETRY": "Skaityti telemetriją", - "WRITE_TELEMETRY": "Rašyti telemetriją", - "CLAIM_DEVICES": "Patvirtinti įrenginius", - "IMPERSONATE": "Įeiti kaip vartotojui", - "CHANGE_OWNER": "Pakeisti savininką", - "ADD_TO_GROUP": "Įtraukti į grupę", - "REMOVE_FROM_GROUP": "Pašalinti iš grupės", - "SHARE_GROUP": "Bendrinti grupę", - "ASSIGN_TO_TENANT": "Priskirti valdytojui" - } - } + "table": { + "common-table-settings": "Bendrieji lentelės nustatymai", + "enable-search": "Įjungti paiešką", + "enable-sticky-header": "Visada rodyti antraštę", + "enable-sticky-action": "Visada rodyti veiksmų stulpelį", + "hidden-cell-button-display-mode": "Paslėpto mygtuko veiksmų rodymo režimas", + "show-empty-space-hidden-action": "Rodyti tuščią vietą vietoje paslėpto langelio mygtuko veiksmo", + "dont-reserve-space-hidden-action": "Nerezervuoti vietos paslėptiems veiksmų mygtukams", + "display-timestamp": "Rodyti laiko žymos stulpelį", + "display-pagination": "Rodyti puslapiavimą", + "default-page-size": "Numatytasis puslapio dydis", + "page-step-settings": "Puslapio žingsnių nustatymai", + "page-step-count": "Žingsnių skaičius", + "page-step-increment": "Žingsnio didinimas", + "page-step-count-format-message": "Turi būti sveikasis skaičius nuo 1 iki 100.", + "page-step-increment-format-message": "Turi būti sveikasis skaičius, ne mažesnis kaip 1.", + "use-entity-label-tab-name": "Naudoti objekto etiketę skirtuko pavadinime", + "hide-empty-lines": "Slėpti tuščias eilutes", + "row-style": "Eilutės stilius", + "use-row-style-function": "Naudoti eilutės stiliaus funkciją", + "row-style-function": "Eilutės stiliaus funkcija", + "cell-style": "Langelio stilius", + "use-cell-style-function": "Naudoti langelio stiliaus funkciją", + "cell-style-function": "Langelio stiliaus funkcija", + "cell-content": "Langelio turinys", + "use-cell-content-function": "Naudoti langelio turinio funkciją", + "cell-content-function": "Langelio turinio funkcija", + "show-latest-data-column": "Rodyti naujausių duomenų stulpelį", + "latest-data-column-order": "Naujausių duomenų stulpelio tvarka", + "entities-table-title": "Objektų lentelės pavadinimas", + "enable-select-column-display": "Įjungti pasirinktų stulpelių rodymą", + "display-entity-name": "Rodyti objekto pavadinimo stulpelį", + "entity-name-column-title": "Objekto pavadinimo stulpelio pavadinimas", + "display-entity-label": "Rodyti objekto etiketės stulpelį", + "entity-label-column-title": "Objekto etiketės stulpelio pavadinimas", + "display-entity-type": "Rodyti objekto tipo stulpelį", + "default-sort-order": "Numatytoji rūšiavimo tvarka", + "custom-title": "Tinkintas antraštės pavadinimas", + "column-width": "Stulpelio plotis (px arba %)", + "default-column-visibility": "Numatytasis stulpelio matomumas", + "column-visibility-visible": "Matomas", + "column-visibility-hidden": "Paslėptas", + "column-visibility-hidden-mobile": "Paslėptas mobiliuoju režimu", + "column-selection-to-display": "Stulpelių pasirinkimas rodymui", + "column-selection-to-display-enabled": "Įjungta", + "column-selection-to-display-disabled": "Išjungta", + "alarms-table-title": "Pavojaus signalų lentelės pavadinimas", + "enable-alarms-selection": "Įjungti signalų pasirinkimą", + "enable-alarms-search": "Įjungti signalų paiešką", + "enable-alarm-filter": "Įjungti signalų filtrą", + "display-alarm-details": "Rodyti signalų detales", + "allow-alarms-ack": "Leisti patvirtinti signalus", + "allow-alarms-clear": "Leisti išvalyti signalus", + "display-alarm-activity": "Rodyti signalų veiklą", + "allow-alarms-assign": "Leisti priskirti signalus", + "columns": "Stulpeliai", + "column-settings": "Stulpelių nustatymai", + "remove-column": "Pašalinti stulpelį", + "add-column": "Pridėti stulpelį", + "no-columns": "Stulpeliai nesukonfigūruoti", + "columns-to-display": "Stulpeliai, kuriuos rodyti", + "table-header": "Lentelės antraštė", + "header-buttons": "Antraštės mygtukai", + "table-buttons": "Lentelės mygtukai", + "pagination": "Puslapiavimas", + "rows": "Eilutės", + "timeseries-column-error": "Turi būti nurodytas bent vienas laiko sekos stulpelis", + "alarm-column-error": "Turi būti nurodytas bent vienas signalų stulpelis", + "table-tabs": "Lentelės skirtukai", + "show-cell-actions-menu-mobile": "Rodyti langelio veiksmų meniu mobiliajame režime", + "disable-sorting": "Išjungti rūšiavimą" }, - "scheduler": { - "scheduler": "Tvarkaraštis", - "scheduler-event": "Tvarkaraščio įvykis", - "select-scheduler-event": "Pasirinkite tvarkaraščio įvykį", - "no-scheduler-events-matching": "Tvarkaraščio įvykių, atitinkančių '{{entity}}' nėra.", - "scheduler-event-required": "Tvarkaraščio įvykis būtinas", - "management": "Tvarkaraščio valdymas", - "scheduler-events": "Tvarkaraščio įvykiai", - "add-scheduler-event": "Pridėti tvarkaraščio įvykį", - "search-scheduler-events": "Tvarkaraščio įvykių paieška", - "created-time": "Sukūrimo laikas", - "name": "Pavadinimas", - "name-required": "Pavadinimas būtinas", - "name-max-length": "Pavadinimas negali viršyti 256 simbolių", - "type": "Tipas", - "created_customer": "Sukūrė klientas", - "edit-scheduler-event": "Redaguoti tvarkaraščio įvykį", - "view-scheduler-event": "Peržiūrėti tvarkaraščio įvykį", - "delete-scheduler-event": "Panaikinti tvarkaraščio įvykį", - "no-scheduler-events": "Tvarkaraščio įvykių nėra", - "selected-scheduler-events": "Pasirinkta { count, plural, =1 {1 tvarkaraščio įvykis} other {# tvarkaraščio įvykiai} }", - "delete-scheduler-event-title": "Ar tikrai norite panaikinti tvarkaraščio įvykį '{{schedulerEventName}}'?", - "delete-scheduler-event-text": "`", - "delete-scheduler-events-title": "Ar tikrai norite panaikinti { count, plural, =1 {1 tvarkaraščio įvykį} other {# tvarkaraščio įvykius} }?", - "delete-scheduler-events-text": "Būkite dėmesingi, po patvirtinimo, pasirinkti tvarkaraščio įvykiai ir visa su jais susijusi informacija bus panaikinta.", - "create": "Sukurti tvarkaraščio įvykį", - "edit": "Redaguoti tvarkaraščio įvykį", - "view": "Peržiūrėti tvarkaraščio įvykį", - "configuration": "Konfigūracija", - "schedule": "Tvarkaraštis", - "start-time": "Pradžios laikas", - "repeat": "Pakartoti", - "repeats": "Pakartojimai", - "daily": "Kasdieną", - "every-n-days": "Kas N dienas", - "every-n-days-text": "Every { days, plural, =1 {day} other {# days} }", - "weekly": "Kas savaitę", - "every-n-weeks": "Kas N savaites", - "every-n-weeks-text": "Every { weeks, plural, =1 {week} other {# weeks} }", - "monthly": "Kas mėnesį", - "yearly": "Kas metus", - "timer": "Nurodytu laiku", - "repeats-required": "Pakartojimai būtini.", - "repeat-on": "Kartoti", - "repeat-every": "Kartoti kiekvieną", - "repeat-every-n-days": "Kartoti kas N dienas", - "repeat-days-required": "Pakartojim dienų skaičius būtinas.", - "invalid-repeat-days-value": "Pakartojimo dienų skaičius turi būti sveikas teigiamas skaičius.", - "repeat-every-n-weeks": "Kartoti kas N savaites", - "repeat-weeks-required": "Pakartojimo savaičių skaičius būtinas.", - "invalid-repeat-weeks-value": "Pakartojimo savaičių skaičius turi būti sveikas teigiamas skaičius.", - "ends-on": "Pabaiga", - "sunday-label": "Sk", - "monday-label": "Pr", - "tuesday-label": "An", - "wednesday-label": "Tr", - "thursday-label": "Kt", - "friday-label": "Pn", - "saturday-label": "Št", - "repeat-on-sunday": "Kartoti sekmadieniais", - "repeat-on-monday": "Kartoti pirmadieniais", - "repeat-on-tuesday": "Kartoti antradieniais", - "repeat-on-wednesday": "Kartoti trečiadieniais", - "repeat-on-thursday": "Kartoti ketvirtadieniais", - "repeat-on-friday": "Kartoti penktadieniais", - "repeat-on-saturday": "Kartoti šeštadieniais", - "event-type": "Įvykio tipas", - "select-event-type": "Pasirinkite įvykio tiipą", - "event-type-required": "Įvykio tipas būtinas.", - "event-type-max-length": "Įvykio tipas negali viršyti 256 simbolių.", - "list-mode": "Sąrašas", - "calendar-mode": "Kalendorius", - "calendar-view-type": "Kalendoriaus peržiūros tipas", - "month": "Mėnuo", - "week": "Savaitė", - "day": "Diena", - "agenda-week": "Savaitinis tvarkaraštis", - "agenda-day": "Dienų tvarkaraštis", - "list-year": "Sąrašas metams", - "list-month": "Sąrašas mėnesiui", - "list-week": "Sąrašas savaitei", - "list-day": "Sąrašas dienai", - "today": "Šiandien", - "navigate-before": "Ankstesnis", - "navigate-next": "Sekantis", - "starting-from": "Pradėti nuo", - "until": "iki", - "on": "į", - "sunday": "Sekmadienis", - "monday": "Pirmadienis", - "tuesday": "Antradienis", - "wednesday": "Trečiadienis", - "thursday": "Ketvirtadienis", - "friday": "Penktadienis", - "saturday": "Šesštadienis", - "originator": "Iniciatorius", - "single-entity": "Vienas subjektas", - "group-of-entities": "Subjektų grupė", - "entities-group-owner": "Subjektų grupės savininkas", - "single-device": "Vienas įrenginys", - "group-of-devices": "Įrenginių grupė", - "devices-group-owner": "Įrenginių grupės savininkas", - "message-body": "Pranešimo tekstas", - "target": "Tikslas", - "rpc-method": "Method", - "rpc-method-required": "Method is required", - "rpc-method-white-space": "White space is not allowed.", - "rpc-params": "Params", - "select-dashboard-state": "Pasirinkite skydelio būseną", - "hours": "Valandos", - "minutes": "Minutės", - "seconds": "Sekundės", - "time-interval-required": "Laiko intervalas būtinas", - "time-unit-required": "Laiko vienetas būtinas", - "every-hour": "kas { count, plural, =1 {valandą} other {# valandas} }", - "every-minute": "kas { count, plural, =1 {minutę} other {# minutes} }", - "every-second": "kas { count, plural, =1 {sekundę} other {# sekundes} }", - "invalid-time": "Neteisingas laikas" - }, - "report": { - "report-config": "Ataskaitos konfigūracija", - "email-config": "Elektroninio pašto konfigūracija", - "dashboard-state-param": "Skydelio būsenos parametro reikšmė", - "base-url": "Pagrindinis URL", - "base-url-required": "Pagrindinis URL būtinas.", - "use-dashboard-timewindow": "Naudoti skydelio laiko langą", - "timewindow": "Laiko langas", - "name-pattern": "Ataskaitos pavadinimo šablonas", - "name-pattern-required": "Ataskaitos pavadinimo šablonas būtinas", - "type": "Ataskaitos tipas", - "use-current-user-credentials": "Naudoti dabartinio vartotojo įgaliojimus", - "customer-user-credentials": "Kliento vartotojo įgaliojimai", - "customer-user-credentials-required": "Kliento vartotojo įgaliojimai būtini", - "generate-test-report": "Generuoti bandomąją ataskaitą", - "send-email": "Siųsti laišką", + "latest-chart": { + "total": "Bendra suma", + "auto-scale": "Automatinis mastelis", + "clockwise-layout": "Išdėstymas pagal laikrodžio rodyklę", + "sort-series": "Rūšiuoti serijas pagal etiketę", + "tooltip-value-type-absolute": "Absoliuti reikšmė", + "tooltip-value-type-percentage": "Procentinė reikšmė" + }, + "pie-chart": { + "pie-chart-appearance": "Skritulinės diagramos išvaizda", + "label": "Etiketė", + "border": "Kraštinė", + "radius": "Spindulys", + "pie-chart-card-style": "Skritulinės diagramos kortelės stilius" + }, + "radar-chart": { + "radar-appearance": "Radaro diagramos išvaizda", + "shape": "Forma", + "shape-polygon": "Daugiakampis", + "shape-circle": "Apskritimas", + "color": "Spalva", + "line": "Linija", + "points": "Taškai", + "points-label": "Taškų etiketė", + "radar-axis": "Radaro ašis", + "axis-label": "Ašies etiketė", + "ticks-label": "Padalų etiketė", + "radar-chart-style": "Radaro diagramos stilius", + "max-axes-scaling": "Maksimalus ašių mastelis", + "max-axes-scaling-hint": "Pasirinkite, ar kiekviena radaro ašis turi savo maksimalų dydį (Atskiras), ar dalijasi didžiausia reikšme tarp visų ašių pagal valdiklio duomenis (Bendras).", + "separate": "Atskiras", + "common": "Bendras" + }, + "time-series-chart": { + "chart": "Diagrama", + "chart-style": "Diagramos stilius", + "data-zoom": "Duomenų mastelio keitimas", + "stack-mode": "Sluoksniavimo režimas", + "stack-mode-hint": "Sluoksniuoja serijas diagramoje. Serijos su tomis pačiomis vienetais bus dedamos viena ant kitos.", + "axes": "Ašys", + "y-axes": "Y ašys", + "line-type": "Linijos tipas", + "line-width": "Linijos storis", + "type-line": "Linija", + "type-bar": "Stulpelis", + "type-point": "Taškas", + "no-aggregation-bar-width-strategy": "Stulpelių pločio strategija neagreguotiems duomenims", + "no-aggregation-bar-width-strategy-group": "Grupuoti", + "no-aggregation-bar-width-strategy-separate": "Atskiri", + "bar-group-width": "Stulpelių grupės plotis", + "bar-width": "Stulpelio plotis", + "bar-width-relative": "Procentinė laiko lango dalis", + "bar-width-absolute": "Absoliutus (ms)", + "comparison": { + "comparison": "Palyginimas", + "comparison-hint": "Palyginimas veikia tik su istorinių duomenų!", + "show": "Rodyti", + "settings": "Palyginimo nustatymai", + "show-values-for-comparison": "Rodyti istorinius duomenis palyginimui", + "comparison-values-label": "Palyginimo rakto etiketė", + "comparison-values-label-auto": "Automatinė", + "comparison-data-color": "Palyginimo duomenų spalva" + }, + "threshold": { + "thresholds": "Slenksčiai", + "source": "Šaltinis", + "key-value": "Raktas / Reikšmė", + "no-thresholds": "Slenksčiai nesukonfigūruoti", + "add-threshold": "Pridėti slenkstį", + "type-constant": "Pastovus", + "type-latest-key": "Raktas", + "type-entity": "Objektas", + "threshold-settings": "Slenksčio nustatymai", + "remove-threshold": "Pašalinti slenkstį", + "threshold-value-required": "Reikalinga slenksčio reikšmė.", + "key-required": "Reikalingas raktas.", + "entity-key-required": "Reikalingas objekto raktas.", + "line-appearance": "Linijos išvaizda", + "line-color": "Linijos spalva", + "start-symbol": "Pradžios simbolis", + "end-symbol": "Pabaigos simbolis", + "symbol-size": "Dydis", + "label": "Etiketė", + "label-position-start": "Pradžia", + "label-position-middle": "Vidurys", + "label-position-end": "Pabaiga", + "label-position-inside-start": "Viduje pradžioje", + "label-position-inside-start-top": "Viduje viršuje pradžioje", + "label-position-inside-start-bottom": "Viduje apačioje pradžioje", + "label-position-inside-middle": "Viduje per vidurį", + "label-position-inside-middle-top": "Viduje per vidurį viršuje", + "label-position-inside-middle-bottom": "Viduje per vidurį apačioje", + "label-position-inside-end": "Viduje pabaigoje", + "label-position-inside-end-top": "Viduje pabaigoje viršuje", + "label-position-inside-end-bottom": "Viduje pabaigoje apačioje", + "label-background": "Etiketės fonas" + }, + "state": { + "states": "Būsenos", + "label": "Etiketė", + "ticks-value": "Padalų reikšmė", + "source": "Šaltinis", + "value-range": "Reikšmė / Diapazonas", + "no-states": "Būsenos nesukonfigūruotos", + "add-state": "Pridėti būseną", + "type-constant": "Pastovi", + "type-range": "Diapazonas", "from": "Nuo", - "from-required": "Būtina nurodyti nuo ko siunčiamas laiškas.", - "to": "Kam", - "to-required": "Būtina nurodyti kam siunčiamas laiškas.", - "cc": "Cc", - "bcc": "Bcc", - "subject": "Tema", - "subject-required": "Būtina nurodyti laiško temą.", - "body": "Tekstas", - "body-required": "Būtina įrašyti laiško tekstą." - }, - "blob-entity": { - "blob-entity": "Blob subjektas", - "select-blob-entity": "Pasirinkite blob subjektą", - "no-blob-entities-matching": "Blob subjektų, atitinkančių '{{entity}}' nėra.", - "blob-entity-required": "Blob subjektas būtinas", - "files": "Failai", - "search": "Failų paieška", - "clear-search": "Išvalyti paiešką", - "no-blob-entities-prompt": "Failų nėra", - "report": "Ataskaita", - "created-time": "Sukūrimo laikas", - "name": "Pavadinimas", + "to": "Iki", + "remove-state": "Pašalinti būseną" + }, + "grid": { + "grid": "Tinklelis", + "background-color": "Fono spalva", + "border": "Rėmelis" + }, + "axis": { + "axes": "Ašys", + "x-axis": "X ašis", + "y-axis": "Y ašis", + "y-axis-settings": "Y ašies nustatymai", + "comparison-x-axis-settings": "Palyginimo X ašies nustatymai", + "remove-y-axis": "Pašalinti Y ašį", + "id": "Id", + "label": "Etiketė", + "position": "Pozicija", + "position-left": "Kairėje", + "position-right": "Dešinėje", + "position-top": "Viršuje", + "position-bottom": "Apačioje", + "tick-labels": "Padalų etiketės", + "ticks-formatter-function": "Padalų formatavimo funkcija", + "ticks-generator-function": "Padalų generavimo funkcija", + "show-ticks": "Rodyti padalas", + "show-line": "Rodyti liniją", + "show-split-lines": "Rodyti padalų linijas", + "show-split-lines-x-axis-hint": "Jei įjungta, bus rodomos vertikalios diagramos linijos.", + "show-split-lines-y-axis-hint": "Jei įjungta, bus rodomos horizontalios diagramos linijos.", + "ticks-interval": "Padalų intervalas", + "ticks-interval-hint": "Priverstinai nustato ašies segmentacijos intervalą.", + "split-number": "Padalų skaičius", + "split-number-hint": "Padalų, į kurias suskirstyta ašis, skaičius.", + "min": "Min.", + "max": "Maks.", + "show": "Rodyti", + "add-y-axis": "Pridėti Y ašį" + }, + "series": { + "legend-settings": "Legenda nustatymai", + "show-in-legend": "Rodyti legendoje", + "show-in-legend-hint": "Rodyti serijos pavadinimą ir duomenis legendoje.", + "hidden-by-default": "Numatytai paslėpta", + "hidden-by-default-hint": "Padaryti seriją paslėptą legendoje pagal numatytuosius nustatymus.", + "series-type": "Serijos tipas", "type": "Tipas", - "created_customer": "Skūrė klientas", - "selected-blob-entities": "Pasirinkta{ count, plural, =1 {1 failas} other {# failai} }", - "download-blob-entity": "Atsisiųsti failą", - "delete-blob-entity": "Ištrinti failą", - "delete-blob-entity-title": "Ar tikrai norite ištrinti '{{blobEntityName}}' failą?", - "delete-blob-entity-text": "Būkite dėmesingi, po patvirtinimo failas bus ištrintas.", - "delete-blob-entities-title": "Artikrai norite ištrinti { count, plural, =1 {1 failą} other {# failus} }?", - "delete-blob-entities-text": "Būkite dėmesingi, po patvirtinimo visi pasirinkti failai ir su jais susijusi informacija bus ištrinta." - }, - "timezone": { - "timezone": "Laiko juosta", - "select-timezone": "Pasirinkti laiko juostą", - "no-timezones-matching": "Laiko juostų, atitinkančių '{{timezone}}' nėra.", - "timezone-required": "Laiko juosta būtina.", - "browser-time": "Browser Time" - }, - "queue": { - "queue-name": "Queue", - "no-queues-found": "No queues found.", - "no-queues-matching": "No queues matching '{{queue}}' were found.", - "select-name": "Select queue name", - "name": "Name", - "name-required": "Queue name is required!", - "name-unique": "Queue name is not unique!", - "name-pattern": "Queue name contains a character other than ASCII alphanumerics, '.', '_' and '-'!", - "queue-required": "Queue is required!", - "topic-required": "Queue topic is required!", - "poll-interval-required": "Poll interval is required!", - "poll-interval-min-value": "Poll interval value can't be less then 1", - "partitions-required": "Partitions is required!", - "partitions-min-value": "Partitions value can't be less then 1", - "pack-processing-timeout-required": "Processing timeout is required", - "pack-processing-timeout-min-value": "Processing timeout value can't be less then 1", - "batch-size-required": "Batch size is required!", - "batch-size-min-value": "Batch size value can't be less then 1", - "retries-required": "Retries is required!", - "retries-min-value": "Retries value can't be negative", - "failure-percentage-required": "Failure percentage is required!", - "failure-percentage-min-value": "Failure percentage value can't be less then 0", - "failure-percentage-max-value": "Failure percentage value can't be more then 100", - "pause-between-retries-required": "Pause between retries is required!", - "pause-between-retries-min-value": "Pause between retries value can't be less then 1", - "max-pause-between-retries-required": "Max pause between retries is required!", - "max-pause-between-retries-min-value": "Max pause between retries value can't be less then 1", - "submit-strategy-type-required": "Submit strategy type is required!", - "processing-strategy-type-required": "Processing strategy type is required!", - "queues": "Queues", - "selected-queues": "{ count, plural, =1 {1 queue} other {# queues} } selected", - "delete-queue-title": "Are you sure you want to delete the queue '{{queueName}}'?", - "delete-queues-title": "Are you sure you want to delete { count, plural, =1 {1 queue} other {# queues} }?", - "delete-queue-text": "Be careful, after the confirmation the queue and all related data will become unrecoverable.", - "delete-queues-text": "After the confirmation all selected queues will be deleted and won't be accessible.", - "search": "Search queue", - "add": "Add queue", - "details": "Queue details", - "topic": "Topic", - "submit-settings": "Submit settings", - "submit-strategy": "Strategy type *", - "grouping-parameter": "Grouping parameter", - "processing-settings": "Retries processing settings", - "processing-strategy": "Processing type *", - "retries-settings": "Retries settings", - "polling-settings": "Polling settings", - "batch-processing": "Batch processing", - "poll-interval": "Poll interval", - "partitions": "Partitions", - "immediate-processing": "Immediate processing", - "consumer-per-partition": "Send message poll for each consumer", - "consumer-per-partition-hint": "Enable separate consumer(s) per each partition", - "processing-timeout": "Processing within, ms", - "batch-size": "Batch size", - "retries": "Number of retries (0 – unlimited)", - "failure-percentage": "Percentage of failure messages for skipping retries", - "pause-between-retries": "Retry within, sec", - "max-pause-between-retries": "Additional retry within, sec", - "delete": "Delete queue", - "copyId": "Copy queue Id", - "idCopiedMessage": "Queue Id has been copied to clipboard", - "description": "Description", - "description-hint": "This text will be displayed in the Queue description instead of the selected strategy", - "alt-description": "Submit Strategy: {{submitStrategy}}, Processing Strategy: {{processingStrategy}}", - "custom-properties": "Custom properties", - "custom-properties-hint": "Custom queue (topic) creation properties, e.g. 'retention.ms:604800000;retention.bytes:1048576000'", - "strategies": { - "sequential-by-originator-label": "Sequential by originator", - "sequential-by-originator-hint": "New message for e.g. device A is not submitted until previous message for device A is acknowledged", - "sequential-by-tenant-label": "Sequential by tenant", - "sequential-by-tenant-hint": "New message for e.g tenant A is not submitted until previous message for tenant A is acknowledged", - "sequential-label": "Sequential", - "sequential-hint": "New message is not submitted until previous message is acknowledged", - "burst-label": "Burst", - "burst-hint": "All messages are submitted to the rule chains in the order they arrive", - "batch-label": "Batch", - "batch-hint": "New batch is not submitted until previous batch is acknowledged", - "skip-all-failures-label": "Skip all failures", - "skip-all-failures-hint": "Ignore all failures", - "skip-all-failures-and-timeouts-label": "Skip all failures and timeouts", - "skip-all-failures-and-timeouts-hint": "Ignore all failures and timeouts", - "retry-all-label": "Retry all", - "retry-all-hint": "Retry all messages from processing pack", - "retry-failed-label": "Retry failed", - "retry-failed-hint": "Retry all failed messages from processing pack", - "retry-timeout-label": "Retry timeout", - "retry-timeout-hint": "Retry all timed-out messages from processing pack", - "retry-failed-and-timeout-label": "Retry failed and timeout", - "retry-failed-and-timeout-hint": "Retry all failed and timed-out messages from processing pack" + "type-line": "Linija", + "type-bar": "Stulpelis", + "line": { + "line": "Linija", + "show-line": "Rodyti liniją", + "step-line": "Pakopinė linija", + "step-type-start": "Pradžia", + "step-type-middle": "Vidurys", + "step-type-end": "Pabaiga", + "smooth-line": "Glotni linija" + }, + "point": { + "points": "Taškai", + "show-points": "Rodyti taškus", + "point-label": "Taško etiketė", + "point-label-hint": "Rodyti etiketę su reikšme virš serijos taško.", + "point-label-background": "Taško etiketės fonas", + "point-shape": "Taško forma", + "point-size": "Taško dydis" } + } }, - "server-error": { - "general": "General server error", - "authentication": "Authentication error", - "jwt-token-expired": "JWT token expired", - "tenant-trial-expired": "Tenant trial expired", - "credentials-expired": "Credentials expired", - "permission-denied": "Permission denied", - "invalid-arguments": "Invalid arguments", - "bad-request-params": "Bad request params", - "item-not-found": "Item not found", - "too-many-requests": "Too many requests", - "too-many-updates": "Too many updates" - }, - "tenant": { - "tenant": "Valdytojas", - "tenants": "Valdytojai", - "management": "Valdytojų valdymas", - "add": "Pridėti valdytoją", - "admins": "Administratoriai", - "manage-tenant-admins": "Valdyti valdytojo administratorius", - "delete": "Ištrinti valdytoją", - "add-tenant-text": "Pridėti naują valdytoją", - "no-tenants-text": "Valdytojų nėra", - "tenant-details": "Informacija apie valdytoją", - "title-max-length": "Pavadinimas negali viršyti 256 simbolių", - "delete-tenant-title": "Ar tikrai norite ištrinti valdytoją '{{tenantTitle}}'?", - "delete-tenant-text": "Būkite dėmesingi, po patvirtinimo valdytojas ir visa su juo susijusi informacija bus pašalinta.", - "delete-tenants-title": "Ar tikrai norite pašalinti { count, plural, =1 {1 valdytoją} other {# valdytojus} }?", - "delete-tenants-action-title": "Pašalinti { count, plural, =1 {1 valdytoją} other {# valdytojus} }", - "delete-tenants-text": "Būkite dėmesingi, po patvirtinimo, visi pasirinkti valdytojai ir su jais susijusi informacija bus pašalinta.", - "title": "Pavadinimas", - "title-required": "Pavadinimas būtinas.", - "description": "Aprašymas", - "details": "Informacija", - "events": "Įvykiai", - "copyId": "Kopijuoti valdytojo Id", - "idCopiedMessage": "Valdytojo Id nukopijuotas į iškarpinę", - "select-tenant": "Pasirinkti valdytoją", - "no-tenants-matching": "Valdytojų, atitinkančių '{{entity}}' nėra.", - "tenant-required": "Valdytojas būtinas", - "allow-white-labeling": "Leisti personalizavimą", - "allow-customer-white-labeling": "Leisti kliento personalizavimą", - "search": "Valdytojų paieška", - "selected-tenants": "Pasirinkta { count, plural, =1 {1 valdytojas} other {# valdutojai} }", - "isolated-tb-rule-engine": "Use isolated ThingsBoard Rule Engine queues", - "isolated-tb-rule-engine-details": "Each tenant will have dedicated Rule Engine queues" - }, - "tenant-profile": { - "tenant-profile": "Valdytojų profilis", - "tenant-profiles": "Valdytojų profiliai", - "add": "Pridėti valdytojų profilį", - "add-profile": "Pridėti profilį", - "edit": "Redaguoti valdytojų profilį", - "tenant-profile-details": "Informacija apie valdytojų profilį", - "no-tenant-profiles-text": "Valdytojų profilių nėra", - "name-max-length": "Pavadinimas negali viršyti 256 simbolių", - "search": "Valdytojų profilių paieška", - "selected-tenant-profiles": "Pasirinkta { count, plural, =1 {1 valdytojų profilis} other {# valdytojų profiliai} }", - "no-tenant-profiles-matching": "Valdytojų profilių, atitinkančių '{{entity}}' nėra.", - "tenant-profile-required": "Valdytojų profilis būtinas", - "idCopiedMessage": "Valdytojų profilio Id nukopijuotas į iškarpinę", - "set-default": "Valdytojų profilį nustatyti kaip pagrndinį", - "delete": "Panaikinti valdytojų profilį", - "copyId": "Kopijuoti valdytojų profilio Id", - "name": "Pavadinimas", - "name-required": "Pavadinimas būtinas.", - "data": "Profilio duomenys", - "profile-configuration": "Profilio konfigūracija", - "description": "Aprašymas", - "default": "Pagrindinis", - "delete-tenant-profile-title": "Ar tikrai norite panaikinti valdytojų profilį '{{tenantProfileName}}'?", - "delete-tenant-profile-text": "Būkite dėmesingi, po patvirtinimo, valdytojų profilis ir visa su juo susijusi informacija bus pašalinta.", - "delete-tenant-profiles-title": "Ar tikrai norite pašalinti { count, plural, =1 {1 valdytojų profilį} other {# valdytojų profilius} }?", - "delete-tenant-profiles-text": "Būkite dėmesingi, po patvirtinimo, visi pasirinkti valdytojų profiliai ir su jais susijusi informacija bus pašalinta.", - "set-default-tenant-profile-title": "Ar tikrai norite valdytojų profilį '{{tenantProfileName}}' nustatyti kaip pagrindinį?", - "set-default-tenant-profile-text": "Po patvirtinimo, valdytojų profilis bus nustatytas kaip pagrinfinis ir bus priskiriamas naujiems valdytojams, kuriems valdytojų profilis nenurodytas.", - "no-tenant-profiles-found": "Valdytojų profilių nėra.", - "create-new-tenant-profile": "Sukurti naują!", - "create-tenant-profile": "Sukuri naują valdytojo profilį", - "import": "Importuoti valdytojo profilį", - "export": "Eksportuoti valdytojo profilį", - "export-failed-error": "Valdytojo profilio importuoti nepavyko: {{error}}", - "tenant-profile-file": "Valdytojo profilio failas", - "invalid-tenant-profile-file-error": "Valdytojo profilio importuoti nepavyko: Neteisinga valdytojo profilio duomenų struktūra.", - "advanced-settings": "Pažangūs nustatymai", - "entities": "Subjektai", - "rule-engine": "Rule Engine", - "time-to-live": "Time-to-live", - "alarms-and-notifications": "Alarms and notifications", - "ota-files-in-bytes": "OTA files in bytes", - "ws-title": "WS", - "unlimited": "(0 - unlimited)", - "maximum-devices": "Devices maximum number", - "maximum-devices-required": "Devices maximum number is required.", - "maximum-devices-range": "Devices maximum number can't be negative", - "maximum-assets": "Assets maximum number", - "maximum-assets-required": "Assets maximum number is required.", - "maximum-assets-range": "Assets maximum number can't be negative", - "maximum-customers": "Customers maximum number", - "maximum-customers-required": "Customers maximum number is required.", - "maximum-customers-range": "Customers maximum number can't be negative", - "maximum-users": "Users maximum number", - "maximum-users-required": "Users maximum number is required.", - "maximum-users-range": "Users maximum number can't be negative", - "maximum-dashboards": "Dashboards maximum number", - "maximum-dashboards-required": "Dashboards maximum number is required.", - "maximum-dashboards-range": "Dashboards maximum number can't be negative", - "maximum-edges": "Edges maximum number", - "maximum-edges-required": "Edges maximum number is required.", - "maximum-edges-range": "Edges maximum number can't be negative", - "maximum-rule-chains": "Rule chains maximum number", - "maximum-rule-chains-required": "Rule chains maximum number is required.", - "maximum-rule-chains-range": "Rule chains maximum number can't be negative", - "maximum-integrations": "Integrations maximum number", - "maximum-integrations-required": "Integrations maximum number is required.", - "maximum-integrations-range": "Integrations maximum number can't be negative", - "maximum-converters": "Converters maximum number", - "maximum-converters-required": "Converters maximum number is required.", - "maximum-converters-range": "Converters maximum number can't be negative", - "maximum-scheduler-events": "Scheduler events maximum number", - "maximum-scheduler-events-required": "Scheduler events maximum number is required.", - "maximum-scheduler-events-range": "Scheduler events maximum number can't be negative", - "maximum-resources-sum-data-size": "Resource files sum size", - "maximum-resources-sum-data-size-required": "Resource files sum size is required.", - "maximum-resources-sum-data-size-range": "Resource files sum size can`t be negative", - "maximum-ota-packages-sum-data-size": "OTA package files sum size", - "maximum-ota-package-sum-data-size-required": "OTA package files sum size is required.", - "maximum-ota-package-sum-data-size-range": "OTA package files sum size can`t be negative", - "rest-requests-for-tenant": "REST requests for tenant", - "transport-tenant-telemetry-msg-rate-limit": "Transport tenant telemetry messages", - "transport-tenant-telemetry-data-points-rate-limit": "Transport tenant telemetry data points", - "transport-device-msg-rate-limit": "Transport device messages", - "transport-device-telemetry-msg-rate-limit": "Transport device telemetry messages", - "transport-device-telemetry-data-points-rate-limit": "Transport device telemetry data points", - "tenant-entity-export-rate-limit": "Entity version creation", - "tenant-entity-import-rate-limit": "Entity version load", - "tenant-notification-request-rate-limit": "Notification requests", - "tenant-notification-requests-per-rule-rate-limit": "Notification requests per notification rule", - "integration-msgs-per-tenant-rate-limit": "Tenant integration messages", - "integration-msgs-per-device-rate-limit": "Device integration messages", - "max-transport-messages": "Transport messages maximum number", - "max-transport-messages-required": "Transport messages maximum number is required.", - "max-transport-messages-range": "Transport messages maximum number can't be negative", - "max-transport-data-points": "Transport data points maximum number ", - "max-transport-data-points-required": "Transport data points maximum number is required.", - "max-transport-data-points-range": "Transport data points maximum number can't be negative", - "max-r-e-executions": "Rule Engine executions maximum number", - "max-r-e-executions-required": "Rule Engine executions maximum number is required.", - "max-r-e-executions-range": "Rule Engine executions maximum number can't be negative", - "max-j-s-executions": "JavaScript executions maximum number ", - "max-j-s-executions-required": "JavaScript executions maximum number is required.", - "max-j-s-executions-range": "JavaScript executions maximum number can't be negative", - "max-d-p-storage-days": "Data points storage days maximum number", - "max-d-p-storage-days-required": "Data points storage days maximum number is required.", - "max-d-p-storage-days-range": "Data points storage days maximum number can't be negative", - "default-storage-ttl-days": "Storage TTL days by default", - "default-storage-ttl-days-required": "Storage TTL days by default is required.", - "default-storage-ttl-days-range": "Storage TTL days by default can't be negative", - "alarms-ttl-days": "Alarms TTL days", - "alarms-ttl-days-required": "Alarms TTL days required", - "alarms-ttl-days-days-range": "Alarms TTL days can't be negative", - "rpc-ttl-days": "RPC TTL days", - "rpc-ttl-days-required": "RPC TTL days required", - "rpc-ttl-days-days-range": "RPC TTL days can't be negative", - "max-rule-node-executions-per-message": "Rule node per message executions maximum number", - "max-rule-node-executions-per-message-required": "MRule node per message executions maximum number is required.", - "max-rule-node-executions-per-message-range": "Rule node per message executions maximum number can't be negative", - "max-emails": "Emails sent maximum number", - "max-emails-required": "Emails sent maximum number is required.", - "max-emails-range": "Emails sent maximum number can't be negative", - "sms-enabled": "SMS enabled", - "max-sms": "SMS sent maximum number", - "max-sms-required": "SMS sent maximum number is required.", - "max-sms-range": "SMS sent maximum number can't be negative", - "max-created-alarms": "Alarms created maximum number", - "max-created-alarms-required": "Alarms created maximum number is required.", - "max-created-alarms-range": "Alarms created maximum number be negative", - "no-queue": "No Queue configured", - "add-queue": "Add Queue", - "queues-with-count": "Queues ({{count}})", - "tenant-rest-limits": "REST requests for tenant", - "customer-rest-limits": "REST requests for customer", - "incorrect-pattern-for-rate-limits": "The format is comma separated pairs of capacity and period (in seconds) with a colon between, e.g. 100:1,2000:60", - "too-small-value-zero": "The value must be bigger than 0", - "too-small-value-one": "The value must be bigger than 1", - "queue-size-is-limited-by-system-configuration": "The size of the queue is also limited by the system configuration.", - "cassandra-tenant-limits-configuration": "Cassandra query for tenant", - "ws-limit-max-sessions-per-tenant": "Sessions per tenant maximum number", - "ws-limit-max-sessions-per-customer": "Sessions per customer maximum number", - "ws-limit-max-sessions-per-regular-user": "Sessions per regular user maximum number", - "ws-limit-max-sessions-per-public-user": "Sessions per public user maximum number", - "ws-limit-queue-per-session": "Message queue per session maximum size", - "ws-limit-max-subscriptions-per-tenant": "Subscriptions per tenant maximum number", - "ws-limit-max-subscriptions-per-customer": "Subscriptions per customer maximum number", - "ws-limit-max-subscriptions-per-regular-user": "Subscriptions per regular user maximum number", - "ws-limit-max-subscriptions-per-public-user": "Subscriptions per public user maximum number", - "ws-limit-updates-per-session": "WS updates per session", - "rate-limits": { - "add-limit": "Add limit", - "advanced-settings": "Advanced settings", - "edit-limit": "Edit limit", - "edit-transport-tenant-msg-title": "Edit transport tenant messages rate limits", - "edit-transport-tenant-telemetry-msg-title": "Edit transport tenant telemetry messages rate limits", - "edit-transport-tenant-telemetry-data-points-title": "Edit transport tenant telemetry data points rate limits", - "edit-transport-device-msg-title": "Edit transport device messages rate limits", - "edit-transport-device-telemetry-msg-title": "Edit transport device telemetry messages rate limits", - "edit-transport-device-telemetry-data-points-title": "Edit transport device telemetry data points rate limits", - "edit-tenant-rest-limits-title": "Edit REST requests for tenant rate limits", - "edit-customer-rest-limits-title": "Edit REST requests for customer rate limits", - "edit-ws-limit-updates-per-session-title": "Edit WS updates per session rate limits", - "edit-cassandra-tenant-limits-configuration-title": "Edit Cassandra query for tenant rate limits", - "edit-tenant-entity-export-rate-limit-title": "Edit entity version creation rate limits", - "edit-tenant-entity-import-rate-limit-title": "Edit entity version load rate limits", - "edit-tenant-notification-request-rate-limit-title": "Edit notification requests rate limits", - "edit-tenant-notification-requests-per-rule-rate-limit-title": "Edit notification requests per notification rule rate limits", - "edit-integration-msgs-per-tenant-rate-limit-title": "Edit integration messages per tenant rate limits", - "edit-integration-msgs-per-device-rate-limit-title": "Edit integration messages per device rate limits", - "messages-per": "messages per", - "not-set": "Not set", - "number-of-messages": "Number of messages", - "number-of-messages-required": "Number of messages is required.", - "number-of-messages-min": "Minimum value is 1.", - "preview": "Preview", - "per-seconds": "Per seconds", - "per-seconds-required": "Time rate is required.", - "per-seconds-min": "Minimum value is 1.", - "rate-limits": "Rate limits", - "remove-limit": "Remove limit", - "transport-tenant-msg": "Transport tenant messages", - "transport-tenant-telemetry-msg": "Transport tenant telemetry messages", - "transport-tenant-telemetry-data-points": "Transport tenant telemetry data points", - "transport-device-msg": "Transport device messages", - "transport-device-telemetry-msg": "Transport device telemetry messages", - "transport-device-telemetry-data-points": "Transport device telemetry data points", - "sec": "sec" - } + "wind-speed-direction": { + "layout": "Išdėstymas", + "layout-default": "Numatytasis", + "layout-advanced": "Išplėstinis", + "layout-simplified": "Supaprastintas", + "values": "Reikšmės", + "wind-direction": "Vėjo kryptis", + "center-value": "Centrinė reikšmė", + "icon": "Piktograma", + "arrow": "Rodyklė", + "ticks": "Padalos", + "labels-type": "Etikečių tipas", + "directional-names": "Krypties pavadinimai", + "degrees": "Laipsniai", + "major-ticks": "Pagrindinės padalos", + "minor-ticks": "Smulkios padalos", + "wind-speed-direction-card-style": "Vėjo greičio ir krypties kortelės stilius", + "ticks-color": "Padalų spalva", + "ticks-labels-type": "Padalų etikečių tipas", + "arrow-color": "Rodyklės spalva" }, - "timeinterval": { - "seconds-interval": "{ seconds, plural, =1 {1 sekundė} other {# sekundės} }", - "minutes-interval": "{ minutes, plural, =1 {1 minutė} other {# minutės} }", - "hours-interval": "{ hours, plural, =1 {1 valanda} other {# valandos} }", - "days-interval": "{ days, plural, =1 {1 diena} other {# dienos} }", - "days": "Dienos", - "hours": "Valandos", - "minutes": "Minutės", - "seconds": "Sekundės", - "advanced": "Patyręs vartotojas", - "predefined": { - "yesterday": "Yesterday", - "day-before-yesterday": "Day before yesterday", - "this-day-last-week": "This day last week", - "previous-week": "Previous week (Sun - Sat)", - "previous-week-iso": "Previous week (Mon - Sun)", - "previous-month": "Previous month", - "previous-quarter": "Previous quarter", - "previous-half-year": "Previous half year", - "previous-year": "Previous year", - "current-hour": "Current hour", - "current-day": "Current day", - "current-day-so-far": "Current day so far", - "current-week": "Current week (Sun - Sat)", - "current-week-iso": "Current week (Mon - Sun)", - "current-week-so-far": "Current week so far (Sun - Sat)", - "current-week-iso-so-far": "Current week so far (Mon - Sun)", - "current-month": "Current month", - "current-month-so-far": "Current month so far", - "current-quarter": "Current quarter", - "current-quarter-so-far": "Current quarter so far", - "current-half-year": "Current half year", - "current-half-year-so-far": "Current half year so far", - "current-year": "Current year", - "current-year-so-far": "Current year so far" - } + "value-source": { + "value-source": "Reikšmės šaltinis", + "predefined-value": "Iš anksto nustatyta reikšmė", + "entity-attribute": "Objekto atributas", + "value": "Reikšmė", + "value-required": "Reikšmė yra privaloma.", + "key-required": "Raktas yra privalomas.", + "entity-key-required": "Objekto raktas yra privalomas.", + "source-entity-alias": "Šaltinio objekto pseudonimas", + "source-entity-attribute": "Šaltinio objekto atributas", + "type-constant": "Pastovus", + "type-latest-key": "Raktas", + "type-entity": "Objektas" }, - "timeunit": { - "milliseconds": "Milisekundės", - "seconds": "Sekundės", - "minutes": "Minutės", - "hours": "Valandos", - "days": "Dienos" - }, - "timewindow": { - "timewindow": "Laikotarpio vaizdas", - "years": "{ years, plural, =1 { metai } other {# metai } }", - "years-short": "{{ years }}m", - "months": "{ months, plural, =1 { mėnuo } other {# mėnesiai } }", - "months-short": "{{ months }}mėn", - "weeks": "{ weeks, plural, =1 { savaitė } other {# savaitės } }", - "weeks-short": "{{ weeks }}sav", - "days": "{ days, plural, =1 { diena } other {# dienos } }", - "days-short": "{{ days }}d", - "hours": "{ hours, plural, =0 { valandų } =1 {1 valanda } other {# valandos } }", - "hr": "{{ hr }} val", - "hr-short": "{{ hr }}val", - "minutes": "{ minutes, plural, =0 { minučių } =1 {1 minutė } other {# minutės } }", - "min": "{{ min }} min", - "min-short": "{{ min }}min", - "seconds": "{ seconds, plural, =0 { sekundžių } =1 {1 sekundė } other {# sekundės } }", - "sec": "{{ sec }} sek", - "sec-short": "{{ sec }}s", - "short": { - "days": "{ days, plural, =1 {1 diena } other {# dienos } }", - "hours": "{ hours, plural, =1 {1 valanda } other {# valandos } }", - "minutes": "{{minutes}} min ", - "seconds": "{{seconds}} sek " - }, - "realtime": "Realiu laiku", - "history": "istorija", - "last-prefix": "Paskutinės", - "period": "nuo {{ startTime }} iki {{ endTime }}", - "edit": "Redaguoti laikotarpio vaizdą", - "date-range": "Datų intervalas", - "for-all-time": "Viskas", - "last": "Paskutinės", - "time-period": "Laikotarpis", - "hide": "Slėpti", - "interval": "Interval", - "just-now": "Just now", - "just-now-lower": "just now", - "ago": "ago", - "style": "Timewindow style", - "icon": "Icon", - "icon-position": "Icon position", - "icon-position-left": "Left", - "icon-position-right": "Right", - "font": "Font", - "color": "Color", - "displayTypePrefix": "Display Realtime/History prefix", - "preview": "Preview" - }, - "unit": { - "millimeter": "Millimeter", - "centimeter": "Centimeter", - "angstrom": "Angstrom", - "nanometer": "Nanometer", - "micrometer": "Micrometer", - "meter": "Meter", - "kilometer": "Kilometer", - "inch": "Inch", - "foot": "Foot", - "yard": "Yard", - "mile": "Mile", - "nautical-mile": "Nautical Mile", - "astronomical-unit": "Astronomical Unit", - "reciprocal-metre": "Reciprocal Metre", - "meter-per-meter": "Meter per meter", - "steradian": "Steradian", - "thou": "Thou", - "barleycorn": "Barleycorn", - "hand": "Hand", - "chain": "Chain", - "furlong": "Furlong", - "league": "League", - "fathom": "Fathom", - "cable": "Cable", - "link": "Link", - "rod": "Rod", - "nanogram": "Nanogram", - "microgram": "Microgram", - "milligram": "Milligram", - "gram": "Gram", - "kilogram": "Kilogram", - "tonne": "Tonne", - "ounce": "Ounce", - "pound": "Pound", - "stone": "Stone", - "hundredweight-count": "Hundredweight count", - "short-tons": "Short tons", - "dalton": "Dalton", - "grain": "Grain", - "drachm": "Drachm", - "quarter": "Quarter", - "slug": "Slug", - "carat": "Carat", - "cubic-millimeter": "Cubic Millimeter", - "cubic-centimeter": "Cubic Centimeter", - "cubic-meter": "Cubic Meter/s", - "cubic-kilometer": "Cubic Kilometers", - "microliter": "Microliter", - "milliliter": "Milliliter", - "liter": "Liter", - "hectoliter": "Hectolitre", - "cubic-inch": "Cubic Inch", - "cubic-foot": "Cubic Foot", - "cubic-yard": "Cubic Yards", - "fluid-ounce": "Fluid Ounce", - "pint": "Pint", - "quart": "Quart", - "gallon": "Gallon", - "oil-barrels": "Oil Barrels", - "cubic-meter-per-kilogram": "Cubic Meter per Kilogram", - "gill": "Gill", - "hogshead": "Hogshead", - "teaspoon": "Teaspoon", - "tablespoon": "Tablespoon", - "cup": "Cup", - "celsius": "Celsius", - "kelvin": "Kelvin", - "rankine": "Rankine", - "fahrenheit": "Fahrenheit", - "percent": "Percent", - "meter-per-second": "Meter per Second", - "kilometer-per-hour": "Kilometer per Hour", - "foot-per-second": "Foot per Second", - "mile-per-hour": "Mile per Hour", - "knot": "Knot", - "millimeters-per-minute": "Millimeters per minute", - "kilometer-per-hour-squared": "Kilometer per hour squared", - "foot-per-second-squared": "Foot per second squared", - "pascal": "Pascal", - "kilopascal": "Kilopascal", - "megapascal": "Megapascal", - "gigapascal": "Gigapascal", - "millibar": "Millibar", - "bar": "Bar", - "kilobar": "Kilobar", - "newton": "Newton", - "newton-meter": "Newton meter", - "foot-pounds": "Foot-pounds", - "inch-pounds": "Inch-pounds", - "newton-per-meter": "Newton per meter", - "atmospheres": "Atmospheres", - "pounds-per-square-inch": "Pounds per Square Inch", - "torr": "Torr", - "inches-of-mercury": "Inches of Mercury", - "pascal-per-square-meter": "Pascal per Square Meter", - "pound-per-square-inch": "Pound per Square Inch", - "newton-per-square-meter": "Newton per Square Meter", - "kilogram-force-per-square-meter": "Kilogram-force per Square Meter", - "pascal-per-square-centimeter": "Pascal per Square Centimeter", - "ton-force-per-square-inch": "Ton-force per Square Inch", - "kilonewton-per-square-meter": "Kilonewton per Square Meter", - "newton-per-square-millimeter": "Newton per Square Millimeter", - "microjoule": "Microjoule", - "millijoule": "Millijoule", - "joule": "Joule", - "kilojoule": "Kilojoule", - "megajoule": "Megajoule", - "gigajoule": "Gigajoule", - "watt-hour": "Watt-hour", - "kilowatt-hour": "Kilowatt-hour", - "electron-volts": "Electron volts", - "joules-per-coulomb": "Joules per Coulomb", - "british-thermal-unit": "British Thermal Units", - "foot-pound": "Foot-pound", - "calorie": "Calorie", - "small-calorie": "Small Calorie", - "kilocalorie": "Kilocalorie", - "joule-per-kelvin": "Joule per Kelvin", - "joule-per-kilogram-kelvin": "Joule per Kilogram-Kelvin", - "joule-per-kilogram": "Joule per Kilogram", - "watt-per-meter-kelvin": "Watt per Meter-Kelvin", - "joule-per-cubic-meter": "Joule per Cubic Meter", - "therm": "Therm", - "electric-dipole-moment": "Electric Dipole Moment", - "magnetic-dipole-moment": "Magnetic Dipole Moment", - "debye": "Debye", - "coulomb-per-square-meter-per-volt": "Coulomb per Square Meter per Volt", - "milliwatt": "Milliwatt", - "microwatt": "Microwatt", - "watt": "Watt", - "kilowatt": "Kilowatt", - "megawatt": "Megawatt", - "gigawatt": "Gigawatt", - "metric-horsepower": "Metric Horsepower", - "milliwatt-per-square-centimeter": "Milliwatts per square centimeter", - "watt-per-square-centimeter": "Watts per square centimeter", - "kilowatt-per-square-centimeter": "Kilowatts per square centimeter", - "milliwatt-per-square-meter": "Milliwatts per square meter", - "watt-per-square-meter": "Watts per square meter", - "kilowatt-per-square-meter": "Kilowatts per square meter", - "watt-per-square-inch": "Watts per square inch", - "kilowatt-per-square-inch": "Kilowatts per square inch", - "horsepower": "Horsepower", - "btu-per-hour": "British thermal units/hour", - "coulomb": "Coulomb", - "millicoulomb": "Millicoulombs", - "microcoulomb": "Microcoulomb", - "picocoulomb": "Picocoulomb", - "coulomb-per-meter": "Coulomb per meter", - "coulomb-per-cubic-meter": "Coulomb per Cubic Meter", - "coulomb-per-square-meter": "Coulomb per Square Meter", - "square-millimeter": "Square Millimeter", - "square-centimeter": "Square Centimeter", - "square-meter": "Square Meter", - "hectare": "Hectare", - "square-kilometer": "Square Kilometer", - "square-inch": "Square Inch", - "square-foot": "Square Foot", - "square-yard": "Square Yard", - "acre": "Acre", - "square-mile": "Square Mile", - "are": "Are", - "barn": "Barn", - "circular-inch": "Circular Inch", - "milliampere-hour": "Milliampere-hour", - "milliampere-hour-tags": "electric current, current flow, electric charge, current capacity, flow of electricity, electrical flow, milliampere-hour, milliampere-hours, mAh", - "ampere-hours": "Ampere-hours", - "ampere-hours-tags": "electric current, current flow, electric charge, current capacity, flow of electricity, electrical flow, ampere, ampere-hours, Ah", - "kiloampere-hours": "Kiloampere-hours", - "kiloampere-hours-tags": "electric current, current flow, electric charge, current capacity, flow of electricity, electrical flow, kiloampere-hours, kiloampere-hour, kAh", - "nanoampere": "Nanoampere", - "nanoampere-tags": "current, amperes, nanoampere, nA", - "picoampere": "Picoampere", - "picoampere-tags": "current, amperes, picoampere, pA", - "microampere": "Microampere", - "microampere-tags": "electric current, microampere, microamperes, μA", - "milliampere": "Milliampere", - "milliampere-tags": "electric current, milliampere, milliamperes, mA", - "ampere": "Ampere", - "ampere-tags": "electric current, current flow, flow of electricity, electrical flow, ampere, amperes, amperage, A", - "kiloamperes": "Kiloamperes", - "kiloamperes-tags": "electric current, current flow, kiloamperes, kA", - "microampere-per-square-centimeter": "Microampere per square centimeter", - "microampere-per-square-centimeter-tags": "Current density, microampere per square centimeter, µA/cm²", - "ampere-per-square-meter": "Ampere per Square Meter", - "ampere-per-square-meter-tags": "current density, current per unit area, ampere per square meter, A/m²", - "ampere-per-meter": "Ampere per Meter", - "ampere-per-meter-tags": "magnetic field strength, magnetic field intensity, ampere per meter, A/m", - "oersted": "Oersted", - "oersted-tags": "magnetic field, oersted, Oe", - "bohr-magneton": "Bohr Magneton", - "bohr-magneton-tags": "atomic physics, magnetic moment, bohr magneton, μB", - "ampere-meter-squared": "Ampere-Meter Squared", - "ampere-meter-squared-tags": "magnetic moment, dipole moment, ampere-meter squared, A·m²", - "ampere-meter": "Ampere-Meter", - "ampere-meter-tags": "magnetic field, current loop, ampere-meter, A·m", - "nanovolt": "Nanovolt", - "picovolt": "Picovolt", - "millivolts": "Millivolts", - "microvolts": "Microvolts", - "volt": "Volt", - "kilovolts": "Kilovolts", - "dbmV": "dBmV", - "volt-meter": "Volt-Meter", - "kilovolt-meter": "Kilovolt-Meter", - "megavolt-meter": "Megavolt-Meter", - "microvolt-meter": "Microvolt-Meter", - "millivolt-meter": "Millivolt-Meter", - "nanovolt-meter": "Nanovolt-Meter", - "ohm": "Ohm", - "microohm": "Microohm", - "milliohm": "Milliohm", - "kilohm": "Kilohm", - "megohm": "Megohm", - "gigohm": "Gigohm", - "hertz": "Hertz", - "kilohertz": "Kilohertz", - "megahertz": "Megahertz", - "gigahertz": "Gigahertz", - "rpm": "Revolutions Per Minute", - "candela-per-square-meter": "Candela per square meter", - "candela": "Candela", - "lumen": "Lumen", - "lux": "Lux", - "foot-candle": "Foot-candle", - "lumen-per-square-meter": "Lumen per square meter", - "lux-second": "Lux second", - "lumen-second": "Lumen second", - "lumens-per-watt": "Lumens per watt", - "absorbance": "Absorbance", - "mole": "Mole", - "nanomole": "Nanomole", - "micromole": "MicroMole", - "millimole": "Millimole", - "kilomole": "Kilomole", - "mole-per-cubic-meter": "Mole per Cubic Meter", - "rssi": "RSSI", - "ppm": "Parts Per Million", - "ppb": "Parts Per Billion", - "micrograms-per-cubic-meter": "Micrograms per Cubic Meter", - "aqi": "AQI", - "gram-per-cubic-meter": "Gram per cubic meter", - "gram-per-kilogram": "Specific Humidity", - "millimeters-per-second": "Millimeters per second", - "neper": "Neper", - "bel": "Bel", - "decibel": "Decibel", - "meters-per-second-squared": "Meters per second squared", - "becquerel": "Becquerel", - "curie": "Curie", - "gray": "Gray", - "sievert": "Sievert", - "roentgen": "Roentgen", - "cps": "Counts per Second", - "rad": "Rad", - "rem": "Rem", - "dps": "Disintegrations per second", - "rutherford": "Rutherford", - "coulombs-per-kilogram": "Coulombs per kilogram", - "becquerels-per-cubic-meter": "Becquerels per cubic meter", - "curies-per-liter": "Curies per liter", - "becquerels-per-second": "Becquerels per second", - "curies-per-second": "Curies per second", - "gy-per-second": "Gray per Second", - "watt-per-steradian": "Watt per Steradian", - "watt-per-square-metre-steradian": "Watt per Square Metre-Steradian", - "ph-level": "pH Level", - "turbidity": "Turbidity", - "mg-per-liter": "Milligrams per liter", - "microsiemens-per-centimeter": "Microsiemens per centimeter", - "millisiemens-per-meter": "Millisiemens per meter", - "siemens-per-meter": "Siemens per meter", - "kilogram-per-cubic-meter": "Kilogram per cubic meter", - "gram-per-cubic-centimeter": "Gram per cubic centimeter", - "kilogram-per-square-meter": "Kilogram per square metre", - "milligram-per-milliliter": "Milligram per milliliter", - "pound-per-cubic-foot": "Pound per cubic foot", - "ounces-per-cubic-inch": "Ounces per cubic inch", - "tons-per-cubic-yard": "Tons per cubic yard", - "particle-density": "Particle density", - "kilometers-per-liter": "Kilometers per liter", - "miles-per-gallon": "Miles per gallon", - "liters-per-100-km": "Liters per 100 km", - "gallons-per-mile": "Gallons per mile", - "liters-per-hour": "Liters per hour", - "gallons-per-hour": "Gallons per hour", - "beats-per-minute": "Beats per minute", - "millimeters-of-mercury": "Millimeters of mercury", - "milligrams-per-deciliter": "Milligrams per deciliter", - "g-force": "G-force", - "kilonewton": "Kilonewton", - "kilogram-force": "Kilogram-Force", - "pound-force": "Pound-Force", - "kilopound-force": "Kilopound-Force", - "dyne": "Dyne", - "poundal": "Poundal", - "kip": "Kip", - "gal": "Gal", - "gravity": "Gravity", - "hectopascal": "Hectopascal", - "atmosphere": "Atmosphere", - "millibars": "Millibars", - "inch-of-mercury": "One inch of mercury", - "richter-scale": "Richter Scale", - "second": "Second", - "minute": "Minute", - "hour": "Hour", - "day": "Day", - "week": "Week", - "month": "Month", - "year": "Year", - "cubic-foot-per-minute": "Cubic Foot Per Minute", - "cubic-meters-per-hour": "Cubic Meters Per Hour", - "cubic-meters-per-second": "Cubic Meters Per Second", - "liter-per-second": "Liter Per Second", - "liter-per-minute": "Liter Per Minute", - "gallons-per-minute": "Gallons Per Minute", - "cubic-foot-per-second": "Cubic foot per second", - "milliliters-per-minute": "Milliliters per minute", - "bit": "Bit", - "byte": "Byte", - "kilobyte": "Kilobyte", - "megabyte": "Megabyte", - "gigabyte": "Gigabyte", - "terabyte": "Terabyte", - "petabyte": "Petabyte", - "exabyte": "Exabyte", - "zettabyte": "Zettabyte", - "yottabyte": "Yottabyte", - "bit-per-second": "Bit per second", - "kilobit-per-second": "Kilobit per second", - "megabit-per-second": "Megabit per second", - "gigabit-per-second": "Gigabit per second", - "terabit-per-second": "Terabit per second", - "byte-per-second": "Byte per second", - "kilobyte-per-second": "Kilobyte per second", - "megabyte-per-second": "Megabyte per second", - "gigabyte-per-second": "Gigabyte per second", - "degree": "Degree", - "radian": "Radian", - "gradian": "Gradian", - "mil": "Mil", - "revolution": "Revolution", - "siemens": "Siemens", - "millisiemens": "Millisiemens", - "microsiemens": "Microsiemens", - "kilosiemens": "Kilosiemens", - "megasiemens": "Megasiemens", - "gigasiemens": "Gigasiemens", - "farad": "Farad", - "millifarad": "Millifarad", - "microfarad": "Microfarad", - "nanofarad": "Nanofarad", - "picofarad": "Picofarad", - "kilofarad": "Kilofarad", - "megafarad": "Megafarad", - "gigafarad": "Gigafarad", - "terfarad": "Terfarad", - "farad-per-meter": "Farad per Meter", - "tesla": "Tesla", - "gauss": "Gauss", - "kilogauss": "Kilogauss", - "millitesla": "Millitesla", - "microtesla": "Microtesla", - "nanotesla": "Nanotesla", - "kilotesla": "Kilotesla", - "megatesla": "Megatesla", - "millitesla-square-meters": "millitesla square meters", - "gamma": "Gamma", - "lambda": "Lambda", - "square-meter-per-second": "Square meter per second", - "square-centimeter-per-second": "Square centimeter per second", - "stoke": "Stoke", - "centistokes": "Centistokes", - "square-foot-per-second": "Square foot per second", - "square-inch-per-second": "Square inch per second", - "pascal-second": "Pascal-second", - "centipoise": "Centipoise", - "poise": "Poise", - "reynolds": "Reynolds", - "pound-per-foot-hour": "Pound per foot-hour", - "newton-second-per-square-meter": "Newton second per square meter", - "dyne-second-per-square-centimeter": "Dyne second per square centimeter", - "kilogram-per-meter-second": "Kilogram per meter-second", - "tesla-square-meters": "Tesla square meters", - "maxwell": "Maxwell", - "tesla-per-meter": "Tesla per Meter", - "gauss-per-centimeter": "Gauss per Centimeter", - "weber": "Weber", - "microweber": "Microweber", - "milliweber": "Milliweber", - "gauss-square-centimeter": "Gauss-Square Centimeter", - "kilogauss-square-centimeter": "Kilogauss-Square Centimeter", - "henry": "Henry", - "millihenry": "Millihenry", - "microhenry": "Microhenry", - "nanohenry": "Nanohenry", - "henry-per-meter": "Henry per Meter", - "tesla-meter-per-ampere": "Tesla Meter per Ampere", - "gauss-per-oersted": "Gauss per Oersted", - "kilogram-per-mole": "Kilogram per mole", - "gram-per-mole": "Gram per mole", - "milligram-per-mole": "Milligram per mole", - "joule-per-mole": "Joule per Mole", - "joule-per-mole-kelvin": "Joule per Mole-Kelvin", - "millivolts-per-meter": "Millivolts per meter", - "volts-per-meter": "Volts per meter", - "kilovolts-per-meter": "Kilovolts per meter", - "radian-per-second": "Radian per second", - "radian-per-second-squared": "Radian per second squared", - "revolutions-per-minute-per-second": "Angular acceleration", - "revolutions-per-minute-per-second-squared": "Angular Acceleration", - "deg-per-second": "deg/s", - "degrees-brix": "Degrees Brix", - "katal": "Katal", - "katal-per-cubic-metre": "Katal per Cubic Metre" - }, - "user": { - "all": "Visi", - "all-users": "Visi vartotojai", - "groups": "Grupės", - "user": "Vartotojas", - "users": "Vartotojai", - "management": "Vartotojų valdymas", - "customer-users": "Kliento vartotojai", - "tenant-admins": "Valdytojų administratoriai", - "sys-admin": "Sistemos administratoriai", - "tenant-admin": "Valdytojo administratoriai", - "customer": "Klientas", - "anonymous": "Anonimas", - "add": "Pridėti vartotoją", - "delete": "Panaikinti vartotoją", - "add-user-text": "Pridėti naują vartotoją", - "no-users-text": "Vartotojų nėra", - "user-details": "Informacija apie vartotoją", - "delete-users": "Panaikinti vartotojus", - "delete-user-title": "Ar tikrai norite panaikinti vartotoją '{{userEmail}}'?", - "delete-user-text": "Būkite dėmesingi, po patvirtinimo vartotojas ir visa su juo susijusi informacija bus panaikinta.", - "delete-users-title": "Ar tikrai norite panaikinti { count, plural, =1 {1 vatotoją} other {# vartotojus} }?", - "delete-users-action-title": "Panaikinti { count, plural, =1 {1 vartotoją} other {# vartotojus} }", - "delete-users-text": "Būkite dėmesingi, po patvirtinimo visi pasirinkti vartotojai ir su jis susijusi informacija bus panaikinta.", - "activation-email-sent-message": "Aktyvinimo el. laiškas sėkmingai išsiųstas!", - "resend-activation": "Iš naujo siųsti aktyvinimą", - "email": "El. pašto adresas", - "email-required": "El. pašto adresas būtinas.", - "invalid-email-format": "Neteisingas el. pašto adreso formatas.", - "first-name": "Vardas", - "last-name": "Pavardė", - "description": "Aprašymas", - "default-dashboard": "Pagrindinis skydelis", - "always-fullscreen": "Visada per visą ekraną", - "select-user": "Pasirinkti vartotoją", - "no-users-matching": "Vartotojų, atitinkančių'{{entity}}' nėra.", - "user-required": "Vartotojas būtinas", - "activation-method": "Aktyvavimo būdas", - "display-activation-link": "Rodyti aktyvavimo nuorodą", - "send-activation-mail": "Siųsti aktyvavimo el. laišką", - "activation-link": "Vartotojo aktyvavimo nuoroda", - "activation-link-text": "Vartotojui aktyvuoti, paspauskite nuorodą :", - "copy-activation-link": "Kopijuoti aktyvavimo nuorodą", - "activation-link-copied-message": "Vartotojo aktyvavimo nuoroda nukopijuota į iškarpinę", - "details": "Informacija", - "login-as-tenant-admin": "Prisijunkti kaip valdytojo administratorius", - "login-as-customer-user": "Prisijunkti kaip kliento vartotojas", - "select-group-to-add": "Pasirinkite grupę, kuriai priskirti pažymėtus vartotojus", - "select-group-to-move": "Pasirinkite grupę, į kurią perkelti pažymėtus vartotojus", - "remove-users-from-group": "Ar tikrai norite pašalinti { count, plural, =1 {1 vartotoją} other {# vartotojus} } iš grupės '{{entityGroup}}'?", - "group": "Vartotojų grupė", - "list-of-groups": "{ count, plural, =1 {Viena vartotojų grupė} other {# Vartotojų grupių sąrašas} }", - "group-name-starts-with": "Vartotojų grupės, kurios prasideda '{{prefix}}'", - "search": "Vartotojų paieška", - "selected-users": "Pasirinkta { count, plural, =1 {1 vartotojas} other {# vartotojai} }", - "disable-account": "Išjungti vartotojo paskyrą", - "enable-account": "Įjungti vartotojo paskyrą", - "enable-account-message": "Vartotojo paskyra sėkmingai įjungta!", - "disable-account-message": "Vartotojo paskyra sėkmingai išjungta!", - "copyId": "Kopijuoti vartotojo Id", - "idCopiedMessage": "Vartotojo Id nukopiuotas į iškarpinę", - "user-list": "Vartotojų sąrašas", - "user-list-required": "Vartotojų sąrašas būtinas" - }, - "value": { - "type": "Reikšmės tipas", - "string": "Tekstas", - "string-value": "Tekstinė informacija", - "string-value-required": "Tekstinė informacija būtina", - "integer": "Sveikasis skaičius", - "integer-value": "Sveikojo skaičiaus reikšmė", - "integer-value-required": "Sveikojo skaičiaus reikšmė būtina", - "invalid-integer-value": "Sveikojo skaičiaus reikšmė neteisinga", - "double": "Realusis skaičius", - "double-value": "Realiojo skaičiaus reikšmė", - "double-value-required": "Realiojo skaičiaus reikšmė būtina", - "boolean": "Loginis", - "boolean-value": "Loginė reikšmė", - "false": "Netiesa", - "true": "Tiesa", - "long": "Sveikas skaičius", - "json": "JSON", - "json-value": "JSON reikšmė", - "json-value-invalid": "Neteisingas JSON reikšmės formatas", - "json-value-required": "JSON reikšmė būtina." - }, - "version-control": { - "version-control": "Version control", - "management": "Version control management", - "search": "Search versions", - "branch": "Branch", - "default": "Default", - "select-branch": "Select branch", - "branch-required": "Branch is required", - "create-entity-version": "Create entity version", - "version-name": "Version name", - "version-name-required": "Version name is required", - "author": "Author", - "export-relations": "Export relations", - "export-attributes": "Export attributes", - "export-credentials": "Export credentials", - "export-group-entities": "Export group entities", - "export-roles": "Export roles", - "entity-versions": "Entity versions", - "versions": "Versions", - "created-time": "Created time", - "version-id": "Version ID", - "no-entity-versions-text": "No entity versions found", - "no-versions-text": "No versions found", - "copy-full-version-id": "Copy full version id", - "create-version": "Create version", - "creating-version": "Creating version... Please wait", - "nothing-to-commit": "No changes to commit", - "restore-version": "Restore version", - "restore-entity-from-version": "Restore entity from version '{{versionName}}'", - "restoring-entity-version": "Restoring entity version... Please wait", - "load-relations": "Load relations", - "load-attributes": "Load attributes", - "load-credentials": "Load credentials", - "load-group-entities": "Load group entities", - "load-roles": "Load roles", - "compare-with-current": "Compare with current", - "diff-entity-with-version": "Diff with entity version '{{versionName}}'", - "previous-difference": "Previous Difference", - "next-difference": "Next Difference", - "current": "Current", - "differences": "{ count, plural, =1 {1 difference} other {# differences} }", - "create-entities-version": "Create entities version", - "default-sync-strategy": "Default sync strategy", - "sync-strategy-merge": "Merge", - "sync-strategy-overwrite": "Overwrite", - "entities-to-export": "Entities to export", - "entities-to-restore": "Entities to restore", - "sync-strategy": "Sync strategy", - "all-entities": "All entities", - "no-entities-to-export-prompt": "Please specify entities to export", - "no-entities-to-restore-prompt": "Please specify entities to restore", - "add-entity-type": "Add entity type", - "remove-all": "Remove all", - "version-create-result": "{ added, plural, =0 {No entities} =1 {1 entity} other {# entities} } added.
{ modified, plural, =0 {No entities} =1 {1 entity} other {# entities} } modified.
{ removed, plural, =0 {No entities} =1 {1 entity} other {# entities} } removed.", - "remove-other-entities": "Remove other entities", - "find-existing-entity-by-name": "Find existing entity by name", - "restore-entities-from-version": "Restore entities from version '{{versionName}}'", - "restoring-entities-from-version": "Restoring entities... Please wait", - "no-entities-restored": "No entities restored", - "created": "{{created}} created", - "updated": "{{updated}} updated", - "deleted": "{{deleted}} deleted", - "groups-created": "{ created, plural, =1 {1 group} other {# groups} } created", - "groups-updated": "{ updated, plural, =1 {1 group} other {# groups} } updated", - "groups-deleted": "{ deleted, plural, =1 {1 group} other {# groups} } deleted", - "remove-other-entities-confirm-text": "Be careful! This will permanently delete all current entities
not present in the version you want to restore.

Please type \"remove other entities\" to confirm.", - "auto-commit-to-branch": "auto-commit to {{ branch }} branch", - "default-create-entity-version-name": "{{entityName}} update", - "sync-strategy-merge-hint": "Creates or updates selected entities in the repository. All other repository entities are not modified.", - "sync-strategy-overwrite-hint": "Creates or updates selected entities in the repository. All other repository entities are deleted.", - "device-credentials-conflict": "Failed to load the device with external id {{entityId}}
due to the same credentials are already present in the database for another device.
Please consider disabling the load credentials setting in the restore form.", - "missing-referenced-entity": "Failed to load the {{sourceEntityTypeName}} with external id {{sourceEntityId}}
because it references missing {{targetEntityTypeName}} with id {{targetEntityId}}.", - "add-entity-groups": "Add entity groups", - "entity-groups": "Entity groups", - "integration-routing-key-conflict": "Failed to load the integration with external id {{entityId}}
due to the same integration key is already present in the database for another integration.
Please consider enabling the auto-generate integration key setting in the restore form.", - "auto-generate-integration-key": "Auto-generate integration key", - "runtime-failed": "Failed: {{message}}", - "auto-commit-settings-read-only-hint": "Auto-commit feature doesn't work with enabled read-only option in Repository settings." - }, - "widget": { - "widget-library": "Valdiklių galerija", - "widget-bundle": "Valdiklių rinkinys", - "all-bundles": "Visi rinkiniai", - "select-widgets-bundle": "Pasirinkti valdiklių rinkinį", - "widgets": "Valdikliai", - "all-widgets": "Visi valdikliai", - "widget": "Valdiklis", - "select-widget": "Pasirinkti valdiklį", - "no-widgets-matching": "Valdiklių atitinkančių '{{entity}}' nėra.", - "no-widgets": "Valdiklių dar nėra", - "no-widgets-text": "Valdiklių nėra", - "management": "Valdiklių valdymas", - "editor": "Valdiklių redaktorius", - "widget-type-not-found": "Įkeliant valdiklio konfigūraciją kilo klaidų.
Gali būti, kad\n toks valdiklio tipas panaikintas.", - "widget-type-load-error": "Valdiklis neįkeltas, nes iškilo klaidų:", - "remove": "Panaikinti valdiklį", - "delete": "Panaikinti valdiklį", - "edit": "Redaguoti valdiklį", - "edit-widget-type": "Redaguoti valdikliį", - "remove-widget-title": "Ar tikrai norite panaikinti valdiklį '{{widgetTitle}}'?", - "remove-widget-text": "Būkite dėmesingi, po patvirtinimo valdiklis ir visa su juo susijusi informacija bus pašalinta.", - "timeseries": "Telemetrija", - "search-data": "Duomenų paieška", - "no-data-found": "Duomenų nėra", - "latest": "Naujausios reikšmės", - "rpc": "Valdymo valdiklis", - "alarm": "Įspėjimų valdiklis", - "static": "Statinis valdiklis", - "select-widget-type": "Pasirinkite valdiklio tipą", - "missing-widget-title-error": "Valdiklio pavadinimas būtinas!", - "widget-saved": "Valdiklis išsaugotas", - "unable-to-save-widget-error": "Valdiklio išsaugoti negalima! Valdiklyje yra klaidų!", - "save": "Valdiklis išsaugotas", - "saveAs": "valdiklį išsaugoti kaip", - "move": "Perkelti valdiklį", - "save-widget-type-as": "Valdiklį išsaugoti kaip", - "save-widget-type-as-text": "Įrašykite naują valdiklio pavadinimą", - "toggle-fullscreen": "Perjungti į viso ekrano režimą", - "run": "Paleisti valdiklį", - "widget-title": "Pavadinimas", - "title": "Pavadinimas", - "title-required": "Valdiklio pavadinimas būtinas.", - "title-max-length": "Pavadinimas negali viršyti 256 simbolių", - "system": "Sisteminis", - "type": "Tipas", - "resources": "Resursai", - "resource-url": "JavaScript/CSS URL", - "remove-resource": "Panaikinti resursą", - "add-resource": "Pridėti resursą", - "html": "HTML", - "tidy": "Tidy", - "css": "CSS", - "settings-schema": "Nustatymų schema", - "datakey-settings-schema": "Duomenų raktų nustatymų schema", - "latest-datakey-settings-schema": "Latest data key settings schema", - "widget-settings": "Valdiklio nustatymai", - "description": "Aprašymas", - "image-preview": "Paveiksliuko peržiūra", - "settings-form-selector": "Settings form selector", - "data-key-settings-form-selector": "Data key settings form selector", - "latest-data-key-settings-form-selector": "Latest data key settings form selector", - "all": "All", - "actual": "Actual", - "deprecated": "Pasenęs", - "has-basic-mode": "Has basic mode", - "basic-mode-form-selector": "Basic mode form selector", - "basic-mode": "Basic", - "advanced-mode": "Advanced", - "javascript": "Javascript", - "js": "JS", - "remove-widget-type-title": "Ar tikrai norite pašalinti valdiklį '{{widgetName}}'?", - "remove-widget-type-text": "Būkite dėmesingi, po patvirtinimo valdiklis ir visa su juo susijusi informacija bus pašalinta.", - "remove-widget-type": "Panaikinti valdiklį", - "widget-types": "Valdikliai", - "delete-widget-type-title": "Ar tikrai norite panaikinti valdiklį '{{widgetTypeName}}'?", - "delete-widget-type-text": "Būkite dėmesingi, po patvirtinimo valdiklis ir visa su juo susijusi informacija bus pašalinta.", - "delete-widget-types-title": "Ar tikrai norite panaikinti { count, plural, =1 {1 valdiklį} other {# valdiklius} }?", - "delete-widget-types-text": "Būkite dėmesingi, po patvirtinimo visi pasirinkti valdikliai ir su jais susijusi informacija bus pašalinta.", - "delete-widget-type": "Panaikinti valdiklį", - "add-widget-type": "Pridėti naują valdiklį", - "widget-type-load-failed-error": "Valdiklio įkelti nepavyko!", - "widget-template-load-failed-error": "Valdiklio šablono įkelti nepavyko!", - "details": "Informacija", - "widget-type-details": "Informacija apie valdiklį", - "add": "Pridėti valdiklį", - "no-widget-types-text": "Valdiklių nėra", - "search-widget-types": "Valdiklių paieška", - "selected-widget-types": "Pasirinkta { count, plural, =1 {1 valdiklis} other {# valdikliai} }", - "undo": "Atšaukti valdiklio pakeitimus", - "export": "Eksportuoti valdiklį", - "export-data": "Eksportuoti valdiklio duomenis", - "export-to-csv": "Eksportuoti valdiklio duomenis į CSV...", - "export-to-excel": "Eksportuoti valdiklio duomenis į XLS...", - "export-to-excel-xlsx": "Eksportuoti valdiklio duomenis į XLSX...", - "no-data": "Duomenų atvaizdavimui nėra", - "data-overflow": "Valdiklyje rodoma {{count}} iš {{total}} įrašų", - "alarm-data-overflow": "Valdiklyje rodomi {{allowedEntities}} (didižiausias leistinas skaičius) įspėjimų įrašai iš {{totalEntities}}", - "search": "Valdiklių paieška", - "filter": "Valdiklių filtro tipas", - "loading-widgets": "Valdikliai įkeliami...", - "widget-template-error": "Netinkamas valdiklio HTML šablonas." + "rpc-state": { + "initial-state": "Pradinė būsena", + "initial-state-hint": "Veiksmas, skirtas gauti pradinę komponento būseną (Įjungta / Išjungta).", + "disabled-state": "Išjungta būsena", + "disabled-state-hint": "Sąlyga, pagal kurią komponentas yra išjungiamas.", + "turn-on": "Įjungti", + "turn-on-hint": "Veiksmas, paleidžiamas, kai jungiklis perjungiamas į 'Įjungta'.", + "turn-off": "Išjungti", + "turn-off-hint": "Veiksmas, paleidžiamas, kai jungiklis perjungiamas į 'Išjungta'.", + "on": "Įjungta", + "off": "Išjungta", + "disabled": "Išjungta" }, - "widget-action": { - "header-button": "Valdiklio antraštės mygtukas", - "open-dashboard-state": "Eiti į naują skydelio būseną", - "update-dashboard-state": "Atnaujinti dabartinę skydelio būseną", - "open-dashboard": "Eiti į kitą skydelio būseną", - "custom": "Aprašomas veiksmas", - "custom-pretty": "Aprašomas veiksmas (su HTML šablonu)", - "custom-pretty-error-title": "Custom dialog error", - "custom-pretty-template-error": "Invalid custom dialog template.", - "custom-pretty-controller-error": "Error occurred while evaluating custom dialog function.", - "mobile-action": "Mobile action", - "target-dashboard-state": "Tikslinė skydelio būsena", - "target-dashboard-state-required": "Tikslnė skydelio būsena būtina", - "set-entity-from-widget": "Nustatyti subjektą iš valdiklio", - "target-dashboard": "Tikslinis skydelis", - "open-right-layout": "Atidarykiti tinkamą skydelio išdėstymą (vaizdas mobiliesiems)", - "state-display-type": "Skydelio būsenos rodymo parinktis", - "open-normal": "Normal", - "open-in-separate-dialog": "Open in separate dialog", - "open-in-popover": "Open in popover", - "dialog-title": "Dialog title", - "dialog-hide-dashboard-toolbar": "Hide dashboard toolbar in dialog", - "dialog-width": "Dialog width in percents relative to viewport width", - "dialog-height": "Dialog height in percents relative to viewport height", - "dialog-size-range-error": "Dialog size percent value should be in a range from 1 to 100.", - "popover-preferred-placement": "Preferred popover placement", - "popover-placement-top": "Top", - "popover-placement-topLeft": "Top left", - "popover-placement-topRight": "Top right", - "popover-placement-right": "Right", - "popover-placement-rightTop": "Right top", - "popover-placement-rightBottom": "Right bottom", - "popover-placement-bottom": "Bottom", - "popover-placement-bottomLeft": "Bottom left", - "popover-placement-bottomRight": "Bottom right", - "popover-placement-left": "Left", - "popover-placement-leftTop": "Left top", - "popover-placement-leftBottom": "Left bottom", - "popover-hide-on-click-outside": "Hide popover on outside click", - "popover-hide-dashboard-toolbar": "Hide dashboard toolbar in popover", - "popover-width": "Popover width in browser units (ex. 100px, 25vw)", - "popover-height": "Popover height in browser units (ex. 100px, 25vh)", - "popover-style": "Popover style", - "open-new-browser-tab": "Open in a new browser tab", - "mobile": { - "action-type": "Mobile action type", - "action-type-required": "Mobile action type is required", - "take-picture-from-gallery": "Take picture from gallery", - "take-photo": "Take photo", - "map-direction": "Open map directions", - "map-location": "Open map location", - "scan-qr-code": "Scan QR Code", - "make-phone-call": "Make phone call", - "get-location": "Get phone location", - "take-screenshot": "Take screenshot" - } + "value-action": { + "do-nothing": "Nedaryti nieko", + "execute-rpc": "Vykdyti RPC komandą", + "get-attribute": "Gauti atributą", + "set-attribute": "Nustatyti atributą", + "get-time-series": "Gauti laiko eilutę", + "get-alarm-status": "Gauti aliarmo būseną", + "get-dashboard-state": "Gauti skydelio būsenos ID", + "get-dashboard-state-object": "Gauti skydelio būsenos objektą", + "add-time-series": "Pridėti laiko eilutę", + "execute-rpc-text": "Vykdyti RPC metodą '{{methodName}}'", + "get-time-series-text": "Naudoti laiko eilutę '{{key}}'", + "get-attribute-text": "Naudoti atributą '{{key}}'", + "get-alarm-status-text": "Naudoti aliarmo būseną", + "get-dashboard-state-text": "Naudoti skydelio būseną", + "get-dashboard-state-object-text": "Naudoti skydelio būsenos objektą", + "when-dashboard-state-is-text": "Kai skydelio būsena yra '{{state}}'", + "when-dashboard-state-function-is-text": "Kai f(skydelio būsena) = '{{state}}'", + "when-dashboard-state-object-function-is-text": "Kai f(skydelio būsenos objektas) = '{{state}}'", + "set-attribute-to-value-text": "Nustatyti '{{key}}' atributo reikšmę į: {{value}}", + "add-time-series-value-text": "Pridėti '{{key}}' laiko eilutės reikšmę: {{value}}", + "set-attribute-text": "Nustatyti '{{key}}' atributą", + "add-time-series-text": "Pridėti '{{key}}' laiko eilutę", + "action": "Veiksmas", + "value": "Reikšmė", + "init-value-hint": "Reikšmė, kuri bus naudojama iki kol įrenginys atsiųs duomenis.", + "method": "Metodas", + "method-name-required": "Metodo pavadinimas yra privalomas.", + "request-timeout-ms": "RPC užklausos laiko limitas (ms)", + "request-timeout-required": "Reikalingas užklausos laiko limitas.", + "min-request-timeout-error": "Užklausos laiko limitas turi būti ne mažesnis nei 5000 ms (5 sekundės).", + "request-persistent": "Išliekanti RPC užklausa", + "persistent-polling-interval": "Išliekantis apklausos intervalas (ms)", + "persistent-polling-interval-hint": "Apklausos intervalas (ms) išliekantiems RPC komandų atsakymams gauti", + "persistent-polling-interval-required": "Išliekantis apklausos intervalas yra privalomas.", + "min-persistent-polling-interval-error": "Apklausos intervalas turi būti ne mažesnis nei 1000 ms (1 sekundė).", + "attribute-scope": "Atributo taikymo sritis", + "attribute-key": "Atributo raktas", + "attribute-key-required": "Atributo raktas yra privalomas.", + "time-series-key": "Laiko eilutės raktas", + "time-series-key-required": "Laiko eilutės raktas yra privalomas.", + "action-result-converter": "Veiksmo rezultatų konverteris", + "converter-none": "Nėra", + "converter-function": "Funkcija", + "converter-constant": "Pastovi reikšmė", + "converter-value": "Reikšmė", + "parse-value-function": "Reikšmės apdorojimo funkcija", + "state-when-result-is": "'{{state}}' kai rezultatas yra", + "parameters": "Parametrai", + "convert-value-function": "Reikšmės konvertavimo funkcija", + "error": { + "target-entity-is-not-set": "Tikslinis objektas nenustatytas!", + "failed-to-perform-action": "Nepavyko atlikti veiksmo {{ actionLabel }}.", + "invalid-attribute-scope": "{{scope}} atributų taikymo sritis nepalaikoma {{entityType}} objekte." + } }, - "widgets-bundle": { - "current": "Dabartinis rinkinys", - "widgets-bundles": "Valdiklių rinkiniai", - "widgets-bundle-widgets": "Valdiklių rinkinio valdikliai", - "add": "Pridėti valdiklių rinkinį", - "delete": "Panaikinti valdiklių rinkinį", - "title": "Pavadinimas", - "title-required": "Pavadinimas būtinas.", - "title-max-length": "Pavadinimas negali viršyti 256 simbolių", - "description": "Aprašymas", - "image-preview": "Paveiksliuko peržiūra", - "add-widgets-bundle-text": "Pridėti naują valdiklių rinkinį", - "no-widgets-bundles-text": "Valdiklių rinkinių nėra", - "empty": "Valdiklių rinkinys tuščias", - "details": "Informacija", - "widgets-bundle-details": "Informacija apie valdiklių rinkinį", - "delete-widgets-bundle-title": "Ar tikrai norite panaikinti valdiklių rinkinį '{{widgetsBundleTitle}}'?", - "delete-widgets-bundle-text": "Būkite dėmesingi, po patvirtinimo valdiklių rinkinys ir visa su juo susijusi informacija bus panaikinta.", - "delete-widgets-bundles-title": "Ar tikrai norite panaikinti { count, plural, =1 {1 valdiklių rinkinį} other {# valdiklių rinkinius} }?", - "delete-widgets-bundles-action-title": "Panaikinti { count, plural, =1 {1 valdiklių rinkinį} other {# valdiklių rinknius} }", - "delete-widgets-bundles-text": "Būkite dėmesingi, po patvirtinimo visi pasirinkti valdiklių rinkiniai ir su jais susijusi informacija bus panaikinta.", - "no-widgets-bundles-matching": "Valdiklių rinkinių, atitinkančių '{{widgetsBundle}}' nėra.", - "widgets-bundle-required": "Valdiklių rinkinys būtinas.", - "system": "Sisteminis", - "import": "Importuoti valdiklių rinknį", - "export": "Eksportuoti valdiklių rinkinį", - "export-widgets-bundle-widgets-prompt": "Valdiklių rinkinių tipus įtraukti į eksportuotus duomenis (kitu atveju bus eksportuojami tik nurodytų valdiklių tipų FQN)", - "export-failed-error": "Valdiklių rinkinio eksportuoti nepavyko: {{error}}", - "create-new-widgets-bundle": "Sukurti naują valdiklių rinkinį", - "widgets-bundle-file": "Valdiklių rinkinio failas", - "invalid-widgets-bundle-file-error": "Valdiklių rinkinio importuoti nepavyko: neteisinga duomenš struktūra.", - "search": "Valdiklių rinkinių paieška", - "selected-widgets-bundles": "Pasirinkta { count, plural, =1 {1 valdiklių rinkinys} other {# valdiklių rinkiniai} }", - "open-widgets-bundle": "Atverti valdiklių rinkinį", - "loading-widgets-bundles": "Įkeliamas valdiklių rinkinys..." - }, - "widget-config": { - "data": "Duomenys", - "settings": "Nustatymai", - "advanced": "Išplėstiniai nustatymai", - "appearance": "Išvaizda", - "widget-card": "Valdiklio kortelė", - "mobile": "Mobilusis vaizdas", - "title": "Pavadinimas", - "title-tooltip": "Pavadinimo paaiškinimas", - "general-settings": "Pagrindiniai nustatymai", - "display-title": "Rodyti valdiklio pavadinimą", - "card-title": "Kortelės pavadinimas", - "drop-shadow": "Šešėlis", - "enable-fullscreen": "Įjungti rodymą per visą ekraną", - "enable-data-export": "Įjungti duomenų eksportą", - "data-export": "Duomenų eksportas", - "background-color": "Fono spalva", - "text-color": "Teksto spalva", - "border-radius": "Rėmelio storis", - "padding": "Padding", - "margin": "Margin", - "widget-style": "Valdiklio stilius", - "widget-css": "Valdiklio CSS", - "title-style": "Antraštės stilius", - "mobile-mode-settings": "Mobiliojo vaizdo režimas", - "order": "Rikiavimo tvarka", - "height": "Aukštis", - "mobile-hide": "Valdiklį paslėpti mobiliojo vaizdo režime", - "desktop-hide": "Slėpti valdiklį darbalaukio režime", - "units": "Papildomas simbolis šalia reikšmės", - "units-by-default": "Numatytieji matavimo vienetai", - "decimals": "Skaimenys po kablelio", - "decimals-by-default": "Dešimtainiai skaičiai pagal numatytuosius nustatymus", - "default-data-key-parameter-hint": "Šis parametras taikomas visoms valdiklių reikšmėms, nebent jis nustatomas duomenų rakto konfigūracijoje", - "units-short": "Vienetai", - "decimals-short": "Dešimtainiai skaičiai", - "decimals-suffix": "dešimtainiai skaičiai", - "timewindow": "Laikotarpio langas", - "use-dashboard-timewindow": "Naudoti skydelio laikotarpio langą", - "use-widget-timewindow": "Naudoti valdiklio laikotarpio langą", - "display-timewindow": "Rodyti laikotarpio langą", - "legend": "Legenda", - "display-legend": "Rodyti legendą", - "datasources": "Duomenų šaltiniai", - "datasource": "Duomenų šaltinis", - "maximum-datasources": "Daugiausiai leidžiama { count, plural, =1 {1 vienas duomenų šaltinis.} other {# duomenų šaltiniai} }", - "timeseries-key-error": "Reikia nurodyti nors vieną telemetrijos rodiklį", - "datasource-type": "Tipas", - "datasource-parameters": "Parametrai", - "remove-datasource": "Pašalinti duomenų šaltinį", - "add-datasource": "Pridėti duomenų šaltinį", - "target-device": "Tikslinis įrenginys", - "alarm-source": "Įspėjimo šaltinis", - "actions": "Veiksmai", - "action": "Veiksmas", - "add-action": "Pridėti veiksmą", - "search-actions": "Veiksmų paieška", - "no-actions-text": "Veiksmų nėra", - "action-source": "Veiksmo šaltinis", - "action-source-required": "Veiksmo šaltinis būtinas.", - "action-name": "Pavadinimas", - "action-name-required": "Veiksmo pavadinimas būtinas.", - "action-name-not-unique": "Veiksmas su tokiu pavadinimu jau yra.
Šaltinyje veiksmų pavadinimai kartotis negali.", - "action-icon": "Piktograma", - "show-hide-action-using-function": "Rodyti/slėpti veiksmą funkcijos pagalba", - "action-type": "Tipas", - "action-type-required": "Veiksmo tipas būtinas.", - "edit-action": "Redaguoti veiksmą", - "delete-action": "Panaikinti veiksmą", - "delete-action-title": "Panaikinti valdiklio veiksmą", - "delete-action-text": "Ar tikrai norite panaikinti valdiklio veiksmą '{{actionName}}'?", - "title-icon": "Antraštės piktograma", - "display-icon": "Rodyti antraštės piktoramą", - "card-icon": "Kortelės piktograma", - "icon-color": "Piktogramos spalva", - "icon-size": "Piktogramos dydis", - "advanced-settings": "Išplėstiniai nustatymai", - "data-settings": "Duomenų nustatymai", - "limits": "Ribos", - "no-data-display-message": "\"Nėra duomenų\" alternatyvus tekstas", - "data-page-size": "Maximum entities per datasource", - "settings-component-not-found": "Settings form component not found for selector '{{selector}}'", - "preview": "Preview", - "set": "Set", - "set-message": "Set message", - "advanced-title-style": "Advanced title style", - "card-style": "Card style", - "text": "Text", - "background": "Background", - "advanced-widget-style": "Advanced widget style", - "card-buttons": "Card buttons", - "show-card-buttons": "Show card buttons", - "card-border-radius": "Card border radius", - "card-appearance": "Card appearance", - "color": "Color" - }, - "widget-type": { - "import": "Importuoti valdiklį", - "export": "Eksportuoti valdiklį", - "export-widget-types": "Eksportuoti valdiklius", - "export-failed-error": "Valdiklio eksportuoti nepavyko: {{error}}", - "create-new-widget-type": "Sukurt naują valdiklį", - "widget-type-file": "Valdiklių failas", - "invalid-widget-type-file-error": "Nepavyko importuoti valdiklio: neteisinga valdiklio duomenų struktūra." - }, - "self-registration": { - "self-registration": "Self Registration", - "self-registration-url": "Self Registration URL", - "captcha-version": "reCAPTCHA version", - "captcha-action": "reCAPTCHA log action name", - "captcha-site-key": "reCAPTCHA site key", - "captcha-secret-key": "reCAPTCHA secret key", - "notification-email": "El. pašto adresas pranešimų siuntimui", - "notification-email-invalid": "Neteisingas el. pašto adreso formatas.", - "notification-email-required": "El. pašto adresas pranešimų siuntimui būtinas.", - "privacy-policy-text": "Privatumo politikos tekstas", - "terms-of-use-text": "Terms of Use text", - "text-message-page": "Tekstinė žinutė registracijos puslapiui", - "enable-mobile-self-registration": "Enable self registration from mobile application", - "mobile-self-registration-title": "Mobile application self registration settings", - "mobile-package": "Application package", - "mobile-package-placeholder": "Ex.: my.example.app", - "mobile-package-hint": "For Android: your own unique Application ID. For iOS: Product bundle identifier.", - "mobile-package-required": "Application package is required", - "mobile-app-secret": "Application secret", - "invalid-mobile-app-secret": "Application secret must contain only alphanumeric characters and must be between 16 and 2048 characters long.", - "copy-mobile-app-secret": "Copy application secret", - "mobile-app-scheme": "Application URL scheme", - "mobile-app-scheme-placeholder": "Ex.: customscheme", - "mobile-app-scheme-required": "Application URL scheme is required", - "mobile-app-host": "Application URL hostname", - "mobile-app-host-placeholder": "Ex.: my.app.host", - "mobile-app-host-required": "Application URL hostname is required", - "show-privacy-policy": "Show Privacy Policy", - "show-terms-of-use": "Show Terms of Use", - "domain-settings": "Domain settings", - "general-settings": "General settings" - }, - "solution-template": { - "solution-template": "Solution template", - "solution-templates": "Solution templates", - "management": "Manage solution templates", - "details": "Details", - "install": "Install", - "level": "Level", - "install-title": "Solution template successfully installed", - "install-failed-title": "Solution template installation failed", - "instructions": "Instructions", - "goto-main-dashboard": "Goto main dashboard", - "delete": "Delete", - "delete-solution-title": "Are you sure you want to delete the solution '{{solutionTitle}}'?", - "delete-solution-text": "Be careful, after the confirmation the solution and all related data will become unrecoverable.", - "installing": "Installing solution template..." + "widget-font": { + "font-settings": "Šrifto nustatymai", + "font-family": "Šrifto šeima", + "size": "Dydis", + "relative-font-size": "Santykinis šrifto dydis (procentais)", + "font-style": "Stilius", + "font-style-normal": "Normalus", + "font-style-italic": "Kursyvas", + "font-style-oblique": "Pasviręs", + "font-weight": "Storis", + "font-weight-normal": "Normalus", + "font-weight-bold": "Paryškintas", + "font-weight-bolder": "Labiau paryškintas", + "font-weight-lighter": "Plonesnis", + "color": "Spalva", + "shadow-color": "Šešėlio spalva", + "preview": "Peržiūra", + "line-height": "Eilučių aukštis", + "auto": "Automatinis" }, - "markdown": { - "edit": "Edit", - "preview": "Preview", - "copy-code": "Click to copy", - "copied": "Copied!" - }, - "white-labeling": { - "white-labeling": "Tinkinimas", - "white-labeling-general": "General White Labeling", - "login-white-labeling": "Prisijungimo puslapio tinkinimas", - "general": "General", - "login": "Prisijungti", - "preview": "Peržiūra", - "app-title": "Aplikaciijios pavadinimas", - "favicon": "Aplikacijos piktograma", - "favicon-description": "*.ico, *.gif ar *.png paveiksliukas, kurio maksimalus dydis {{kbSize}} kilobaitai.", - "favicon-size-error": "Paveiksliukas per didelis. Maksimalus leistinas dydis yra {{kbSize}} kilobaitai.", - "favicon-type-error": "Netinkamas paveiksliuko formatas. Leidžiami tik ICO, GIF ar PNG formatai.", - "drop-favicon-image": "Užvilkite svetainės piktogramos paveiksliuką arba spustelėkite, kad pasirinktumėte failą, kurį norite įkelti.", - "drop-favicon-image-or": "Drag and drop a website icon image or", - "no-favicon-image": "Piktograma nepasirinkta", - "logo": "Logo", - "logo-description": "Bet koks paveiksliukas, kurio dydis neviršija {{kbSize}} kilobaitų.", - "logo-size-error": "Logotipas per didelis. Maksimalus leistinas dydis yra {{kbSize}} kilobaitai.", - "logo-type-error": "Netinkamas logotipo failo. Only images are accepted.", - "drop-logo-image": "Užvilkite svetainės logotipo paveiksliuką arba spustelėkite, kad pasirinktumėte failą, kurį norite įkelti.", - "drop-logo-image-or": "Drag and drop a logo image or", - "no-logo-image": "Logotipas nepasirinktas", - "logo-height": "Logotipo aukštis, px", - "primary-palette": "Pirminė paletė", - "accent-palette": "Akcentų paletė", - "customize-palette": "Pritaikyti", - "advanced-css": "Advanced CSS", - "edit-palette": "Redaguoti paletę", - "save-palette": "Išsaugoti paletę", - "primary-background": "Pirminis fonas", - "secondary-background": "Antrinis fonas", - "hue1": "HUE 1", - "hue2": "HUE 2", - "hue3": "HUE 3", - "page-background-color": "Puslapio fono spalva", - "dark-foreground": "Tamsi tema", - "domain-name": "Domeno pavadinimas", - "base-url": "Bazinis URL", - "prohibit-different-url": "Prohibit to use hostname from the client request headers", - "prohibit-different-url-hint": "This setting should be enabled for production environments. May cause security issues when disabled", - "help-link-base-url": "Bazinis pagalbos puslapio url", - "ui-help-base-url": "UI help base url", - "enable-help-links": "Įjungti pagalbos nuorodas", - "error-verification-url": "Domeno pavadinime negali būti '/' ir ':' simbolių. Pavyzdžiui: thingsboard.io", - "show-platform-name-version": "Rodyti platformos pavadinimą ir versiją", - "platform-name": "Platformas pavadinimas", - "platform-version": "Platformos versija", - "version-mask": "{{name}} v.{{version}}", - "position": { - "label": "Platformos pavadinimo ir versijos išdėstymas", - "under-logo": "Po logotipu", - "bottom": "Prisijungimo formos apačioje" - } + "home": { + "no-data-available": "Nėra prieinamų duomenų" }, - "widgets": { - "background": { - "background": "Background", - "background-settings": "Background settings", - "background-type-image": "Upload image", - "background-type-image-url": "Image URL", - "background-type-color": "Solid color", - "image-url": "Image URL", - "overlay": "Overlay", - "enable-overlay": "Enable overlay", - "blur": "Blur", - "preview": "Preview" - }, - "battery-level": { - "layout": "Layout", - "layout-vertical-solid": "Vertical. Solid", - "layout-horizontal-solid": "Horizontal. Solid", - "layout-vertical-divided": "Vertical. Divided", - "layout-horizontal-divided": "Horizontal. Divided", - "icon": "Icon", - "value": "Value", - "auto-scale": "Auto scale", - "battery-level-color": "Battery level color", - "battery-shape-color": "Battery shape color", - "battery-level-card-style": "Battery level card style" - }, - "chart": { - "common-settings": "Common settings", - "enable-stacking-mode": "Enable stacking mode", - "selection": "Time range selection", - "enable-selection-mode": "Enable selection mode", - "line-shadow-size": "Line shadow size", - "display-smooth-lines": "Display smooth (curved) lines", - "default-bar-width": "Default bar width for non-aggregated data (milliseconds)", - "bar-alignment": "Bar alignment", - "bar-alignment-left": "Left", - "bar-alignment-right": "Right", - "bar-alignment-center": "Center", - "default-font": "Default font", - "default-font-size": "Default font size", - "default-font-color": "Default font color", - "thresholds-line-width": "Default line width for all thresholds", - "tooltip-settings": "Tooltip settings", - "tooltip": "Tooltip", - "show-tooltip": "Show tooltip", - "hover-individual-points": "Hover individual points", - "show-cumulative-values": "Show cumulative values in stacking mode", - "hide-zero-false-values": "Hide zero/false values from tooltip", - "tooltip-value-format-function": "Tooltip value format function", - "grid-settings": "Grid settings", - "show-vertical-lines": "Show vertical lines", - "show-horizontal-lines": "Show horizontal lines", - "grid-outline-border-width": "Grid outline/border width (px)", - "primary-color": "Primary color", - "background-color": "Background color", - "ticks-color": "Ticks color", - "xaxis-settings": "X axis settings", - "axis-title": "Axis title", - "xaxis-tick-labels-settings": "X axis tick labels settings", - "show-tick-labels": "Show axis tick labels", - "yaxis-settings": "Y axis settings", - "min-scale-value": "Minimum value on the scale", - "max-scale-value": "Maximum value on the scale", - "yaxis-tick-labels-settings": "Y axis tick labels settings", - "tick-step-size": "Step size between ticks", - "number-of-decimals": "The number of decimals to display", - "ticks-formatter-function": "Ticks formatter function", - "comparison-settings": "Comparison settings", - "enable-comparison": "Enable comparison", - "time-for-comparison": "Comparison period", - "time-for-comparison-previous-interval": "Previous interval (default)", - "time-for-comparison-days": "Day ago", - "time-for-comparison-weeks": "Week ago", - "time-for-comparison-months": "Month ago", - "time-for-comparison-years": "Year ago", - "time-for-comparison-custom-interval": "Custom interval", - "custom-interval-value": "Custom interval value (ms)", - "comparison-x-axis-settings": "Comparison X axis settings", - "axis-position": "Axis position", - "axis-position-top": "Top (default)", - "axis-position-bottom": "Bottom", - "custom-legend-settings": "Custom legend settings", - "enable-custom-legend": "Enable custom legend (this will allow you to use attribute/timeseries values in key labels)", - "key-name": "Key name", - "key-name-required": "Key name is required", - "key-type": "Key type", - "key-type-attribute": "Attribute", - "key-type-timeseries": "Timeseries", - "label-keys-list": "Keys list to use in labels", - "no-label-keys": "No keys configured", - "add-label-key": "Add new key", - "line-width": "Line width", - "color": "Color", - "data-is-hidden-by-default": "Data is hidden by default", - "disable-data-hiding": "Disable data hiding", - "remove-from-legend": "Remove datakey from legend", - "exclude-from-stacking": "Exclude from stacking(available in \"Stacking\" mode)", - "line-settings": "Line settings", - "show-line": "Show line", - "fill-line": "Fill line", - "fill-line-opacity": "Fill opacity", - "points-settings": "Points settings", - "show-points": "Show points", - "points-line-width": "Line width of points", - "points-radius": "Radius of points", - "point-shape": "Point shape", - "point-shape-circle": "Circle", - "point-shape-cross": "Cross", - "point-shape-diamond": "Diamond", - "point-shape-square": "Square", - "point-shape-triangle": "Triangle", - "point-shape-custom": "Custom function", - "point-shape-draw-function": "Point shape draw function", - "show-separate-axis": "Show separate axis", - "axis-position-left": "Left", - "axis-position-right": "Right", - "thresholds": "Thresholds", - "no-thresholds": "No thresholds configured", - "add-threshold": "Add threshold", - "show-values-for-comparison": "Show historical values for comparison", - "comparison-values-label": "Historical values label", - "comparison-line-color": "Comparison line color", - "threshold-settings": "Threshold settings", - "use-as-threshold": "Use key value as threshold", - "threshold-line-width": "Threshold line width", - "threshold-color": "Threshold color", - "common-pie-settings": "Common pie settings", - "radius": "Radius", - "inner-radius": "Inner radius", - "tilt": "Tilt", - "common-pie-settings-range-error": "Value should be in range from 0 to 1", - "stroke-settings": "Stroke settings", - "width-pixels": "Width (pixels)", - "show-labels": "Show labels", - "animation-settings": "Animation settings", - "animated-pie": "Enable pie animation (experimental)", - "border-settings": "Border settings", - "border-width": "Border width", - "border-color": "Border color", - "legend-settings": "Legend settings", - "display-legend": "Display legend", - "labels-font-color": "Labels font color", - "series": "Series", - "add-series": "Add series", - "series-settings": "Series settings", - "remove-series": "Remove series", - "no-series": "No series configured", - "no-series-error": "At least one series should be specified", - "chart-appearance": "Chart appearance", - "vertical-grid-lines": "Vertical grid lines", - "horizontal-grid-lines": "Horizontal grid lines", - "chart-background": "Chart background", - "grid-lines-color": "Grid lines color", - "border": "Border", - "axis": "Axis", - "vertical-axis": "Vertical axis", - "ticks": "Ticks", - "horizontal-axis": "Horizontal axis" - }, - "color": { - "color-settings": "Color settings", - "color-type-constant": "Constant", - "color-type-range": "Range", - "color-type-function": "Function", - "color": "Color", - "value-range": "Value range", - "from": "From", - "to": "To", - "color-function": "Color function" - }, - "dashboard-state": { - "dashboard-state-settings": "Dashboard state settings", - "dashboard-state": "Dashboard state id", - "autofill-state-layout": "Autofill state layout height by default", - "default-margin": "Default widgets margin", - "default-background-color": "Default background color", - "sync-parent-state-params": "Sync state params with parent dashboard" - }, - "date-range-navigator": { - "date-range-picker-settings": "Date range picker settings", - "hide-date-range-picker": "Hide date range picker", - "picker-one-panel": "Date range picker one panel", - "picker-auto-confirm": "Date range picker auto confirm", - "picker-show-template": "Date range picker show template", - "first-day-of-week": "First day of the week", - "interval-settings": "Interval settings", - "hide-interval": "Hide interval", - "initial-interval": "Initial interval", - "interval-hour": "Hour", - "interval-day": "Day", - "interval-week": "Week", - "interval-two-weeks": "2 weeks", - "interval-month": "Month", - "interval-three-months": "3 months", - "interval-six-months": "6 months", - "step-settings": "Step settings", - "hide-step-size": "Hide step size", - "initial-step-size": "Initial step size", - "hide-labels": "Hide labels", - "use-session-storage": "Use session storage", - "localizationMap": { - "Sun": "Sun", - "Mon": "Mon", - "Tue": "Tue", - "Wed": "Wed", - "Thu": "Thu", - "Fri": "Fri", - "Sat": "Sat", - "Jan": "Jan", - "Feb": "Feb", - "Mar": "Mar", - "Apr": "Apr", - "May": "May", - "Jun": "Jun", - "Jul": "Jul", - "Aug": "Aug", - "Sep": "Sep", - "Oct": "Oct", - "Nov": "Nov", - "Dec": "Dec", - "January": "January", - "February": "February", - "March": "March", - "April": "April", - "June": "June", - "July": "July", - "August": "August", - "September": "September", - "October": "October", - "November": "November", - "December": "December", - "Custom Date Range": "Custom Date Range", - "Date Range Template": "Date Range Template", - "Today": "Today", - "Yesterday": "Yesterday", - "This Week": "This Week", - "Last Week": "Last Week", - "This Month": "This Month", - "Last Month": "Last Month", - "Year": "Year", - "This Year": "This Year", - "Last Year": "Last Year", - "Date picker": "Date picker", - "Hour": "Hour", - "Day": "Day", - "Week": "Week", - "2 weeks": "2 Weeks", - "Month": "Month", - "3 months": "3 Months", - "6 months": "6 Months", - "Custom interval": "Custom interval", - "Interval": "Interval", - "Step size": "Step size", - "Ok": "Ok" - } - }, - "entities-hierarchy": { - "hierarchy-data-settings": "Hierarchy data settings", - "relations-query-function": "Node relations query function", - "has-children-function": "Node has children function", - "node-state-settings": "Node state settings", - "node-opened-function": "Default node opened function", - "node-disabled-function": "Node disabled function", - "display-settings": "Display settings", - "node-icon-function": "Node icon function", - "node-text-function": "Node text function", - "sort-settings": "Sort settings", - "nodes-sort-function": "Nodes sort function" - }, - "edge": { - "display-default-title": "Display default title" - }, - "gateway": { - "general-settings": "General settings", - "widget-title": "Widget title", - "default-archive-file-name": "Default archive file name", - "device-type-for-new-gateway": "Device type for new gateway", - "messages-settings": "Messages settings", - "save-config-success-message": "Text message about successfully saved gateway configuration", - "device-name-exists-message": "Text message when device with entered name is already exists", - "gateway-title": "Gateway form", - "read-only": "Read only", - "events-title": "Gateway events form title", - "events-filter": "Events filter", - "event-key-contains": "Event key contains...", - "show-connector": "Show for the connector", - "connector-state-param-key": "Connector state parameter key", - "message": "Message", - "created-time": "Created time" - }, - "gauge": { - "default-color": "Default color", - "radial-gauge-settings": "Radial gauge settings", - "ticks-settings": "Ticks settings", - "min-value": "Minimum value", - "max-value": "Maximum value", - "start-ticks-angle": "Start ticks angle", - "ticks-angle": "Ticks angle", - "major-ticks-count": "Major ticks count", - "major-ticks-color": "Major ticks color", - "minor-ticks-count": "Minor ticks count", - "minor-ticks-color": "Minor ticks color", - "tick-numbers-font": "Tick numbers font", - "unit-title-settings": "Unit title settings", - "show-unit-title": "Show unit title", - "unit-title": "Unit title", - "title-font": "Title text font", - "units-settings": "Units settings", - "units-font": "Units text font", - "value-box-settings": "Value box settings", - "show-value-box": "Show value box", - "value-int": "Digits count for integer part of value", - "value-font": "Value text font", - "value-box-rect-stroke-color": "Value box rectangle stroke color", - "value-box-rect-stroke-color-end": "Value box rectangle stroke color - end gradient", - "value-box-background-color": "Value box background color", - "value-box-shadow-color": "Value box shadow color", - "plate-settings": "Plate settings", - "show-plate-border": "Show plate border", - "plate-color": "Plate color", - "needle-settings": "Needle settings", - "needle-circle-size": "Needle circle size", - "needle-color": "Needle color", - "needle-color-end": "Needle color - end gradient", - "needle-color-shadow-up": "Upper half of the needle shadow color", - "needle-color-shadow-down": "Drop shadow needle color", - "highlights-settings": "Highlights settings", - "highlights-width": "Highlights width", - "highlights": "Highlights", - "highlight-from": "From", - "highlight-to": "To", - "highlight-color": "Color", - "no-highlights": "No highlights configured", - "add-highlight": "Add highlight", - "animation-settings": "Animation settings", - "enable-animation": "Enable animation", - "animation-duration": "Animation duration", - "animation-rule": "Animation rule", - "animation-linear": "Linear", - "animation-quad": "Quad", - "animation-quint": "Quint", - "animation-cycle": "Cycle", - "animation-bounce": "Bounce", - "animation-elastic": "Elastic", - "animation-dequad": "Dequad", - "animation-dequint": "Dequint", - "animation-decycle": "Decycle", - "animation-debounce": "Debounce", - "animation-delastic": "Delastic", - "linear-gauge-settings": "Linear gauge settings", - "bar-stroke-width": "Bar stroke width", - "bar-stroke-color": "Bar stroke color", - "bar-background-color": "Gauge bar background color", - "bar-background-color-end": "Bar background color - end gradient", - "progress-bar-color": "Progress bar color", - "progress-bar-color-end": "Progress bar color - end gradient", - "major-ticks-names": "Major ticks names", - "show-stroke-ticks": "Show ticks stroke", - "major-ticks-font": "Major ticks font", - "border-color": "Border color", - "border-width": "Border width", - "needle-circle-color": "Needle circle color", - "animation-target": "Animation target", - "animation-target-needle": "Needle", - "animation-target-plate": "Plate", - "common-settings": "Common gauge settings", - "gauge-type": "Gauge type", - "gauge-type-arc": "Arc", - "gauge-type-donut": "Donut", - "gauge-type-horizontal-bar": "Horizontal bar", - "gauge-type-vertical-bar": "Vertical bar", - "donut-start-angle": "Angle to start from", - "bar-settings": "Gauge bar settings", - "relative-bar-width": "Relative bar width", - "neon-glow-brightness": "Neon glow effect brightness, (0-100), 0 - disable effect", - "stripes-thickness": "Thickness of the stripes, 0 - no stripes", - "rounded-line-cap": "Display rounded line cap", - "bar-color-settings": "Bar color settings", - "use-precise-level-color-values": "Use precise color levels", - "bar-colors": "Bar colors, from lower to upper", - "color": "Color", - "no-bar-colors": "No bar colors configured", - "add-bar-color": "Add bar color", - "from": "From", - "to": "To", - "fixed-level-colors": "Bar colors using boundary values", - "gauge-title-settings": "Gauge title settings", - "show-gauge-title": "Show gauge title", - "gauge-title": "Gauge title", - "gauge-title-font": "Gauge title font", - "unit-title-and-timestamp-settings": "Unit title and timestamp settings", - "show-timestamp": "Show value timestamp", - "timestamp-format": "Timestamp format", - "label-font": "Font of label showing under value", - "value-settings": "Value settings", - "show-value": "Show value text", - "min-max-settings": "Minimum/maximum labels settings", - "show-min-max": "Show min and max values", - "min-max-font": "Font of minimum and maximum labels", - "show-ticks": "Show ticks", - "tick-width": "Tick width", - "tick-color": "Tick color", - "tick-values": "Tick values", - "no-tick-values": "No tick values configured", - "add-tick-value": "Add tick value" - }, - "gpio": { - "pin": "Pin", - "label": "Label", - "row": "Row", - "column": "Column", - "color": "Color", - "panel-settings": "Panel settings", - "background-color": "Background color", - "gpio-switches": "GPIO switches", - "no-gpio-switches": "No GPIO switches configured", - "add-gpio-switch": "Add GPIO switch", - "gpio-status-request": "GPIO status request", - "method-name": "Method name", - "method-body": "Method body", - "gpio-status-change-request": "GPIO status change request", - "parse-gpio-status-function": "Parse gpio status function", - "gpio-leds": "GPIO leds", - "no-gpio-leds": "No GPIO leds configured", - "add-gpio-led": "Add GPIO led" - }, - "html-card": { - "html": "HTML", - "css": "CSS" - }, - "input-widgets": { - "attribute-not-allowed": "Attribute parameter cannot be used in this widget", - "blocked-location": "Geolocation is blocked in your browser", - "claim-device": "Claim device", - "claim-failed": "Failed to claim the device!", - "claim-not-found": "Device not found!", - "claim-successful": "Device was successfully claimed!", - "date": "Date", - "device-name": "Device name", - "device-name-required": "Device name is required", - "discard-changes": "Discard changes", - "entity-attribute-required": "Entity attribute is required", - "entity-coordinate-required": "Both fields, latitude and longitude, are required", - "entity-timeseries-required": "Entity timeseries is required", - "get-location": "Get current location", - "invalid-date": "Invalid Date", - "latitude": "Latitude", - "longitude": "Longitude", - "min-value-error": "Min value is {{value}}", - "max-value-error": "Max value is {{value}}", - "not-allowed-entity": "Selected entity cannot have shared attributes", - "no-attribute-selected": "No attribute is selected", - "no-datakey-selected": "No datakey is selected", - "no-coordinate-specified": "Datakey for latitude/longitude doesn't specified", - "no-entity-selected": "No entity selected", - "no-image": "No image", - "no-support-geolocation": "Your browser doesn't support geolocation", - "no-support-web-camera": "Your browser does not support cameras", - "enable-https-use-widget": "Please enable HTTPS to use this widget", - "no-found-your-camera": "Can't find your camera", - "no-permission-camera": "Permission was denied by the user / This site doesn't have permission to use the camera", - "no-timeseries-selected": "No timeseries selected", - "secret-key": "Secret key", - "secret-key-required": "Secret key is required", - "switch-attribute-value": "Switch entity attribute value", - "switch-camera": "Switch camera", - "switch-timeseries-value": "Switch entity timeseries value", - "take-photo": "Take photo", - "time": "Time", - "timeseries-not-allowed": "Timeseries parameter cannot be used in this widget", - "update-failed": "Update failed", - "update-successful": "Update successful", - "update-attribute": "Update attribute", - "update-timeseries": "Update timeseries", - "value": "Value", - "general-settings": "General settings", - "widget-title": "Widget title", - "claim-button-label": "Claiming button label", - "show-secret-key-field": "Show 'Secret key' input field", - "labels-settings": "Labels settings", - "show-labels": "Show labels", - "device-name-label": "Label for device name input field", - "secret-key-label": "Label for secret key input field", - "messages-settings": "Messages settings", - "claim-device-success-message": "Text message of successful device claiming", - "claim-device-not-found-message": "Text message when device not found", - "claim-device-failed-message": "Text message of failed device claiming", - "claim-device-name-required-message": "'Device name required' error message", - "claim-device-secret-key-required-message": "'Secret key required' error message", - "relations-settings": "Relations settings", - "relate-device-to-state-entity": "Relate device to current state entity", - "relate-direction": "Relate direction", - "relate-direction-from": "From", - "relate-direction-to": "To", - "relation-type": "Relation type", - "show-label": "Show label", - "label": "Label", - "required": "Required", - "required-error-message": "'Required' error message", - "show-result-message": "Show result message", - "integer-field-settings": "Integer field settings", - "min-value": "Min value", - "max-value": "Max value", - "double-field-settings": "Double field settings", - "text-field-settings": "Text field settings", - "min-length": "Min length", - "max-length": "Max length", - "checkbox-settings": "Checkbox settings", - "true-label": "Checked label", - "false-label": "Unchecked label", - "image-input-settings": "Image input settings", - "display-preview": "Display preview", - "display-clear-button": "Display clear button", - "display-apply-button": "Display apply button", - "display-discard-button": "Display discard button", - "datetime-field-settings": "Date/time field settings", - "display-time-input": "Display time input", - "latitude-key-name": "Latitude key name", - "longitude-key-name": "Longitude key name", - "show-get-location-button": "Show button 'Get current location'", - "use-high-accuracy": "Use high accuracy", - "location-fields-settings": "Location fields settings", - "latitude-label": "Label for latitude", - "longitude-label": "Label for longitude", - "input-fields-alignment": "Input fields alignment", - "input-fields-alignment-column": "Column (default)", - "input-fields-alignment-row": "Row", - "layout": "Layout", - "row-gap": "Gap between rows in pixels", - "column-gap": "Gap between columns in pixels", - "latitude-field-required": "Latitude field required", - "longitude-field-required": "Longitude field required", - "attribute-settings": "Attribute settings", - "widget-mode": "Widget mode", - "widget-mode-update-attribute": "Update attribute", - "widget-mode-update-timeseries": "Update timeseries", - "attribute-scope": "Attribute scope", - "attribute-scope-server": "Server attribute", - "attribute-scope-shared": "Shared attribute", - "value-required": "Value required", - "image-settings": "Image settings", - "image-format": "Image format", - "image-format-jpeg": "JPEG", - "image-format-png": "PNG", - "image-format-webp": "WEBP", - "image-quality": "Image quality that use lossy compression such as jpeg and webp", - "max-image-width": "Maximum image width", - "max-image-height": "Maximum image height", - "action-buttons": "Action buttons", - "show-action-buttons": "Show action buttons", - "update-all-values": "Update all values, not only modified", - "save-button-label": "'SAVE' button label", - "reset-button-label": "'UNDO' button label", - "group-settings": "Group settings", - "show-group-title": "Show title for group of fields, related to different entities", - "group-title": "Group title", - "fields-alignment": "Fields alignment", - "fields-alignment-row": "Row (default)", - "fields-alignment-column": "Column", - "fields-in-row": "Number of fields in the row", - "option-value": "Value (write 'null' for create empty option)", - "option-label": "Label", - "hide-input-field": "Hide input field", - "datakey-type": "Datakey type", - "datakey-type-server": "Server attribute (default)", - "datakey-type-shared": "Shared attribute", - "datakey-type-timeseries": "Timeseries", - "datakey-value-type": "Datakey value type", - "datakey-value-type-string": "String", - "datakey-value-type-double": "Double", - "datakey-value-type-integer": "Integer", - "datakey-value-type-json": "JSON", - "datakey-value-type-boolean-checkbox": "Boolean (Checkbox)", - "datakey-value-type-boolean-switch": "Boolean (Switch)", - "datakey-value-type-date-time": "Date & Time", - "datakey-value-type-date": "Date", - "datakey-value-type-time": "Time", - "datakey-value-type-select": "Select", - "datakey-value-type-color": "Color", - "value-is-required": "Value is required", - "ability-to-edit-attribute": "Ability to edit attribute", - "ability-to-edit-attribute-editable": "Editable (default)", - "ability-to-edit-attribute-disabled": "Disabled", - "ability-to-edit-attribute-readonly": "Read-only", - "disable-on-datakey-name": "Disable on false value of another datakey (specify datakey name)", - "field-appearance": "Field appearance", - "appearance-fill": "Fill", - "appearance-outline": "Outline", - "subscript-sizing": "Subscript sizing", - "subscript-sizing-fixed": "Fixed", - "subscript-sizing-dynamic": "Dynamic", - "slide-toggle-settings": "Slide toggle settings", - "slide-toggle-label-position": "Slide toggle label position", - "slide-toggle-label-position-after": "After", - "slide-toggle-label-position-before": "Before", - "select-options": "Select options", - "no-select-options": "No select options configured", - "add-select-option": "Add select option", - "numeric-field-settings": "Numeric field settings", - "step-interval": "Step interval between values", - "error-messages": "Error messages", - "min-value-error-message": "'Min value' error message", - "max-value-error-message": "'Max value' error message", - "invalid-date-error-message": "'Invalid date' error message", - "invalid-JSON-error-message": "'Invalid JSON' error message", - "icon-settings": "Icon settings", - "dialog-editor-settings": "Dialog editor settings", - "use-custom-icon": "Use custom icon", - "input-cell-icon": "Icon to show before input cell", - "value-conversion-settings": "Value conversion settings", - "get-value-settings": "Get value settings", - "use-get-value-function": "Use getValue function", - "get-value-function": "getValue function", - "set-value-settings": "Set value settings", - "use-set-value-function": "Use setValue function", - "set-value-function": "setValue function", - "json-invalid": "JSON value has an invalid format", - "title": "Title", - "cancel-button-label": "'Cancel' button label" - }, - "invalid-qr-code-text": "Invalid input text for QR code. Input should have a string type", - "qr-code": { - "use-qr-code-text-function": "Use QR code text function", - "qr-code-text-pattern": "QR code text pattern (for ex. '${entityName} | ${keyName} - some text.')", - "qr-code-text-pattern-hint": "QR code text pattern use the value of the first found key in the entities in the entity alias.", - "qr-code-text-pattern-required": "QR code text pattern is required.", - "qr-code-text-function": "QR code text function" - }, - "label-widget": { - "label-pattern": "Pattern", - "label-pattern-hint": "Hint: for ex. 'Text ${keyName} units.' or ${#<key index>} units'", - "label-pattern-required": "Pattern is required", - "label-position": "Position (Percentage relative to background)", - "x-pos": "X", - "y-pos": "Y", - "background-color": "Background color", - "font-settings": "Font settings", - "background-image": "Background image", - "labels": "Labels", - "no-labels": "No labels configured", - "add-label": "Add label" - }, - "navigation": { - "title": "Title", - "navigation-path": "Navigation path", - "filter-type": "Filter type", - "filter-type-all": "All items", - "filter-type-include": "Include items", - "filter-type-exclude": "Exclude items", - "items": "Items", - "enter-urls-to-filter": "Enter urls to filter..." - }, - "persistent-table": { - "rpc-id": "RPC ID", - "message-type": "Message type", - "method": "Method", - "params": "Params", - "created-time": "Created time", - "expiration-time": "Expiration time", - "retries": "Retries", - "status": "Status", - "filter": "Filter", - "refresh": "Refresh", - "add": "Add RPC request", - "details": "Details", - "delete": "Delete", - "delete-request-title": "Delete Persistent RPC request", - "delete-request-text": "Are you sure you want to delete request?", - "details-title": "Details RPC ID: ", - "additional-info": "Additional info", - "response": "Response", - "any-status": "Any status", - "rpc-status-list": "RPC status list", - "no-request-prompt": "No request to display", - "send-request": "Send request", - "add-title": "Create Persistent RPC request", - "method-error": "Method is required.", - "timeout-error": "Min timeout value is 5000 (5 seconds).", - "white-space-error": "White space is not allowed.", - "rpc-status": { - "QUEUED": "QUEUED", - "SENT": "SENT", - "DELIVERED": "DELIVERED", - "SUCCESSFUL": "SUCCESSFUL", - "TIMEOUT": "TIMEOUT", - "EXPIRED": "EXPIRED", - "FAILED": "FAILED" - }, - "rpc-search-status-all": "ALL", - "message-types": { - "false": "Two-way", - "true": "One-way" - }, - "general-settings": "General settings", - "enable-filter": "Enable filter", - "enable-sticky-header": "Display header while scrolling", - "enable-sticky-action": "Display actions column while scrolling", - "display-request-details": "Display request details", - "allow-send-request": "Allow send RPC request", - "allow-delete-request": "Allow delete request", - "columns-settings": "Columns settings", - "display-columns": "Columns to display", - "column": "Column", - "no-columns-found": "No columns found", - "no-columns-matching": "'{{column}}' not found." - }, - "rpc": { - "value-settings": "Value settings", - "initial-value": "Initial value", - "retrieve-value-settings": "Retrieve on/off value settings", - "retrieve-value-method": "Retrieve value using method", - "retrieve-value-method-none": "Don't retrieve", - "retrieve-value-method-rpc": "Call RPC get value method", - "retrieve-value-method-attribute": "Subscribe for attribute", - "retrieve-value-method-timeseries": "Subscribe for timeseries", - "attribute-value-key": "Attribute key", - "timeseries-value-key": "Timeseries key", - "get-value-method": "RPC get value method", - "parse-value-function": "Parse value function", - "update-value-settings": "Update value settings", - "set-value-method": "RPC set value method", - "convert-value-function": "Convert value function", - "rpc-settings": "RPC settings", - "request-timeout": "RPC request timeout (ms)", - "persistent-rpc-settings": "Persistent RPC settings", - "request-persistent": "RPC request persistent", - "persistent-polling-interval": "Polling interval (ms) to get persistent RPC command response", - "common-settings": "Common settings", - "switch-title": "Switch title", - "show-on-off-labels": "Show on/off labels", - "slide-toggle-label": "Slide toggle label", - "label-position": "Label position", - "label-position-before": "Before", - "label-position-after": "After", - "slider-color": "Slider color", - "slider-color-primary": "Primary", - "slider-color-accent": "Accent", - "slider-color-warn": "Warn", - "button-style": "Button style", - "button-raised": "Raised button", - "button-primary": "Primary color", - "button-background-color": "Button background color", - "button-text-color": "Button text color", - "widget-title": "Widget title", - "button-label": "Button label", - "device-attribute-scope": "Device attribute scope", - "server-attribute": "Server attribute", - "shared-attribute": "Shared attribute", - "device-attribute-parameters": "Device attribute parameters", - "is-one-way-command": "Is one way command", - "rpc-method": "RPC method", - "rpc-method-params": "RPC method params", - "show-rpc-error": "Show RPC command execution error", - "led-title": "LED title", - "led-color": "LED color", - "check-status-settings": "Check status settings", - "perform-rpc-status-check": "Perform RPC device status check", - "retrieve-led-status-value-method": "Retrieve led status value using method", - "led-status-value-attribute": "Device attribute containing led status value", - "led-status-value-timeseries": "Device timeseries containing led status value", - "check-status-method": "RPC check device status method", - "parse-led-status-value-function": "Parse led status value function", - "knob-title": "Knob title", - "min-value": "Minimum value", - "max-value": "Maximum value" - }, - "maps": { - "select-entity": "Select entity", - "select-entity-hint": "Hint: after selection click at the map to set position", - "tooltips": { - "placeMarker": "Click to place '{{entityName}}' entity", - "firstVertex": "Polygon for '{{entityName}}': click to place first point", - "firstVertex-cut": "Click to place first point", - "continueLine": "Polygon for '{{entityName}}': click to continue drawing", - "continueLine-cut": "Click to continue drawing", - "finishLine": "Click any existing marker to finish", - "finishPoly": "Polygon for '{{entityName}}': click first marker to finish and save", - "finishPoly-cut": "Click first marker to finish and save", - "finishRect": "Polygon for '{{entityName}}': click to finish and save", - "startCircle": "Circle for '{{entityName}}': click to place circle center", - "finishCircle": "Circle for '{{entityName}}': click to finish circle", - "placeCircleMarker": "Click to place circle marker" - }, - "actions": { - "finish": "Finish", - "cancel": "Cancel", - "removeLastVertex": "Remove last point" - }, - "buttonTitles": { - "drawMarkerButton": "Place entity", - "drawPolyButton": "Create polygon", - "drawLineButton": "Create polyline", - "drawCircleButton": "Create circle", - "drawRectButton": "Create rectangle", - "editButton": "Edit mode", - "dragButton": "Drag-drop mode", - "cutButton": "Cut polygon area", - "deleteButton": "Remove", - "drawCircleMarkerButton": "Create circle marker", - "rotateButton": "Rotate polygon" - }, - "map-provider-settings": "Map provider settings", - "map-provider": "Map provider", - "map-provider-google": "Google maps", - "map-provider-openstreet": "OpenStreet maps", - "map-provider-here": "HERE maps", - "map-provider-image": "Image map", - "map-provider-tencent": "Tencent maps", - "openstreet-provider": "OpenStreet map provider", - "openstreet-provider-mapnik": "OpenStreetMap.Mapnik (Default)", - "openstreet-provider-hot": "OpenStreetMap.HOT", - "openstreet-provider-esri-street": "Esri.WorldStreetMap", - "openstreet-provider-esri-topo": "Esri.WorldTopoMap", - "openstreet-provider-esri-imagery": "Esri.WorldImagery", - "openstreet-provider-cartodb-positron": "CartoDB.Positron", - "openstreet-provider-cartodb-dark-matter": "CartoDB.DarkMatter", - "use-custom-provider": "Use custom provider", - "custom-provider-tile-url": "Custom provider tile URL", - "google-maps-api-key": "Google Maps API Key", - "default-map-type": "Default map type", - "google-map-type-roadmap": "Roadmap", - "google-map-type-satelite": "Satellite", - "google-map-type-hybrid": "Hybrid", - "google-map-type-terrain": "Terrain", - "map-layer": "Map layer", - "here-map-normal-day": "HERE.normalDay (Default)", - "here-map-normal-night": "HERE.normalNight", - "here-map-hybrid-day": "HERE.hybridDay", - "here-map-terrain-day": "HERE.terrainDay", - "credentials": "Credentials", - "here-app-id": "HERE app id", - "here-app-code": "HERE app code", - "here-api-key": "HERE API key", - "here-use-new-version-api-3": "Use API version 3", - "tencent-maps-api-key": "Tencent Maps API Key", - "tencent-map-type-roadmap": "Roadmap", - "tencent-map-type-satelite": "Satellite", - "tencent-map-type-hybrid": "Hybrid", - "image-map-background": "Image map background", - "image-map-background-from-entity-attribute": "Take image map background from entity attribute", - "image-url-source-entity-alias": "Image URL source entity alias", - "image-url-source-entity-attribute": "Image URL source entity attribute", - "common-map-settings": "Common map settings", - "x-pos-key-name": "X position key name", - "y-pos-key-name": "Y position key name", - "latitude-key-name": "Latitude key name", - "longitude-key-name": "Longitude key name", - "default-map-zoom-level": "Default map zoom level (0 - 20)", - "default-map-center-position": "Default map center position (0,0)", - "disable-scroll-zooming": "Disable scroll zooming", - "disable-double-click-zooming": "Disable double click zooming", - "disable-zoom-control-buttons": "Disable zoom control buttons", - "fit-map-bounds": "Fit map bounds to cover all markers", - "use-default-map-center-position": "Use default map center position", - "entities-limit": "Limit of entities to load", - "markers-settings": "Markers settings", - "marker-offset-x": "Marker X offset relative to position multiplied by marker width", - "marker-offset-y": "Marker Y offset relative to position multiplied by marker height", - "position-function": "Position conversion function, should return x,y coordinates as double from 0 to 1 each", - "draggable-marker": "Draggable marker", - "label": "Label", - "show-label": "Show label", - "use-label-function": "Use label function", - "label-pattern": "Label (pattern examples: '${entityName}', '${entityName}: (Text ${keyName} units.)' )", - "label-function": "Label function", - "tooltip": "Tooltip", - "show-tooltip": "Show tooltip", - "show-tooltip-action": "Action for displaying the tooltip", - "show-tooltip-action-click": "Show tooltip on click (Default)", - "show-tooltip-action-hover": "Show tooltip on hover", - "auto-close-tooltips": "Auto-close tooltips", - "use-tooltip-function": "Use tooltip function", - "tooltip-pattern": "Tooltip (for ex. 'Text ${keyName} units.' or Link text')", - "tooltip-function": "Tooltip function", - "tooltip-offset-x": "Tooltip X offset relative to marker anchor multiplied by marker width", - "tooltip-offset-y": "Tooltip Y offset relative to marker anchor multiplied by marker height", - "color": "Color", - "use-color-function": "Use color function", - "color-function": "Color function", - "marker-image": "Marker image", - "use-marker-image-function": "Use marker image function", - "custom-marker-image": "Custom marker image", - "custom-marker-image-size": "Custom marker image size (px)", - "marker-image-function": "Marker image function", - "marker-images": "Marker images", - "polygon-settings": "Polygon settings", - "show-polygon": "Show polygon", - "polygon-key-name": "Polygon key name", - "enable-polygon-edit": "Enable polygon edit", - "polygon-label": "Polygon label", - "show-polygon-label": "Show polygon label", - "use-polygon-label-function": "Use polygon label function", - "polygon-label-pattern": "Polygon label (pattern examples: '${entityName}', '${entityName}: (Text ${keyName} units.)' )", - "polygon-label-function": "Polygon label function", - "polygon-tooltip": "Polygon tooltip", - "show-polygon-tooltip": "Show polygon tooltip", - "auto-close-polygon-tooltips": "Auto-close polygon tooltips", - "use-polygon-tooltip-function": "Use polygon tooltip function", - "polygon-tooltip-pattern": "Tooltip (for ex. 'Text ${keyName} units.' or Link text')", - "polygon-tooltip-function": "Polygon tooltip function", - "polygon-color": "Polygon color", - "polygon-opacity": "Polygon opacity", - "use-polygon-color-function": "Use polygon color function", - "polygon-color-function": "Polygon color function", - "polygon-stroke": "Polygon stroke", - "stroke-color": "Stroke color", - "stroke-opacity": "Stroke opacity", - "stroke-weight": "Stroke weight", - "use-polygon-stroke-color-function": "Use polygon stroke color function", - "polygon-stroke-color-function": "Polygon stroke color function", - "circle-settings": "Circle settings", - "show-circle": "Show circle", - "circle-key-name": "Circle key name", - "enable-circle-edit": "Enable circle edit", - "circle-label": "Circle label", - "show-circle-label": "Show circle label", - "use-circle-label-function": "Use circle label function", - "circle-label-pattern": "Circle label (pattern examples: '${entityName}', '${entityName}: (Text ${keyName} units.)' )", - "circle-label-function": "Circle label function", - "circle-tooltip": "Circle tooltip", - "show-circle-tooltip": "Show circle tooltip", - "auto-close-circle-tooltips": "Auto-close circle tooltips", - "use-circle-tooltip-function": "Use circle tooltip function", - "circle-tooltip-pattern": "Tooltip (for ex. 'Text ${keyName} units.' or Link text')", - "circle-tooltip-function": "Circle tooltip function", - "circle-fill-color": "Circle fill color", - "circle-fill-color-opacity": "Circle fill color opacity", - "use-circle-fill-color-function": "Use circle fill color function", - "circle-fill-color-function": "Circle fill color function", - "circle-stroke": "Circle stroke", - "use-circle-stroke-color-function": "Use circle stroke color function", - "circle-stroke-color-function": "Circle stroke color function", - "markers-clustering-settings": "Markers clustering settings", - "use-map-markers-clustering": "Use map markers clustering", - "zoom-on-cluster-click": "Zoom when clicking on a cluster", - "max-cluster-zoom": "The maximum zoom level when a marker can be part of a cluster (0 - 18)", - "max-cluster-radius-pixels": "Maximum radius that a cluster will cover in pixels", - "cluster-zoom-animation": "Show animation on markers when zooming", - "show-markers-bounds-on-cluster-mouse-over": "Show the bounds of markers when mouse over a cluster", - "spiderfy-max-zoom-level": "Spiderfy at the max zoom level (to see all cluster markers)", - "load-optimization": "Load optimization", - "cluster-chunked-loading": "Use chunks for adding markers so that the page does not freeze", - "cluster-markers-lazy-load": "Use lazy load for adding markers", - "editor-settings": "Editor settings", - "enable-snapping": "Enable snapping to other vertices for precision drawing", - "init-draggable-mode": "Initialize map in draggable mode", - "hide-all-edit-buttons": "Hide all edit control buttons", - "hide-draw-buttons": "Hide draw buttons", - "hide-edit-buttons": "Hide edit buttons", - "hide-remove-button": "Hide remove button", - "route-map-settings": "Route map settings", - "trip-animation-settings": "Trip animation settings", - "normalization-step": "Normalization data step (ms)", - "tooltip-background-color": "Tooltip background color", - "tooltip-font-color": "Tooltip font color", - "tooltip-opacity": "Tooltip opacity (0-1)", - "auto-close-tooltip": "Auto-close tooltip", - "rotation-angle": "Set additional rotation angle for marker (deg)", - "path-settings": "Path settings", - "path-color": "Path color", - "use-path-color-function": "Use path color function", - "path-color-function": "Path color function", - "path-decorator": "Path decorator", - "use-path-decorator": "Use path decorator", - "decorator-symbol": "Decorator symbol", - "decorator-symbol-arrow-head": "Arrow", - "decorator-symbol-dash": "Dash", - "decorator-symbol-size": "Decorator symbol size (px)", - "use-path-decorator-custom-color": "Use path decorator custom color", - "decorator-custom-color": "Decorator custom color", - "decorator-offset": "Decorator offset", - "end-decorator-offset": "End decorator offset", - "decorator-repeat": "Decorator repeat", - "points-settings": "Points settings", - "show-points": "Show points", - "point-color": "Point color", - "point-size": "Point size (px)", - "use-point-color-function": "Use point color function", - "point-color-function": "Point color function", - "use-point-as-anchor": "Use point as anchor", - "point-as-anchor-function": "Point as anchor function", - "independent-point-tooltip": "Independent point tooltip", - "clustering-markers": "Clustering markers", - "use-icon-create-function": "Use markers colour function", - "marker-color-function": "Marker color function" - }, - "markdown": { - "use-markdown-text-function": "Use markdown/HTML value function", - "markdown-text-function": "Markdown/HTML value function", - "markdown-text-pattern": "Markdown/HTML pattern (markdown or HTML with variables, for ex. '${entityName} or ${keyName} - some text.')", - "apply-default-markdown-style": "Apply default markdown style", - "markdown-css": "Markdown/HTML CSS" - }, - "simple-card": { - "label": "Label", - "label-position": "Label position", - "label-position-left": "Left", - "label-position-top": "Top" - }, - "value-card": { - "layout": "Layout", - "layout-square": "Square", - "layout-vertical": "Vertical", - "layout-centered": "Centered", - "layout-simplified": "Simplified", - "layout-horizontal": "Horizontal", - "layout-horizontal-reversed": "Horizontal reversed", - "label": "Label", - "icon": "Icon", - "value": "Value", - "date": "Date", - "value-card-style": "Value card style" - }, - "aggregated-value-card": { - "subtitle": "Subtitle", - "chart": "Chart", - "values": "Values", - "value-appearance": "Value appearance", - "position": "Position", - "position-center": "Center", - "position-right-top": "Right top", - "position-right-bottom": "Right bottom", - "position-left-top": "Left top", - "position-left-bottom": "Left bottom", - "font": "Font", - "color": "Color", - "arrow": "Arrow", - "display-up-down-arrow": "Display Up/Down arrow", - "add-value": "Add value", - "remove-value": "Remove value", - "no-values": "No values configured", - "aggregation": "Aggregation", - "aggregated-value-card-style": "Aggregated value card style" - }, - "alarm-count": { - "alarm-count-card-style": "Alarm count card style" - }, - "entity-count": { - "entity-count-card-style": "Entity count card style" - }, - "count": { - "layout": "Layout", - "layout-column": "Column", - "layout-row": "Row", - "label": "Label", - "icon": "Icon", - "icon-background": "Icon background", - "value": "Value", - "chevron": "Chevron" - }, - "table": { - "common-table-settings": "Common Table Settings", - "enable-search": "Enable search", - "enable-sticky-header": "Always display header", - "enable-sticky-action": "Always display actions column", - "hidden-cell-button-display-mode": "Hidden cell button actions display mode", - "show-empty-space-hidden-action": "Show empty space instead of hidden cell button action", - "dont-reserve-space-hidden-action": "Don't reserve space for hidden action buttons", - "display-timestamp": "Display timestamp column", - "display-milliseconds": "Display timestamp milliseconds", - "display-pagination": "Display pagination", - "default-page-size": "Default page size", - "use-entity-label-tab-name": "Use entity label in tab name", - "hide-empty-lines": "Hide empty lines", - "row-style": "Row style", - "use-row-style-function": "Use row style function", - "row-style-function": "Row style function", - "cell-style": "Cell style", - "use-cell-style-function": "Use cell style function", - "cell-style-function": "Cell style function", - "cell-content": "Cell content", - "use-cell-content-function": "Use cell content function", - "cell-content-function": "Cell content function", - "show-latest-data-column": "Show latest data column", - "latest-data-column-order": "Latest data column order", - "entities-table-title": "Entities table title", - "enable-select-column-display": "Enable select columns to display", - "display-entity-name": "Display entity name column", - "entity-name-column-title": "Entity name column title", - "display-entity-label": "Display entity label column", - "entity-label-column-title": "Entity label column title", - "display-entity-type": "Display entity type column", - "default-sort-order": "Default sort order", - "custom-title": "Custom header title", - "column-width": "Column width (px or %)", - "default-column-visibility": "Default column visibility", - "column-visibility-visible": "Visible", - "column-visibility-hidden": "Hidden", - "column-visibility-hidden-mobile": "Hidden in mobile mode", - "column-selection-to-display": "Column selection in 'Columns to Display'", - "column-selection-to-display-enabled": "Enabled", - "column-selection-to-display-disabled": "Disabled", - "column-export-option": "Include column in export", - "column-export-option-always": "Always", - "column-export-option-only-visible": "Only if column visible", - "column-export-option-never": "Never", - "alarms-table-title": "Alarms table title", - "enable-alarms-selection": "Enable alarms selection", - "enable-alarms-search": "Enable alarms search", - "enable-alarm-filter": "Enable alarm filter", - "display-alarm-details": "Display alarm details", - "allow-alarms-ack": "Allow alarms acknowledgment", - "allow-alarms-clear": "Allow alarms clear", - "display-alarm-activity": "Display alarm activity", - "allow-alarms-assign": "Allow alarms assignment", - "blob-entities-table-title": "Blob entities table title", - "display-created-time": "Display created time column", - "display-type": "Display type column", - "display-customer": "Display customer column", - "no-data-display-message": "\"No data to display\" alternative message", - "force-default-blob-entity-type": "Force default blob entity type", - "scheduler-events-table-title": "Scheduler events table title", - "force-default-event-type": "Force default event type", - "columns": "Columns", - "column-settings": "Column settings", - "remove-column": "Remove column", - "add-column": "Add column", - "no-columns": "No columns configured", - "columns-to-display": "Columns to display", - "table-header": "Table header", - "header-buttons": "Header buttons", - "table-buttons": "Table buttons", - "pagination": "Pagination", - "rows": "Rows", - "timeseries-column-error": "At least one timeseries column should be specified", - "table-tabs": "Table tabs", - "show-cell-actions-menu-mobile": "Show cell actions dropdown menu in mobile mode" - }, - "scheduler": { - "enabled-scheduler-event-views": "Enabled scheduler events views", - "enabled-scheduler-event-views-both": "Both", - "enabled-scheduler-event-views-list": "List View Only", - "enabled-scheduler-event-views-calendar": "Calendar View Only", - "display-name": "Display name", - "type-name": "Type name", - "display-originator-select": "Display originator entity select", - "display-message-type-select": "Display message type select", - "display-metadata-table": "Display message metadata table", - "configuration-html-template": "Configuration HTML template", - "custom-event-types": "Custom event types", - "no-custom-event-types": "No custom event types configured", - "add-custom-event-type": "Add custom event type" - }, - "value-source": { - "value-source": "Value source", - "predefined-value": "Predefined value", - "entity-attribute": "Entity attribute", - "value": "Value", - "source-entity-alias": "Source entity alias", - "source-entity-attribute": "Source entity attribute" - }, - "widget-font": { - "font-settings": "Font settings", - "font-family": "Font family", - "size": "Size", - "relative-font-size": "Relative font size (percents)", - "font-style": "Style", - "font-style-normal": "Normal", - "font-style-italic": "Italic", - "font-style-oblique": "Oblique", - "font-weight": "Weight", - "font-weight-normal": "Normal", - "font-weight-bold": "Bold", - "font-weight-bolder": "Bolder", - "font-weight-lighter": "Lighter", - "color": "Color", - "shadow-color": "Shadow color", - "preview": "Preview", - "line-height": "Line height", - "auto": "Auto" - }, - "home": { - "no-data-available": "No data available" - }, - "system-info": { - "cpu": "CPU", - "ram": "RAM", - "disk": "Disk", - "cpu-warning-text": "Running high on CPU usage. To avoid system failure, optimize system performance.", - "cpu-critical-text": "Critically high CPU usage. To avoid system failure, optimize system performance.", - "ram-warning-text": "Running low on reserve of RAM. To avoid system failure, optimize system performance or increase the size of RAM.", - "ram-critical-text": "Critically low reserve of RAM. To avoid system failure, optimize system performance or increase the size of RAM.", - "disk-warning-text": "Running low on disk space. To avoid data loss, free up or expand the disk space.", - "disk-critical-text": "Critically low disk space. To avoid data loss, free up or expand the disk space." - }, - "cluster-info": { - "service-id": "Service id", - "service-type": "Service type", - "no-data": "No data" - }, - "transport-messages": { - "title": "Transport messages", - "info": "All the messages that came from devices" - }, - "activity": { - "title": "Activity" - }, - "documentation": { - "title": "Documentation", - "add-link": "Add link", - "add-link-title": "Add documentation link", - "name": "Name", - "name-required": "Name is required.", - "link": "Link", - "link-required": "Link is required.", - "columns": "Columns" - }, - "quick-links": { - "title": "Quick links", - "add-link": "Add link", - "add-link-title": "Add quick link", - "quick-link": "Quick link", - "quick-link-required": "Quick link is required.", - "no-links-matching": "No links matching '{{name}}' were found.", - "columns": "Columns" - }, - "recent-dashboards": { - "title": "Dashboards", - "last": "Last viewed", - "starred": "Starred", - "name": "Name", - "last-viewed": "Last viewed", - "no-last-viewed-dashboards": "No last viewed dashboards yet" + "system-info": { + "cpu": "CPU", + "ram": "RAM", + "disk": "Diskas", + "cpu-warning-text": "Didelis procesoriaus apkrovimas. Siekiant išvengti sistemos gedimo, optimizuokite našumą.", + "cpu-critical-text": "Kritiškai didelis procesoriaus apkrovimas. Nedelsiant optimizuokite sistemos našumą.", + "ram-warning-text": "Mažas RAM rezervas. Padidinkite RAM arba optimizuokite sistemos veikimą.", + "ram-critical-text": "Kritiškai mažas RAM rezervas. Būtina optimizacija arba RAM padidinimas.", + "disk-warning-text": "Mažai vietos diske. Išvalykite arba išplėskite disko talpą.", + "disk-critical-text": "Kritiškai mažai vietos diske. Skubiai atlaisvinkite arba išplėskite talpą." + }, + "cluster-info": { + "service-id": "Paslaugos ID", + "service-type": "Paslaugos tipas", + "no-data": "Nėra duomenų" + }, + "transport-messages": { + "title": "Transporto pranešimai", + "info": "Visi pranešimai, gauti iš įrenginių" + }, + "activity": { + "title": "Aktyvumas" + }, + "documentation": { + "title": "Dokumentacija", + "add-link": "Pridėti nuorodą", + "add-link-title": "Pridėti dokumentacijos nuorodą", + "name": "Pavadinimas", + "name-required": "Pavadinimas yra privalomas.", + "link": "Nuoroda", + "link-required": "Nuoroda yra privaloma.", + "columns": "Stulpeliai" + }, + "quick-links": { + "title": "Greitosios nuorodos", + "add-link": "Pridėti nuorodą", + "add-link-title": "Pridėti greitąją nuorodą", + "quick-link": "Greitoji nuoroda", + "quick-link-required": "Greitoji nuoroda yra privaloma.", + "no-links-matching": "Nuorodų, atitinkančių '{{name}}', nerasta.", + "columns": "Stulpeliai" + }, + "recent-dashboards": { + "title": "Valdymo skydeliai", + "last": "Paskutiniai peržiūrėti", + "starred": "Pažymėti žvaigždute", + "name": "Pavadinimas", + "last-viewed": "Paskutinį kartą peržiūrėtas", + "no-last-viewed-dashboards": "Dar nėra peržiūrėtų skydelių" + }, + "configured-features": { + "title": "Sukonfigūruotos funkcijos", + "info": "Funkcijų, kurioms reikia konfigūracijos, būsena", + "email-feature": "El. paštas", + "sms-feature": "SMS", + "slack-feature": "Slack", + "oauth2-feature": "OAuth 2", + "2fa-feature": "Dvigubas autentifikavimas (2FA)", + "feature-configured": "Funkcija sukonfigūruota.\nSpustelėkite, kad nustatytumėte", + "feature-not-configured": "Funkcija nesukonfigūruota.\nSpustelėkite, kad nustatytumėte" + }, + "version-info": { + "title": "Versija", + "contact-us": "Susisiekite su mumis", + "current-version": "Dabartinė versija", + "current": "Dabartinė", + "available-version": "Prieinama versija", + "available": "Prieinama", + "upgrade": "Atnaujinti", + "version-is-up-to-date": "Versija yra naujausia" + }, + "usage-info": { + "title": "Naudojimas", + "entities": "Objektai", + "api-calls": "API užklausos" + }, + "functions": { + "title": "Funkcijos", + "pe-feature-tooltip": "Galima tik ThingsBoard\nProfessional Edition versijoje", + "switch-to-pe": "Pereiti į PE versiją", + "alarms": "Aliarmai", + "dashboards": "Valdymo skydeliai", + "entities-and-relations": "Objektai ir ryšiai", + "profiles": "Profiliai", + "advanced-features": "Išplėstinės funkcijos", + "notification-center": "Pranešimų centras", + "api-usage": "API naudojimas", + "customers": "Klientai", + "customers-hierarchy": "Klientų hierarchija", + "roles-and-permissions": "Vaidmenys ir leidimai", + "groups": "Grupės", + "integrations": "Integracijos", + "solution-templates": "Sprendimų šablonai", + "scheduler": "Tvarkaraštis", + "white-labeling": "Prekinio ženklo pritaikymas (White-labeling)" + }, + "devices": { + "view-docs": "Peržiūrėti dokumentaciją", + "inactive": "Neaktyvūs", + "active": "Aktyvūs", + "total": "Iš viso" + }, + "alarms": { + "critical": "Kritiniai", + "assigned-to-me": "Priskirti man", + "total": "Iš viso" + }, + "getting-started": { + "get-started": "Pradėti", + "finish": "Baigti", + "done-welcome-title": "Sveiki atvykę!", + "done-welcome-text": "Puikiai susitvarkėte!", + "sys-admin": { + "step1": { + "title": "Sukurkite nuomininką ir jo administratorių", + "content": "

Nuomininkas – tai fizinis ar juridinis asmuo, turintis arba valdantis įrenginius ir išteklius. Nuomininkas gali turėti kelis administratoriaus vartotojus, klientus, įrenginius ir išteklius.

Nuomininko administratorius gali kurti ir valdyti įrenginius, išteklius, klientus bei valdymo skydelius nuomininko paskyroje.

Sekite dokumentaciją, kaip tai atlikti:

", + "how-to-create-tenant": "Kaip sukurti nuomininką ir jo administratorių" }, - "configured-features": { - "title": "Configured features", - "info": "Status of features that require configuration", - "white-labeling-feature": "White labeling", - "email-feature": "Email", - "sms-feature": "SMS", - "slack-feature": "Slack", - "oauth2-feature": "OAuth 2", - "2fa-feature": "2FA", - "feature-configured": "Feature is configured.\nClick to setup", - "feature-not-configured": "Feature is not configured.\nClick to setup" + "step2": { + "title": "Sukonfigūruokite funkciją: Pašto serveris", + "content": "

Pašto serverio konfigūracija būtina vartotojų aktyvavimui, slaptažodžio atkūrimui ir aliarmų pranešimų siuntimui.

Sekite dokumentaciją, kaip tai atlikti:

", + "how-to-configure-mail-server": "Kaip sukonfigūruoti pašto serverį" }, - "version-info": { - "title": "Version", - "contact-us": "Contact us", - "current-version": "Current version", - "current": "Current", - "available-version": "Available version", - "available": "Available", - "upgrade": "Upgrade", - "version-is-up-to-date": "Version is up to date" + "step3": { + "title": "Sukonfigūruokite funkciją: SMS tiekėjas", + "content": "

Sukonfigūruokite SMS tiekėjus, kad klientai gautų aliarmų pranešimus SMS žinutėmis.

Sekite dokumentaciją, kaip tai atlikti:

", + "how-to-configure-sms-provider": "Kaip sukonfigūruoti SMS tiekėją" }, - "license-info": { - "title": "License info", - "view-all": "View all", - "license-portal": "License portal", - "devices-info": "{count} / { max, plural, =0 {∞} other {#} } Devices", - "assets-info": "{count} / { max, plural, =0 {∞} other {#} } Assets", - "dashboards-info": "{count} / { max, plural, =0 {∞} other {#} } Dashboards", - "integrations-info": "{count} / { max, plural, =0 {∞} other {#} } Integrations", - "community-support": "Community support", - "white-labeling": "White labeling", - "unlimited-datapoints-and-messages": "Unlimited datapoints and messages", - "unlimited-api-calls": "Unlimited API calls" + "step4": { + "title": "Sukonfigūruokite funkciją: Prekinio ženklo pritaikymas", + "content": "

Lengvai pritaikykite savo įmonės ar produkto logotipą ir spalvų schemą be programavimo ir paslaugos paleidimo iš naujo.

Sekite dokumentaciją, kaip tai atlikti:

" }, - "usage-info": { - "title": "Usage", - "entities": "Entities", - "api-calls": "API calls" + "step5": { + "title": "Sukonfigūruokite funkciją: Dvigubas autentifikavimas (2FA)", + "content": "

Pagerinkite paskyrų saugumą naudodami dviejų faktorių autentifikavimą.

Sekite dokumentaciją, kaip tai atlikti:

" }, - "functions": { - "title": "Functions", - "pe-feature-tooltip": "Only on ThingsBoard\nProfessional Edition", - "switch-to-pe": "Switch to PE", - "alarms": "Alarms", - "dashboards": "Dashboards", - "entities-and-relations": "Entities & Relations", - "profiles": "Profiles", - "advanced-features": "Advanced features", - "notification-center": "Notification center", - "api-usage": "API usage", - "customers": "Customers", - "customers-hierarchy": "Customers hierarchy", - "roles-and-permissions": "Roles & Permissions", - "groups": "Groups", - "integrations": "Integrations", - "solution-templates": "Solution templates", - "scheduler": "Scheduler", - "white-labeling": "White-labeling" + "step6": { + "title": "Sukonfigūruokite funkciją: OAuth 2", + "content": "

Supaprastinkite nuomininko ir kliento vartotojų prisijungimą naudodami vieningo prisijungimo (Single Sign-On) funkciją per OAuth 2.0.

Sekite dokumentaciją, kaip tai atlikti:

" + } + }, + "tenant-admin": { + "step1": { + "title": "Sukurti įrenginį", + "content": "

Sukurkite savo pirmąjį įrenginį platformoje per naudotojo sąsają (UI). Sekite dokumentaciją, kaip tai atlikti:

", + "how-to-create-device": "Kaip sukurti įrenginį" }, - "devices": { - "view-docs": "View docs", - "inactive": "Inactive", - "active": "Active", - "total": "Total" + "step2": { + "title": "Prijungti įrenginį", + "content-before": "

Norint prijungti įrenginį, reikia gauti jo prisijungimo duomenis. Šiame vadove rekomenduojame naudoti numatytuosius automatiškai sugeneruotus prisijungimo duomenis – prieigos raktą (Access Token).

  • Eikite į įrenginių lentelę
  • Spustelėkite įrenginio eilutę, kad atidarytumėte jo informaciją
  • Paspauskite mygtuką „Kopijuoti prieigos raktą“

Naudokite paprastas HTTP komandas duomenų publikavimui. Nepamirškite pakeisti $ACCESS_TOKEN savo įrenginio prieigos raktu:

", + "ubuntu": { + "install-curl": "Įdiekite cURL Ubuntu sistemoje:" + }, + "macos": { + "install-curl": "Įdiekite cURL MacOS sistemoje:" + }, + "windows": { + "install-curl": "Nuo Windows 10 b17063 versijos cURL yra įdiegtas pagal nutylėjimą." + }, + "replace-access-token": "Pakeiskite $ACCESS_TOKEN savo įrenginio prieigos raktu:", + "content-after": "

Taip pat galite naudoti kitus protokolus, tokius kaip MQTT, CoAP ir kt.

Sekite dokumentaciją, kaip tai atlikti:

", + "how-to-connect-device": "Kaip prijungti įrenginį" }, - "alarms": { - "critical": "Critical", - "assigned-to-me": "Assigned to me", - "total": "Total" + "step3": { + "title": "Sukurti valdymo skydelį", + "content": "

Sukurkite valdymo skydelį duomenų vizualizavimui iš objektų, tokių kaip įrenginiai ar ištekliai.

Sekite dokumentaciją, kaip tai atlikti:

", + "how-to-create-dashboard": "Kaip sukurti valdymo skydelį" }, - "solution-templates": { - "title": "Solution templates", - "prototype-plan": "Prototype plan", - "startup-plan": "Startup plan" + "step4": { + "title": "Sukonfigūruoti aliarmo taisykles", + "alarm-rules": "Aliarmo taisyklės", + "content": "

Sukurkime aliarmą, kuris suveiks, kai temperatūra pasieks 25°C. Sekite dokumentaciją, kaip tai atlikti:

", + "how-to-configure-alarm-rules": "Kaip sukonfigūruoti aliarmo taisykles" }, - "getting-started": { - "get-started": "Get started", - "finish": "Finish", - "done-welcome-title": "Welcome on board", - "done-welcome-text": "You did great with it!", - "sys-admin": { - "step1": { - "title": "Create Tenant & Tenant Administrator", - "content": "

A tenant is an individual or an organization that owns or produces devices and assets. The tenant may have multiple tenant administrator users, customers, devices, and assets.

The Tenant Administrator can create and manage devices, assets, customers, and dashboards within the tenant account.

Follow the documentation on how to do it:

", - "how-to-create-tenant": "How to create Tenant & Tenant Administrator" - }, - "step2": { - "title": "Configure feature: Mail server", - "content": "

Mail server configuration is essential for user activation, password recovery, and alarm notification delivery.

Follow the documentation on how to do it:

", - "how-to-configure-mail-server": "How to configure Mail server" - }, - "step3": { - "title": "Configure feature: SMS provider", - "content": "

Configure SMS providers to notify the customers about the alarms via SMS.

Follow the documentation on how to do it:

", - "how-to-configure-sms-provider": "How to configure SMS provider" - }, - "step4": { - "title": "Configure feature: White-labeling", - "content": "

Easily customize your company's or product's logo and color scheme without coding and without restarting the service.

Follow the documentation on how to do it:

", - "how-to-configure-white-labeling": "How to configure White-labeling" - }, - "step5": { - "title": "Configure feature: 2FA", - "content": "

Improve security of the platform accounts with two-factor authentication.

Follow the documentation on how to do it:

", - "how-to-configure-2fa": "How to configure 2FA" - }, - "step6": { - "title": "Configure feature: OAuth 2", - "content": "

Simplify login for the tenant and customer users with Single Sign-On functionality via OAuth 2.0.

Follow the documentation on how to do it:

", - "how-to-configure-oauth2": "How to configure OAuth 2" - }, - "step7": { - "title": "Configure feature: Slack", - "content": "

Distribute notifications to the tenant and customer users via Slack according to the notification rules you set.

Follow the documentation on how to do it:

", - "how-to-configure-notifications": "How to configure Slack" - } - }, - "tenant-admin": { - "step1": { - "title": "Create device", - "content": "

Let's provision your first device to the platform via UI. Follow the documentation on how to do it:

", - "how-to-create-device": "How to create Device" - }, - "step2": { - "title": "Connect device", - "content-before": "

To connect the device you need to get the device credentials. We recommend using default auto-generated credentials which is access token for this guide.

  • Go to device table
  • Click on the device row to open device details
  • Press the button \"Copy access token\"

Use simple commands to publish data over HTTP. Don't forget to replace $ACCESS_TOKEN with your device access token:

", - "ubuntu": { - "install-curl": "Install cURL for Ubuntu:" - }, - "macos": { - "install-curl": "Install cURL for MacOS:" - }, - "windows": { - "install-curl": "Starting Windows 10 b17063, cURL is available by default." - }, - "replace-access-token": "Replace $ACCESS_TOKEN with your device's token:", - "content-after": "

You can also use other protocols such as MQTT, CoAP, etc.

Follow the documentation on how to do it:

", - "how-to-connect-device": "How to connect Device" - }, - "step3": { - "title": "Create dashboard", - "content": "

Create a dashboard to visualize data from entities such as assets, devices, etc.

Follow the documentation on how to do it:

", - "how-to-create-dashboard": "How to create Dashboard" - }, - "step4": { - "title": "Configure alarm rules", - "alarm-rules": "Alarm rules", - "content": "

Let's raise an alarm when the temperature reaches 25°C. Follow the documentation on how to do it:

", - "how-to-configure-alarm-rules": "How to configure Alarm rules" - }, - "step5": { - "title": "Create alarm", - "content-before": "

To trigger the alarm, send a new telemetry value of 26°C or higher.

", - "replace-access-token": "Replace $ACCESS_TOKEN with your device's token:", - "content-after": "

Follow the documentation on how to do it:

", - "how-to-create-alarm": "How to create Alarm" - }, - "step6": { - "title": "Create customer and share dashboard", - "content": "

By creating end-user dashboards, a customer user can only see his own devices, and data from another customer will be hidden.

Follow the documentation on how to do it:

", - "how-to-create-customer-and-share-dashboard": "How to create Customer and share Dashboard" - } - } - } - }, - "icon": { - "icon": "Icon", - "icons": "Icons", - "select-icon": "Select icon", - "material-icons": "Material icons", - "show-all": "Show all icons", - "search-icon": "Search icon", - "no-icons-found": "No icons found for '{{iconSearch}}'" - }, - "subscription": { - "entity-limit-text": "However you can upgrade your subscription plan in order to increase your limits.", - "upgrade-your-plan": "Upgrade subscription plan", - "white-labeling-feature": "White labeling feature", - "white-labeling-text-full": "Rebrand ThingsBoard platform web interface with your company or product logo and color scheme in 2 minutes.

Remove “Powered By” on the dashboards footer.
No coding or service restart required. Allow your customers to white-label their interface as well.", - "enable-white-labeling": "Enable white-labeling feature now by upgrading your subscription plan!", - "read-more": "Read more", - "white-labeling-video-text": "See video tutorial below to see how this feature works!" - }, - "subscription-error": { - "title": "Subscription violation", - "warning-title": "Subscription warning", - "upgrade-subscription-plan": "Please upgrade your subscription plan", - "upgrade-subscription-plan-to-install-solution-template": "In order to install {{solutionTemplateName}} solution you must upgrade your subscription at least to the {{planName}} plan!", - "limit-reached": { - "device-count": "You have reached maximum devices ({{value}}) allowed by your subscription plan!", - "asset-count": "You have reached maximum assets ({{value}}) allowed by your subscription plan!" + "step5": { + "title": "Sukurti aliarmą", + "content-before": "

Norėdami suaktyvinti aliarmą, siųskite naują telemetrijos reikšmę, didesnę arba lygią 26°C.

", + "replace-access-token": "Pakeiskite $ACCESS_TOKEN savo įrenginio prieigos raktu:", + "content-after": "

Sekite dokumentaciją, kaip tai atlikti:

", + "how-to-create-alarm": "Kaip sukurti aliarmą" }, - "feature-disabled": { - "white-labeling": "White Labeling feature is not allowed by your subscription plan!" - } - }, - "phone-input": { - "phone-input-label": "Phone number", - "phone-input-required": "Phone number is required", - "phone-input-validation": "Phone number is invalid or not possible", - "phone-input-pattern": "Invalid phone number. Should be in E.164 format, ex. {{phoneNumber}}", - "phone-input-hint": "Telefono numeris tarptautiniu formatu , pvz. +37060123456" - }, - "custom": { - "widget-action": { - "action-cell-button": "Action cell button", - "row-click": "On row click", - "polygon-click": "On polygon click", - "marker-click": "On marker click", - "circle-click": "On circle click", - "tooltip-tag-action": "Tooltip tag action", - "node-selected": "On node selected", - "element-click": "On HTML element click", - "pie-slice-click": "On slice click", - "row-double-click": "On row double click", - "card-click": "On card click" + "step6": { + "title": "Sukurti klientą ir pasidalyti valdymo skydeliu", + "content": "

Sukūrę galutinio naudotojo valdymo skydelius, kliento vartotojas matys tik savo įrenginius, o kitų klientų duomenys bus paslėpti.

Sekite dokumentaciją, kaip tai atlikti:

" } - }, - "paginator": { - "items-per-page": "Eilučių skaičius puslapyje:", - "first-page-label": "Pirmas puslapis", - "last-page-label": "Paskutinis puslapis", - "next-page-label": "Kitas puslapis", - "previous-page-label": "Ankstesnis puslapis", - "items-per-page-separator": "iš" + } + } + }, + "icon": { + "icon": "Piktograma", + "icons": "Piktogramos", + "select-icon": "Pasirinkti piktogramą", + "material-icons": "Material piktogramos", + "show-all": "Rodyti visas piktogramas", + "search-icon": "Ieškoti piktogramos", + "no-icons-found": "Nerasta piktogramų pagal '{{iconSearch}}'" + }, + "phone-input": { + "phone-input-label": "Telefono numeris", + "phone-input-required": "Telefono numeris yra privalomas", + "phone-input-validation": "Telefono numeris yra neteisingas arba neįmanomas", + "phone-input-pattern": "Neteisingas telefono numeris. Formatą turi atitikti E.164, pvz. {{phoneNumber}}", + "phone-input-hint": "Telefono numeris tarptautiniu formatu, pvz. +37060123456" + }, + "custom": { + "widget-action": { + "action-cell-button": "Veiksmo langelio mygtukas", + "row-click": "Paspaudus eilutę", + "cell-click": "Paspaudus langelį", + "polygon-click": "Paspaudus daugiakampį", + "marker-click": "Paspaudus žymeklį", + "circle-click": "Paspaudus apskritimą", + "tooltip-tag-action": "Patarimo žymos veiksmas", + "node-selected": "Pasirinkus mazgą", + "element-click": "Paspaudus HTML elementą", + "pie-slice-click": "Paspaudus diagramos dalį", + "row-double-click": "Dukart paspaudus eilutę", + "cell-double-click": "Dukart paspaudus langelį", + "card-click": "Paspaudus kortelę", + "click": "Paspaudus" } + }, + "paginator": { + "items-per-page": "Eilučių skaičius puslapyje:", + "first-page-label": "Pirmas puslapis", + "last-page-label": "Paskutinis puslapis", + "next-page-label": "Kitas puslapis", + "previous-page-label": "Ankstesnis puslapis", + "items-per-page-separator": "iš" + }, + "language": { + "language": "Kalba" + } } - diff --git a/ui-ngx/src/assets/locale/locale.constant-nl_NL.json b/ui-ngx/src/assets/locale/locale.constant-nl_NL.json index 379f36b9de..810f49ff00 100644 --- a/ui-ngx/src/assets/locale/locale.constant-nl_NL.json +++ b/ui-ngx/src/assets/locale/locale.constant-nl_NL.json @@ -128,26 +128,26 @@ "port-range": "Poort moet tussen 1 en 65535 liggen." }, "mail-from": "Afzenderadres", - "mail-from-required": "Afzenderadres is verplicht.", + "mail-from-required": "Afzenderadres is vereist.", "smtp-protocol": "SMTP-protocol", "smtp-host": "SMTP-host", - "smtp-host-required": "SMTP-host is verplicht.", + "smtp-host-required": "SMTP-host is vereist.", "smtp-port": "SMTP-poort", "smtp-port-required": "U moet een SMTP-poort opgeven.", - "smtp-port-invalid": "Dit lijkt geen geldige SMTP-poort.", + "smtp-port-invalid": "Dat lijkt geen geldige SMTP-poort te zijn.", "timeout-msec": "Timeout (msec)", - "timeout-required": "Timeout is verplicht.", - "timeout-invalid": "Dit lijkt geen geldige timeout.", + "timeout-required": "Timeout is vereist.", + "timeout-invalid": "Dat lijkt geen geldige timeout te zijn.", "enable-tls": "TLS inschakelen", "tls-version": "TLS-versie", "enable-proxy": "Proxy inschakelen", - "proxy-host": "Proxyhost", - "proxy-host-required": "Proxyhost is verplicht.", - "proxy-port": "Proxypoort", - "proxy-port-required": "Proxypoort is verplicht.", - "proxy-port-range": "Proxypoort moet tussen 1 en 65535 liggen.", - "proxy-user": "Proxygebruiker", - "proxy-password": "Proxywachtwoord", + "proxy-host": "Proxy-host", + "proxy-host-required": "Proxy-host is vereist.", + "proxy-port": "Proxy-poort", + "proxy-port-required": "Proxy-poort is vereist.", + "proxy-port-range": "Proxy-poort moet liggen tussen 1 en 65535.", + "proxy-user": "Proxy-gebruiker", + "proxy-password": "Proxy-wachtwoord", "change-password": "Wachtwoord wijzigen", "send-test-mail": "Testmail verzenden", "sms-provider": "SMS-provider", @@ -538,14 +538,20 @@ "info-message": "Wijziging van de JWT-ondertekeningssleutel maakt alle uitgegeven tokens ongeldig. Alle gebruikers moeten opnieuw inloggen. Dit heeft ook invloed op scripts die gebruikmaken van de REST API/Websockets." }, "resources": "Bronnen", - "notifications": "Meldingen", - "notifications-settings": "Meldingsinstellingen", + "notifications": "Notificaties", + "notifications-settings": "Notificatie-instellingen", "slack-api-token": "Slack API-token", "slack": "Slack", "slack-settings": "Slack-instellingen", "mobile-settings": "Mobiele instellingen", - "firebase-service-account-file": "Firebase serviceaccount referenties JSON-bestand", - "select-firebase-service-account-file": "Sleep uw Firebase serviceaccountbestand hierheen of " + "firebase-service-account-file": "Firebase serviceaccountreferenties JSON-bestand", + "select-firebase-service-account-file": "Sleep je Firebase serviceaccountreferentiesbestand hierheen of ", + "trendz": "Trendz", + "trendz-settings": "Trendz-instellingen", + "trendz-url": "Trendz-URL", + "trendz-url-required": "Trendz-URL is vereist", + "trendz-api-key": "Trendz API-sleutel", + "trendz-enable": "Trendz inschakelen" }, "alarm": { "alarm": "Alarm", @@ -612,43 +618,43 @@ "search": "Alarmen zoeken", "selected-alarms": "{ count, plural, =1 {1 alarm} other {# alarmen} } geselecteerd", "no-data": "Geen gegevens om weer te geven", - "polling-interval": "Polling-interval voor alarmen (sec)", - "polling-interval-required": "Polling-interval voor alarmen is verplicht.", - "min-polling-interval-message": "Minimaal toegestaan polling-interval is 1 seconde.", - "aknowledge-alarms-title": "{ count, plural, =1 {1 alarm bevestigen} other {# alarmen bevestigen} }", - "aknowledge-alarms-text": "Weet u zeker dat u { count, plural, =1 {1 alarm} other {# alarmen} } wilt bevestigen?", - "aknowledge-alarm-title": "Alarm bevestigen", - "aknowledge-alarm-text": "Weet u zeker dat u het alarm wilt bevestigen?", - "selected-alarms-are-acknowledged": "Geselecteerde alarmen zijn al bevestigd", - "clear-alarms-title": "{ count, plural, =1 {1 alarm zuiveren} other {# alarmen zuiveren} }", - "clear-alarms-text": "Weet u zeker dat u { count, plural, =1 {1 alarm} other {# alarmen} } wilt zuiveren?", - "clear-alarm-title": "Alarm zuiveren", - "clear-alarm-text": "Weet u zeker dat u het alarm wilt zuiveren?", - "delete-alarms-title": "{ count, plural, =1 {1 alarm verwijderen} other {# alarmen verwijderen} }", + "polling-interval": "Poll-interval voor alarmen (sec)", + "polling-interval-required": "Poll-interval voor alarmen is vereist.", + "min-polling-interval-message": "Minimaal 1 seconde poll-interval is toegestaan.", + "aknowledge-alarms-title": "Erken { count, plural, =1 {1 alarm} other {# alarmen} }", + "aknowledge-alarms-text": "Weet u zeker dat u { count, plural, =1 {1 alarm} other {# alarmen} } wilt erkennen?", + "aknowledge-alarm-title": "Alarm erkennen", + "aknowledge-alarm-text": "Weet u zeker dat u dit alarm wilt erkennen?", + "selected-alarms-are-acknowledged": "Geselecteerde alarmen zijn al erkend", + "clear-alarms-title": "Wis { count, plural, =1 {1 alarm} other {# alarmen} }", + "clear-alarms-text": "Weet u zeker dat u { count, plural, =1 {1 alarm} other {# alarmen} } wilt wissen?", + "clear-alarm-title": "Alarm wissen", + "clear-alarm-text": "Weet u zeker dat u dit alarm wilt wissen?", + "delete-alarms-title": "Verwijder { count, plural, =1 {1 alarm} other {# alarmen} }", "delete-alarms-text": "Weet u zeker dat u { count, plural, =1 {1 alarm} other {# alarmen} } wilt verwijderen?", - "selected-alarms-are-cleared": "Geselecteerde alarmen zijn al gezuiverd", + "selected-alarms-are-cleared": "Geselecteerde alarmen zijn al gewist", "alarm-status-filter": "Alarmstatusfilter", "alarm-filter-title": "Alarmfilter", "assigned": "Toegewezen", "filter-title": "Filter", "max-count-load": "Maximaal aantal te laden alarmen (0 - onbeperkt)", - "max-count-load-required": "Maximaal aantal te laden alarmen is verplicht.", + "max-count-load-required": "Maximaal aantal te laden alarmen is vereist.", "max-count-load-error-min": "Minimale waarde is 0.", - "fetch-size": "Fetch-grootte", - "fetch-size-required": "Fetch-grootte is verplicht.", + "fetch-size": "Ophaalgrootte", + "fetch-size-required": "Ophaalgrootte is vereist.", "fetch-size-error-min": "Minimale waarde is 10.", "alarm-types": "Alarmtypen", - "alarm-type-list": "Lijst van alarmtypen", + "alarm-type-list": "Lijst met alarmtypen", "any-type": "Elk type", "assigned-to-current-user": "Toegewezen aan huidige gebruiker", "assigned-to-me": "Toegewezen aan mij", - "search-propagated-alarms": "Gepropageerde alarmen zoeken", - "comments": "Alarmopmerkingen", - "show-more": "Meer weergeven", - "additional-info": "Aanvullende info", + "search-propagated-alarms": "Zoek verspreide alarmen", + "comments": "Alarmcommentaren", + "show-more": "Toon meer", + "additional-info": "Aanvullende informatie", "alarm-type": "Alarmtype", "enter-alarm-type": "Voer alarmtype in", - "no-alarm-types-matching": "Geen overeenkomende alarmtypen gevonden voor '{{entitySubtype}}'.", + "no-alarm-types-matching": "Geen alarmtypen gevonden die overeenkomen met '{{entitySubtype}}'.", "alarm-type-list-empty": "Geen alarmtypen geselecteerd." }, "alarm-activity": { @@ -671,14 +677,14 @@ "add": "Alias toevoegen", "edit": "Alias bewerken", "name": "Aliasnaam", - "name-required": "Aliasnaam is verplicht", + "name-required": "Aliasnaam is vereist", "duplicate-alias": "Er bestaat al een alias met dezelfde naam.", - "filter-type-single-entity": "Enkelvoudige entiteit", + "filter-type-single-entity": "Enkele entiteit", "filter-type-entity-list": "Entiteitenlijst", "filter-type-entity-name": "Entiteitsnaam", "filter-type-entity-type": "Entiteitstype", "filter-type-state-entity": "Entiteit uit dashboardstatus", - "filter-type-state-entity-description": "Entiteit afkomstig uit statusparameters van het dashboard", + "filter-type-state-entity-description": "Entiteit verkregen via parameters van dashboardstatus", "filter-type-asset-type": "Assettype", "filter-type-asset-type-description": "Assets van het type '{{assetTypes}}'", "filter-type-asset-type-and-name-description": "Assets van het type '{{assetTypes}}' met naam die begint met '{{prefix}}'", @@ -702,22 +708,23 @@ "filter-type-entity-view-search-query": "Entiteitsoverzicht zoekquery", "filter-type-entity-view-search-query-description": "Entiteitsoverzichten met typen {{entityViewTypes}} die een {{relationType}}-relatie {{direction}} {{rootEntity}} hebben", "filter-type-apiUsageState": "API-gebruiksstatus", - "entity-filter": "Entiteitenfilter", + "entity-filter": "Entiteitfilter", "resolve-multiple": "Oplossen als meerdere entiteiten", - "resolve-multiple-hint": "Inschakelen om gegevens van alle gefilterde entiteiten tegelijkertijd weer te geven.\nAls uitgeschakeld, toont de widget alleen gegevens van de geselecteerde entiteit.", + "resolve-multiple-hint": "Schakel in om gegevens van alle gefilterde entiteiten gelijktijdig weer te geven.\nIndien uitgeschakeld, toont de widget alleen gegevens van de geselecteerde entiteit.", "filter-type": "Filtertype", - "filter-type-required": "Filtertype is verplicht.", + "filter-type-required": "Filtertype is vereist.", "entity-filter-no-entity-matched": "Geen entiteiten gevonden die overeenkomen met het opgegeven filter.", - "no-entity-filter-specified": "Geen entiteitenfilter opgegeven", - "root-state-entity": "Gebruik dashboardstatus-entiteit als root", + "no-entity-filter-specified": "Geen entiteitfilter gespecificeerd", + "root-state-entity": "Gebruik dashboardstatusentiteit als root", "last-level-relation": "Alleen laatste relatieniveau ophalen", "root-entity": "Root-entiteit", - "state-entity-parameter-name": "Parameternaam status-entiteit", - "default-state-entity": "Standaard status-entiteit", + "state-entity-parameter-name": "Naam van statusentiteitsparameter", + "default-state-entity": "Standaardstatusentiteit", "default-entity-parameter-name": "Standaard", + "query-options": "Query-opties", "max-relation-level": "Maximaal relatieniveau", "unlimited-level": "Ongelimiteerd niveau", - "state-entity": "Dashboardstatus-entiteit", + "state-entity": "Dashboardstatusentiteit", "all-entities": "Alle entiteiten", "any-relation": "elke" }, @@ -771,12 +778,12 @@ "delete-asset-text": "Let op: na bevestiging worden de asset en alle gerelateerde gegevens onherstelbaar verwijderd.", "delete-assets-title": "Weet u zeker dat u { count, plural, =1 {1 asset} other {# assets} } wilt verwijderen?", "delete-assets-action-title": "{ count, plural, =1 {1 asset verwijderen} other {# assets verwijderen} }", - "delete-assets-text": "Let op: na bevestiging worden alle geselecteerde assets verwijderd en alle gerelateerde gegevens onherstelbaar.", + "delete-assets-text": "Wees voorzichtig, na bevestiging worden alle geselecteerde assets en alle gerelateerde gegevens onherstelbaar verwijderd.", "make-public-asset-title": "Weet u zeker dat u de asset '{{assetName}}' openbaar wilt maken?", "make-public-asset-text": "Na bevestiging wordt de asset en alle bijbehorende gegevens openbaar en toegankelijk voor anderen.", "make-private-asset-title": "Weet u zeker dat u de asset '{{assetName}}' privé wilt maken?", "make-private-asset-text": "Na bevestiging wordt de asset privé en niet meer toegankelijk voor anderen.", - "unassign-asset-title": "Weet u zeker dat u de asset '{{assetName}}' wilt onttrekken?", + "unassign-asset-title": "Weet u zeker dat u de asset '{{assetName}}' wilt ontkoppelen?", "unassign-asset-text": "Na bevestiging wordt de asset ontkoppeld en is deze niet meer toegankelijk voor de klant.", "unassign-asset": "Asset ontkoppelen", "unassign-assets-title": "Weet u zeker dat u { count, plural, =1 {1 asset} other {# assets} } wilt onttrekken?", @@ -801,7 +808,7 @@ "selected-assets": "{ count, plural, =1 {1 asset} other {# assets} } geselecteerd" }, "attribute": { - "attributes": "Attribuuten", + "attributes": "Attributen", "latest-telemetry": "Laatste telemetrie", "no-latest-telemetry": "Geen laatste telemetrie", "attributes-scope": "Bereik van entiteitsattributen", @@ -823,7 +830,7 @@ "value": "Waarde", "value-required": "Attribuutwaarde is verplicht.", "telemetry-key-required": "Telemetriesleutel is verplicht", - "telemetry-value-required": "Telemetrie waarde is verplicht", + "telemetry-value-required": "Telemetriewaarde is verplicht", "delete-attributes-title": "Weet u zeker dat u { count, plural, =1 {1 attribuut} other {# attributen} } wilt verwijderen?", "delete-attributes-text": "Let op: na bevestiging worden alle geselecteerde attributen verwijderd.", "delete-attributes": "Attributen verwijderen", @@ -854,10 +861,10 @@ } }, "api-usage": { - "api-features": "API-functies", + "api-features": "API-functionaliteiten", "api-usage": "API-gebruik", "alarm": "Alarm", - "alarms-created": "Gegenereerde alarmen", + "alarms-created": "Aangemaakte alarmen", "queue-stats": "Wachtrijstatistieken", "processing-failures-and-timeouts": "Verwerkingsfouten en time-outs", "exceptions": "Uitzonderingen", @@ -913,15 +920,20 @@ "transport-hourly-activity": "Uurlijkse activiteit transport", "transport-messages": "Transportberichten", "transport-monthly-activity": "Maandelijkse activiteit transport", - "view-details": "Bekijk details", - "view-statistics": "Bekijk statistieken" + "view-details": "Details bekijken", + "view-statistics": "Statistieken bekijken" }, "api-limit": { - "cassandra-queries": "Cassandra-query's", - "entity-version-creation": "Versiecreatie van entiteit", - "entity-version-load": "Versieladen van entiteit", - "notification-requests": "Meldingsverzoeken", - "notification-requests-per-rule": "Meldingsverzoeken per regel", + "cassandra-write-queries-core": "Rest API Cassandra schrijfbewerkingen", + "cassandra-read-queries-core": "Rest API en WS-telemetrie Cassandra leesbewerkingen", + "cassandra-write-queries-rule-engine": "Rule Engine telemetrie Cassandra schrijfbewerkingen", + "cassandra-read-queries-rule-engine": "Rule Engine telemetrie Cassandra leesbewerkingen", + "cassandra-write-queries-monolith": "Monolithische telemetrie Cassandra schrijfbewerkingen", + "cassandra-read-queries-monolith": "Monolithische telemetrie Cassandra leesbewerkingen", + "entity-version-creation": "Aanmaak van entiteitsversie", + "entity-version-load": "Laden van entiteitsversie", + "notification-requests": "Notificatieverzoeken", + "notification-requests-per-rule": "Notificatieverzoeken per regel", "rest-api-requests": "REST API-verzoeken", "rest-api-requests-per-customer": "REST API-verzoeken per klant", "transport-messages": "Transportberichten", @@ -931,8 +943,8 @@ "ws-updates-per-session": "WS-updates per sessie", "edge-events": "Edge-gebeurtenissen", "edge-events-per-edge": "Edge-gebeurtenissen per edge", - "edge-uplink-messages": "Edge uplink-berichten", - "edge-uplink-messages-per-edge": "Edge uplink-berichten per edge" + "edge-uplink-messages": "Edge-uplinkberichten", + "edge-uplink-messages-per-edge": "Edge-uplinkberichten per edge" }, "audit-log": { "audit": "Audit", @@ -1057,24 +1069,122 @@ "delete-multiple-title": "Weet u zeker dat u { count, plural, =1 {1 berekend veld} other {# berekende velden} } wilt verwijderen?", "delete-multiple-text": "Let op: na bevestiging worden alle geselecteerde berekende velden verwijderd en zijn de gegevens onherstelbaar.", "test-with-this-message": "Test met dit bericht", + "use-latest-timestamp": "Gebruik laatste tijdstempel", "hint": { - "arguments-simple-with-rolling": "Berekend veld van het type eenvoudig mag geen sleutels met tijdreeks rolling bevatten.", + "arguments-simple-with-rolling": "Berekende velden van het type 'eenvoudig' mogen geen sleutels bevatten met een rollende tijdreeks.", "arguments-empty": "Argumenten mogen niet leeg zijn.", - "expression-required": "Expressie is verplicht.", + "expression-required": "Expressie is vereist.", "expression-invalid": "Expressie is ongeldig", - "expression-max-length": "Lengte van de expressie moet minder dan 255 tekens zijn.", - "argument-name-required": "Argumentnaam is verplicht.", - "argument-name-pattern": "Ongeldige argumentnaam.", - "argument-name-duplicate": "Er bestaat al een argument met deze naam.", - "argument-name-max-length": "Argumentnaam moet minder dan 256 tekens zijn.", - "argument-name-forbidden": "Argumentnaam is gereserveerd en mag niet worden gebruikt.", - "argument-type-required": "Argumenttype is verplicht.", + "expression-max-length": "De lengte van de expressie moet minder dan 255 tekens zijn.", + "argument-name-required": "Argumentnaam is vereist.", + "argument-name-pattern": "Argumentnaam is ongeldig.", + "argument-name-duplicate": "Een argument met deze naam bestaat al.", + "argument-name-max-length": "Argumentnaam mag niet langer zijn dan 256 tekens.", + "argument-name-forbidden": "Deze argumentnaam is gereserveerd en mag niet worden gebruikt.", + "argument-type-required": "Argumenttype is vereist.", "max-args": "Maximum aantal argumenten bereikt.", - "decimals-range": "Standaard aantal decimalen moet tussen 0 en 15 liggen.", - "expression": "Standaardexpressie toont hoe je temperatuur converteert van Fahrenheit naar Celsius.", - "arguments-entity-not-found": "Doelentiteit van argument niet gevonden." + "decimals-range": "Het aantal decimalen moet een getal zijn tussen 0 en 15.", + "expression": "Standaardexpressie toont hoe temperatuur van Fahrenheit naar Celsius wordt omgerekend.", + "arguments-entity-not-found": "Doelentiteit van het argument niet gevonden.", + "use-latest-timestamp": "Indien ingeschakeld, wordt de berekende waarde opgeslagen met de meest recente tijdstempel van de telemetrie van de argumenten, in plaats van met de servertijd." } }, + "ai-models": { + "ai-models": "AI-modellen", + "ai-model": "AI-model", + "model": "Model", + "name": "Naam", + "ai-provider": "AI-provider", + "no-found": "Geen AI-modellen gevonden", + "list": "{ count, plural, =1 {Eén model} other {Lijst van # modellen} }", + "selected-fields": "{ count, plural, =1 {1 model} other {# modellen} } geselecteerd", + "add": "Model toevoegen", + "delete-model-title": "Weet u zeker dat u het model '{{modelName}}' wilt verwijderen?", + "delete-model-text": "Wees voorzichtig, na bevestiging wordt het model en alle gerelateerde gegevens permanent verwijderd.", + "delete-models-title": "Weet u zeker dat u { count, plural, =1 {1 model} other {# modellen} } wilt verwijderen?", + "delete-models-text": "Wees voorzichtig, na bevestiging worden alle geselecteerde modellen verwijderd en alle gerelateerde gegevens permanent gewist.", + "ai-providers": { + "openai": "OpenAI", + "azure-openai": "Azure OpenAI", + "google-ai-gemini": "Google AI Gemini", + "google-vertex-ai-gemini": "Google Vertex AI Gemini", + "mistral-ai": "Mistral AI", + "anthropic": "Anthropic", + "amazon-bedrock": "Amazon Bedrock", + "github-models": "GitHub-modellen", + "ollama": "Ollama" + }, + "name-required": "Naam is vereist.", + "name-max-length": "Naam mag maximaal 255 tekens bevatten.", + "provider": "Provider", + "api-key": "API-sleutel", + "api-key-required": "API-sleutel is vereist.", + "api-key-open-ai-required": "API-sleutel is vereist bij gebruik van de officiële OpenAI API.", + "project-id": "Project-ID", + "project-id-required": "Project-ID is vereist.", + "location": "Locatie", + "location-required": "Locatie is vereist.", + "service-account-key-file": "Serviceaccount sleutelbestand", + "service-account-key-file-required": "Serviceaccount sleutelbestand is vereist.", + "no-file": "Geen bestand geselecteerd.", + "drop-file": "Sleep een bestand hierheen of klik om een bestand te selecteren en te uploaden.", + "personal-access-token": "Persoonlijke toegangstoken", + "personal-access-token-required": "Persoonlijke toegangstoken is vereist.", + "configuration": "Configuratie", + "model-id": "Model-ID", + "model-id-required": "Model-ID is vereist.", + "deployment-name": "Naam van implementatie", + "deployment-name-required": "Naam van implementatie is vereist.", + "set": "Instellen", + "region": "Regio", + "region-required": "Regio is vereist.", + "access-key-id": "Access key ID", + "access-key-id-required": "Access key ID is vereist.", + "secret-access-key": "Geheime access key", + "secret-access-key-required": "Geheime access key is vereist.", + "temperature": "Temperature", + "temperature-hint": "Bepaalt het niveau van willekeur in de modeloutput. Hogere waarden verhogen de willekeur, lagere waarden verlagen deze.", + "temperature-min": "Moet 0 of hoger zijn.", + "top-p": "Top P", + "top-p-hint": "Stelt een groep samen van de meest waarschijnlijke tokens waaruit het model kan kiezen. Hogere waarden vergroten de diversiteit, lagere verkleinen deze.", + "top-p-min-max": "Moet groter zijn dan 0 en maximaal 1.", + "top-k": "Top K", + "top-k-hint": "Beperkt de keuzes van het model tot de vaste set van de \"K\" meest waarschijnlijke tokens.", + "top-k-min": "Moet 0 of hoger zijn.", + "presence-penalty": "Aanwezigheidsstraf", + "presence-penalty-hint": "Past een vaste straf toe op de waarschijnlijkheid van een token als het al eerder in de tekst is verschenen.", + "frequency-penalty": "Frequentiestraf", + "frequency-penalty-hint": "Verlaagt de waarschijnlijkheid van een token op basis van hoe vaak het voorkomt in de tekst.", + "max-output-tokens": "Maximaal aantal outputtokens", + "max-output-tokens-hint": "Stelt het maximumaantal tokens in dat het \nmodel kan genereren in één enkele respons.", + "context-length": "Contextlengte", + "context-length-hint": "Bepaalt de grootte van het contextvenster in tokens. Deze waarde stelt de totale geheugenlimiet van het model vast, inclusief zowel de invoer van de gebruiker als de gegenereerde output.", + "endpoint": "Endpoint", + "endpoint-required": "Endpoint is vereist.", + "baseurl": "Basis-URL", + "baseurl-required": "Basis-URL is vereist.", + "service-version": "Serviceversie", + "check-connectivity": "Verbinding controleren", + "check-connectivity-success": "Testverzoek was succesvol", + "check-connectivity-failed": "Testverzoek mislukt", + "no-model-matching": "Geen modellen gevonden die overeenkomen met '{{entity}}'.", + "model-required": "Model is vereist.", + "no-model-text": "Geen modellen gevonden.", + "authentication": "Authenticatie", + "authentication-basic-hint": "Gebruikt standaard HTTP Basic-authenticatie. De gebruikersnaam en het wachtwoord worden gecombineerd, Base64-gecodeerd en verzonden in een \"Authorization\"-header bij elk verzoek aan de Ollama-server.", + "authentication-token-hint": "Gebruikt Bearer-tokenauthenticatie. Het opgegeven token wordt rechtstreeks verzonden in een \"Authorization\"-header bij elk verzoek aan de Ollama-server.", + "authentication-type": { + "none": "Geen", + "basic": "Basic", + "token": "Token" + }, + "username": "Gebruikersnaam", + "username-required": "Gebruikersnaam is vereist.", + "password": "Wachtwoord", + "password-required": "Wachtwoord is vereist.", + "token": "Token", + "token-required": "Token is vereist." + }, "confirm-on-exit": { "message": "U heeft niet-opgeslagen wijzigingen. Weet u zeker dat u deze pagina wilt verlaten?", "html-message": "U heeft niet-opgeslagen wijzigingen.
Weet u zeker dat u deze pagina wilt verlaten?", @@ -1337,16 +1447,16 @@ "max-vertical-margin-message": "Maximale verticale marge is 50.", "apply-outer-margin": "Marge toepassen aan zijkanten van de lay-out", "autofill-height": "Automatisch lay-outhoogte vullen", - "mobile-layout": "Mobiele lay-outinstellingen", + "mobile-layout": "Instellingen voor mobiel dashboard", "mobile-row-height": "Mobiele rijhoogte", - "mobile-row-height-required": "Mobiele rijhoogte is verplicht.", - "min-mobile-row-height-message": "Minimale mobiele rijhoogte is 5 pixels.", - "max-mobile-row-height-message": "Maximale mobiele rijhoogte is 200 pixels.", + "mobile-row-height-required": "Waarde voor mobiele rijhoogte is vereist.", + "min-mobile-row-height-message": "Minimale toegestane waarde voor mobiele rijhoogte is 5 pixels.", + "max-mobile-row-height-message": "Maximale toegestane waarde voor mobiele rijhoogte is 200 pixels.", "row-height": "Rijhoogte", - "row-height-required": "Rijhoogte is verplicht.", - "min-row-height-message": "Minimale rijhoogte is 5 pixels.", - "max-row-height-message": "Maximale rijhoogte is 200 pixels.", - "display-first-in-mobile-view": "Eerst tonen in mobiele weergave", + "row-height-required": "Waarde voor rijhoogte is vereist.", + "min-row-height-message": "Minimale toegestane waarde voor rijhoogte is 5 pixels.", + "max-row-height-message": "Maximale toegestane waarde voor rijhoogte is 200 pixels.", + "display-first-in-mobile-view": "Als eerste weergeven in mobiele weergave", "title-settings": "Titelinstellingen", "display-title": "Dashboardtitel weergeven", "title-color": "Titelkleur", @@ -1487,20 +1597,20 @@ "time-prev-description": "tijdstempel van vorige waarde;", "prev-orig-value-description": "oorspronkelijke vorige waarde;", "aggregation": "Aggregatie", - "aggregation-type-hint-common": "Om prestatie redenen, is aggregatie alleen beschikbaar voor vaste tijdsintervallen zoals \"huidige dag\", \"huidige maand\", enz., niet voor schuivende vensters zoals 'laatste 30 minuten'.", - "aggregation-type-none-hint": "Gebruik laatste waarde.", - "aggregation-type-min-hint": "Zoek minimale waarde binnen geselecteerd tijdvenster.", - "aggregation-type-max-hint": "Zoek maximale waarde binnen geselecteerd tijdvenster.", - "aggregation-type-avg-hint": "Bereken gemiddelde waarde binnen geselecteerd tijdvenster.", - "aggregation-type-sum-hint": "Sommeer alle waarden binnen geselecteerd tijdvenster.", - "aggregation-type-count-hint": "Aantal gegevenspunten binnen geselecteerd tijdvenster.", + "aggregation-type-hint-common": "Om prestatieredenen is het berekenen van geaggregeerde waarden alleen beschikbaar voor vaste tijdsintervallen zoals \"huidige dag\", \"huidige maand\", enzovoort, en niet voor glijdende vensters zoals 'laatste 30 minuten' of 'laatste 24 uur'.", + "aggregation-type-none-hint": "Neem de laatste waarde.", + "aggregation-type-min-hint": "Bepaal de minimumwaarde uit gegevenspunten binnen het geselecteerde tijdvenster.", + "aggregation-type-max-hint": "Bepaal de maximumwaarde uit gegevenspunten binnen het geselecteerde tijdvenster.", + "aggregation-type-avg-hint": "Bereken de gemiddelde waarde uit gegevenspunten binnen het geselecteerde tijdvenster.", + "aggregation-type-sum-hint": "Sommeer alle waarden van de gegevenspunten binnen het geselecteerde tijdvenster.", + "aggregation-type-count-hint": "Totaal aantal gegevenspunten binnen het geselecteerde tijdvenster.", "delta-calculation": "Delta-berekening", "enable-delta-calculation": "Delta-berekening inschakelen", - "enable-delta-calculation-hint": "Bij inschakeling wordt waarde berekend op basis van geaggregeerde gegevens in gekozen tijdsvenster en vergelijkingsperiode. Alleen beschikbaar voor historische vensters.", - "delta-calculation-result": "Resultaat delta-berekening", + "enable-delta-calculation-hint": "Indien ingeschakeld, wordt de waarde van de gegevenssleutel berekend op basis van geaggregeerde waarden voor een geselecteerd tijdvenster en een opgegeven vergelijkingsperiode. Om prestatie­redenen is delta-berekening alleen beschikbaar voor historische tijdvensters en niet voor real-time waarden. U kunt bijvoorbeeld het verschil berekenen tussen het energieverbruik van gisteren en dat van eergisteren.", + "delta-calculation-result": "Resultaat van delta-berekening", "delta-calculation-result-previous-value": "Vorige waarde", "delta-calculation-result-delta-absolute": "Delta (absoluut)", - "delta-calculation-result-delta-percent": "Delta (procent)", + "delta-calculation-result-delta-percent": "Delta (percentage)", "source": "Bron", "latest": "Laatste", "latest-value": "Laatste waarde", @@ -1607,32 +1717,32 @@ "lwm2m-security-config": { "identity": "Clientidentiteit", "identity-required": "Clientidentiteit is verplicht.", - "identity-tooltip": "De PSK-identificatie is een willekeurige identificatie tot 128 bytes volgens [RFC7925]. Moet eerst naar een tekenreeks worden omgezet en vervolgens in UTF-8 worden gecodeerd.", + "identity-tooltip": "De PSK-identificatie is een willekeurige identificatie tot 128 bytes zoals beschreven in de standaard [RFC7925].\nDe PSK-identificatie MOET eerst worden omgezet naar een tekenreeks en vervolgens in UTF-8 worden gecodeerd.", "client-key": "Clientsleutel", "client-key-required": "Clientsleutel is verplicht.", - "client-key-tooltip-prk": "RPK publieke sleutel of ID moet voldoen aan [RFC7250] en gecodeerd zijn in Base64-formaat!", - "client-key-tooltip-psk": "PSK-sleutel moet voldoen aan [RFC4279] en in HexDec-formaat zijn: 32, 64 of 128 tekens!", - "endpoint": "Endpoint clientnaam", - "endpoint-required": "Endpoint clientnaam is verplicht.", - "client-public-key": "Publieke client sleutel", - "client-public-key-hint": "Als leeg, wordt vertrouwd certificaat gebruikt", - "client-public-key-tooltip": "X509 publieke sleutel moet DER-gecodeerd X509v3-formaat zijn, EC-algoritme ondersteunen en Base64-gecodeerd zijn!", - "mode": "Beveiligingsconfiguratie-modus", - "client-tab": "Clientbeveiliging", + "client-key-tooltip-prk": "RPK publieke sleutel of ID moet voldoen aan de standaard [RFC7250] en gecodeerd zijn in Base64-formaat!", + "client-key-tooltip-psk": "PSK-sleutel moet voldoen aan de standaard [RFC4279] en in HexDec-formaat zijn: 32, 64 of 128 tekens!", + "endpoint": "Client endpointnaam", + "endpoint-required": "Client endpointnaam is verplicht.", + "client-public-key": "Publieke clientsleutel", + "client-public-key-hint": "Als de publieke clientsleutel leeg is, wordt het vertrouwde certificaat gebruikt.", + "client-public-key-tooltip": "De X509 publieke sleutel moet in DER-gecodeerd X509v3-formaat zijn, uitsluitend het EC-algoritme ondersteunen en worden gecodeerd in Base64-formaat!", + "mode": "Beveiligingsconfiguratiemodus", + "client-tab": "Clientbeveiligingsconfiguratie", "client-certificate": "Clientcertificaat", - "bootstrap-tab": "Bootstrap-client", - "bootstrap-server": "Bootstrap-server", + "bootstrap-tab": "Bootstrapclient", + "bootstrap-server": "Bootstrapserver", "lwm2m-server": "LwM2M-server", "client-publicKey-or-id": "Client publieke sleutel of ID", "client-publicKey-or-id-required": "Client publieke sleutel of ID is verplicht.", - "client-publicKey-or-id-tooltip-psk": "PSK-ID max. 128 bytes volgens [RFC7925], omzetten naar string en UTF-8 coderen.", - "client-publicKey-or-id-tooltip-rpk": "RPK moet [RFC7250] volgen en Base64-gecodeerd zijn!", - "client-publicKey-or-id-tooltip-x509": "X509 moet DER-gecodeerd X509v3 zijn met EC-algoritme en Base64-gecodeerd!", - "client-secret-key": "Clientgeheime sleutel", - "client-secret-key-required": "Clientgeheime sleutel is verplicht.", - "client-secret-key-tooltip-psk": "PSK moet [RFC4279] volgen en HexDec (32, 64, 128 tekens) zijn!", - "client-secret-key-tooltip-prk": "RPK geheime sleutel moet in PKCS_8 (DER, [RFC5958]) zijn en Base64-gecodeerd!", - "client-secret-key-tooltip-x509": "X509 geheime sleutel moet in PKCS_8 (DER, [RFC5958]) zijn en Base64-gecodeerd!" + "client-publicKey-or-id-tooltip-psk": "De PSK-identificatie is een willekeurige identificatie tot 128 bytes zoals beschreven in de standaard [RFC7925].\nDe PSK-identificatie MOET eerst worden omgezet naar een tekenreeks en vervolgens in UTF-8 worden gecodeerd.", + "client-publicKey-or-id-tooltip-rpk": "RPK moet voldoen aan de standaard [RFC7250] en gecodeerd zijn in Base64-formaat!", + "client-publicKey-or-id-tooltip-x509": "X509 moet in DER-gecodeerd X509v3-formaat zijn, uitsluitend het EC-algoritme ondersteunen en worden gecodeerd in Base64-formaat.", + "client-secret-key": "Client geheime sleutel", + "client-secret-key-required": "Client geheime sleutel is verplicht.", + "client-secret-key-tooltip-psk": "PSK moet voldoen aan de standaard [RFC4279] en in HexDec-formaat zijn (32, 64 of 128 tekens)!", + "client-secret-key-tooltip-prk": "RPK geheime sleutel moet in PKCS_8-formaat zijn (DER-gecodeerd, standaard [RFC5958]) en worden gecodeerd in Base64-formaat!", + "client-secret-key-tooltip-x509": "X509 geheime sleutel moet in PKCS_8-formaat zijn (DER-gecodeerd, standaard [RFC5958]) en worden gecodeerd in Base64-formaat!" }, "client-id": "Client-ID", "client-id-pattern": "Bevat ongeldig teken.", @@ -1659,31 +1769,31 @@ "label": "Label", "events": "Gebeurtenissen", "details": "Details", - "copyId": "Apparaat-ID kopiëren", - "copyAccessToken": "Access token kopiëren", - "copy-mqtt-authentication": "MQTT-referenties kopiëren", - "idCopiedMessage": "Apparaat-ID is gekopieerd", - "accessTokenCopiedMessage": "Access token is gekopieerd", - "mqtt-authentication-copied-message": "MQTT-authenticatie is gekopieerd", + "copyId": "Kopieer apparaat-ID", + "copyAccessToken": "Kopieer toegangstoken", + "copy-mqtt-authentication": "Kopieer MQTT-inloggegevens", + "idCopiedMessage": "Apparaat-ID is gekopieerd naar het klembord", + "accessTokenCopiedMessage": "Toegangstoken van apparaat is gekopieerd naar het klembord", + "mqtt-authentication-copied-message": "MQTT-authenticatie van apparaat is gekopieerd naar het klembord", "assignedToCustomer": "Toegewezen aan klant", - "unable-delete-device-alias-title": "Kan apparaatalias niet verwijderen", - "unable-delete-device-alias-text": "Alias '{{deviceAlias}}' kan niet worden verwijderd omdat deze wordt gebruikt door de volgende widget(s):
{{widgetsList}}", + "unable-delete-device-alias-title": "Kan apparaat-alias niet verwijderen", + "unable-delete-device-alias-text": "Apparaat-alias '{{deviceAlias}}' kan niet worden verwijderd omdat het wordt gebruikt door de volgende widget(s):
{{widgetsList}}", "is-gateway": "Is gateway", - "overwrite-activity-time": "Overschrijf activiteitsmoment verbonden apparaat", + "overwrite-activity-time": "Activiteitstijd voor verbonden apparaat overschrijven", "device-filter": "Apparaatfilter", "device-filter-title": "Apparaatfilter", "filter-title": "Filter", "device-state": "Apparaatstatus", "state": "Status", - "any": "Elke", + "any": "Alles", "active": "Actief", "inactive": "Inactief", "public": "Openbaar", "device-public": "Apparaat is openbaar", "select-device": "Selecteer apparaat", - "import": "Apparaat importeren", + "import": "Importeer apparaat", "device-file": "Apparaatbestand", - "search": "Apparaten zoeken", + "search": "Zoek apparaten", "selected-devices": "{ count, plural, =1 {1 apparaat} other {# apparaten} } geselecteerd", "device-configuration": "Apparaatconfiguratie", "transport-configuration": "Transportconfiguratie", @@ -1753,8 +1863,9 @@ "step": "Stap", "selected-options-limit": "Limiet geselecteerde opties", "advanced-ui-settings": "Geavanceerde UI-instellingen", - "disable-on-property": "Uitschakelen op eigenschap", - "display-condition-function": "Weergavevoorwaarde functie", + "disable-on-property": "Uitschakelen op basis van eigenschap", + "disable-on-property-none": "Geen (veld altijd ingeschakeld)", + "display-condition-function": "Functie voor weergavevoorwaarde", "sub-label": "Sublabel", "vertical-divider-after": "Verticale scheiding na", "input-field-suffix": "Achtervoegsel invoerveld", @@ -1787,7 +1898,8 @@ "array-item": "Array-item", "item-type": "Itemtype", "item-name": "Itemnaam", - "no-items": "Geen items" + "no-items": "Geen items", + "support-unit-conversion": "Ondersteuning voor eenheidsconversie" }, "clear-form": "Formulier wissen", "clear-form-prompt": "Weet u zeker dat u alle formulier-eigenschappen wilt verwijderen?", @@ -1882,35 +1994,36 @@ "default": "Standaard", "profile-configuration": "Profielconfiguratie", "transport-configuration": "Transportconfiguratie", - "default-rule-chain": "Standaard regelketen", - "default-edge-rule-chain": "Standaard edge regelketen", - "default-edge-rule-chain-hint": "Gebruikt op edge voor verwerking van gegevens voor apparaten met dit profiel", + "default-rule-chain": "Standaardregelketen", + "default-edge-rule-chain": "Standaard edge-regelketen", + "default-edge-rule-chain-hint": "Gebruikt op de edge als regelketen om inkomende gegevens te verwerken voor apparaten van dit apparaatprofiel.", "mobile-dashboard": "Mobiel dashboard", - "mobile-dashboard-hint": "Gebruikt door mobiele app als apparaatoverzicht", - "select-queue-hint": "Selecteer uit de keuzelijst.", + "mobile-dashboard-hint": "Gebruikt door de mobiele applicatie als apparaatdetailsdashboard.", + "select-queue-hint": "Selecteer uit een vervolgkeuzelijst.", "delete-device-profile-title": "Weet u zeker dat u het apparaatprofiel '{{deviceProfileName}}' wilt verwijderen?", - "delete-device-profile-text": "Let op: het apparaatprofiel en gerelateerde gegevens, inclusief OTA-updates, worden onherstelbaar verwijderd.", + "delete-device-profile-text": "Wees voorzichtig, na bevestiging worden het apparaatprofiel en alle gerelateerde gegevens, inclusief bijbehorende OTA-updates, onherstelbaar verwijderd.", "delete-device-profiles-title": "Weet u zeker dat u { count, plural, =1 {1 apparaatprofiel} other {# apparaatprofielen} } wilt verwijderen?", - "delete-device-profiles-text": "Let op: alle geselecteerde profielen en gerelateerde gegevens inclusief OTA-updates worden onherstelbaar verwijderd.", - "set-default-device-profile-title": "Wilt u '{{deviceProfileName}}' instellen als standaardprofiel?", - "set-default-device-profile-text": "Na bevestiging wordt dit profiel gebruikt voor nieuwe apparaten zonder specifiek profiel.", + "delete-device-profiles-text": "Wees voorzichtig, na bevestiging worden alle geselecteerde apparaatprofielen verwijderd en alle gerelateerde gegevens, inclusief bijbehorende OTA-updates, onherstelbaar verwijderd.", + "set-default-device-profile-title": "Weet u zeker dat u het apparaatprofiel '{{deviceProfileName}}' als standaard wilt instellen?", + "set-default-device-profile-text": "Na bevestiging wordt het apparaatprofiel als standaard gemarkeerd en gebruikt voor nieuwe apparaten zonder opgegeven profiel.", "no-device-profiles-found": "Geen apparaatprofielen gevonden.", - "create-new-device-profile": "Nieuwe aanmaken!", - "mqtt-device-topic-filters": "MQTT apparaattopicfilters", - "mqtt-device-topic-filters-unique": "MQTT apparaattopicfilters moeten uniek zijn.", - "mqtt-device-topic-filters-spark-plug": "MQTT Sparkplug B Edge of Network (EoN) node.", - "mqtt-device-topic-filters-spark-plug-hint": "Sta verbindingen toe van EoN-nodes met Sparkplug B payload en topicstructuur.", - "mqtt-device-topic-filters-spark-plug-attribute-metric-names": "SparkPlug-metingen als attributen opslaan.", - "mqtt-device-topic-filters-spark-plug-attribute-metric-names-hint": "SparkPlug-metingen worden opgeslagen als attributen; overige als telemetrie.", - "mqtt-device-payload-type": "MQTT apparaatgegevensformaat", + "create-new-device-profile": "Maak een nieuwe aan!", + "mqtt-device-topic-filters": "MQTT-apparaatonderwerpfilters", + "mqtt-device-topic-filters-unique": "MQTT-apparaatonderwerpfilters moeten uniek zijn.", + "mqtt-device-topic-filters-spark-plug": "MQTT Sparkplug B Edge of Network (EoN)-knooppunt.", + "mqtt-device-topic-filters-spark-plug-hint": "Sta verbindingen toe van EoN-knooppunten met Sparkplug B-payload en onderwerpformaat.", + "mqtt-device-topic-filters-spark-plug-attribute-metric-names": "SparkPlug-metingen opslaan als attributen.", + "mqtt-device-topic-filters-spark-plug-attribute-metric-names-hint": "Namen van SparkPlug-metingen die als apparaatattributen worden opgeslagen. Alle overige metingen worden als apparaattelmetrie opgeslagen.", + "mqtt-device-payload-type": "MQTT-apparaatpayload", "mqtt-device-payload-type-json": "JSON", "mqtt-device-payload-type-proto": "Protobuf", - "mqtt-enable-compatibility-with-json-payload-format": "Compatibiliteit met ander formaat inschakelen", - "mqtt-enable-compatibility-with-json-payload-format-hint": "Bij inschakelen wordt standaard Protobuf gebruikt. Bij fout wordt JSON geprobeerd. Handig tijdens firmware-overgangen. Kan prestaties beïnvloeden.", - "mqtt-use-json-format-for-default-downlink-topics": "Gebruik JSON voor standaard downlink topics", - "mqtt-use-json-format-for-default-downlink-topics-hint": "Indien ingeschakeld, worden JSON payloads gebruikt voor standaard topics zoals v1/devices/me/attributes. Dit heeft geen invloed op v2-topics.", - "mqtt-send-ack-on-validation-exception": "Stuur PUBACK bij validatiefout", - "mqtt-send-ack-on-validation-exception-hint": "Standaard sluit platform sessie. Indien ingeschakeld, wordt PUBACK gestuurd bij fout.", + "mqtt-enable-compatibility-with-json-payload-format": "Compatibiliteit inschakelen met andere payloadformaten.", + "mqtt-enable-compatibility-with-json-payload-format-hint": "Wanneer ingeschakeld, gebruikt het platform standaard het Protobuf-payloadformaat. Als parseren mislukt, probeert het platform het JSON-formaat te gebruiken. Handig voor backward compatibility tijdens firmware-updates. Bijvoorbeeld: de initiële firmwareversie gebruikt JSON, terwijl de nieuwe versie Protobuf gebruikt. Tijdens het firmware-updateproces van het gehele apparaatbestand is ondersteuning voor beide vereist. De compatibiliteitsmodus veroorzaakt lichte prestatievermindering, dus wordt aanbevolen deze uit te schakelen zodra alle apparaten zijn bijgewerkt.", + "mqtt-use-json-format-for-default-downlink-topics": "Gebruik JSON-formaat voor standaard downlink-onderwerpen", + "mqtt-use-json-format-for-default-downlink-topics-hint": "Wanneer ingeschakeld, gebruikt het platform JSON-payloadformaat om attributen en RPC te verzenden via de volgende onderwerpen: v1/devices/me/attributes/response/$request_id, v1/devices/me/attributes, v1/devices/me/rpc/request/$request_id, v1/devices/me/rpc/response/$request_id. Deze instelling heeft geen invloed op attributen en RPC-abonnementen die via nieuwe (v2) onderwerpen worden verzonden: v2/a/res/$request_id, v2/a, v2/r/req/$request_id, v2/r/res/$request_id. Waarbij $request_id een geheel getal is als aanvraag-ID.", + "mqtt-send-ack-on-validation-exception": "PUBACK verzenden bij validatiefout van PUBLISH-bericht", + "mqtt-send-ack-on-validation-exception-hint": "Standaard sluit het platform de MQTT-sessie bij een validatiefout. Wanneer ingeschakeld, verzendt het platform een publicatiebevestiging in plaats van de sessie te sluiten.", + "mqtt-protocol-version": "Protocolversie", "snmp-add-mapping": "SNMP-mapping toevoegen", "snmp-mapping-not-configured": "Geen mapping geconfigureerd van OID naar telemetrie", "snmp-timseries-or-attribute-name": "Naam tijdreeks/attribuut voor mapping", @@ -2143,38 +2256,41 @@ "tqs": "TQS: TCP + SMS actief; TCP in wachtrijmodus (niet ondersteund sinds LWM2M 1.1)", "sq": "SQ: SMS in wachtrijmodus (niet ondersteund sinds LWM2M 1.1)" }, - "binding-tooltip": "Bindingmodus zoals gedefinieerd in resource /1/x/7 van het LwM2M-serverobject.\nGeeft ondersteunde bindingen aan in de client. Deze waarde moet overeenkomen met waarde in resource /3/0/16.\nSlechts één binding kan gebruikt worden per sessie.", + "binding-tooltip": "Dit is de lijst in de 'binding'-resource van het LwM2M-serverobject - /1/x/7.\nGeeft de ondersteunde verbindingsmodi aan in de LwM2M-client.\nDeze waarde MOET gelijk zijn aan de waarde in de resource 'Supported Binding and Modes' in het apparaatobject (/3/0/16).\nHoewel meerdere transporten worden ondersteund, kan slechts één transportbinding worden gebruikt tijdens de gehele transportsessie.\nBijvoorbeeld: wanneer UDP en SMS beide worden ondersteund, kunnen de LwM2M-client en -server kiezen om te communiceren via ofwel UDP ofwel SMS gedurende de gehele transportsessie.", "bootstrap-server": "Bootstrapserver", "lwm2m-server": "LwM2M-server", - "include-bootstrap-server": "Bootstrapserver-updates insluiten", - "bootstrap-update-title": "Er is al een Bootstrapserver geconfigureerd. Weet je zeker dat je de updates wilt uitsluiten?", - "bootstrap-update-text": "Wees voorzichtig, na bevestiging wordt de configuratie van de Bootstrapserver verwijderd.", + "include-bootstrap-server": "Bootstrapserver-updates opnemen", + "bootstrap-update-title": "U hebt al een bootstrapserver geconfigureerd. Weet u zeker dat u de updates wilt uitsluiten?", + "bootstrap-update-text": "Wees voorzichtig, na bevestiging worden de configuratiegegevens van de bootstrapserver onherstelbaar verwijderd.", "server-host": "Host", "server-host-required": "Host is verplicht.", "server-port": "Poort", "server-port-required": "Poort is verplicht.", "server-port-pattern": "Poort moet een positief geheel getal zijn.", "server-port-range": "Poort moet tussen 1 en 65535 liggen.", - "server-public-key": "Server openbare sleutel", - "server-public-key-required": "Server openbare sleutel is verplicht.", - "client-hold-off-time": "Wachttijd client", - "client-hold-off-time-required": "Wachttijd client is verplicht.", - "client-hold-off-time-pattern": "Wachttijd client moet een positief geheel getal zijn.", - "client-hold-off-time-tooltip": "Wachttijd van de client, alleen te gebruiken met een Bootstrap-server", + "server-public-key": "Publieke sleutel van server", + "server-public-key-required": "Publieke sleutel van server is verplicht.", + "client-hold-off-time": "Wachttijd", + "client-hold-off-time-required": "Wachttijd is verplicht.", + "client-hold-off-time-pattern": "Wachttijd moet een positief geheel getal zijn.", + "client-hold-off-time-tooltip": "Wachttijd van client, alleen voor gebruik met bootstrapserver", "account-after-timeout": "Account na time-out", "account-after-timeout-required": "Account na time-out is verplicht.", "account-after-timeout-pattern": "Account na time-out moet een positief geheel getal zijn.", - "account-after-timeout-tooltip": "Accountinstelling van de Bootstrap-server na de opgegeven time-out.", + "account-after-timeout-tooltip": "Bootstrapserver-account na de time-outwaarde opgegeven door deze resource.", "server-type": "Servertype", "add-new-server-title": "Nieuwe serverconfiguratie toevoegen", "add-server-config": "Serverconfiguratie toevoegen", "add-lwm2m-server-config": "LwM2M-server toevoegen", "no-config-servers": "Geen servers geconfigureerd", "others-tab": "Overige instellingen", - "client-strategy": "Clientstrategie bij verbinding", + "ota-update": "OTA-update", + "use-object-19-for-ota-update": "Object 19 gebruiken voor OTA-bestandsmetadata (checksum, grootte, versie, naam)", + "use-object-19-for-ota-update-hint": "Gebruik Resource ObjectId = 19 voor OTA-updates: Firmware → InstanceId = 65534, Software → InstanceId = 65535. Het gegevensformaat is JSON verpakt in Base64. Deze JSON bevat OTA-bestandsmetadata (bestandinfo): \"Checksum\" (SHA256). Extra velden: \"Title\" (OTA-naam), \"Version\" (OTA-versie), \"File Name\" (bestandsnaam voor opslag op client), \"File Size\" (OTA-grootte in bytes).", + "client-strategy": "Clientstrategie bij verbinden", "client-strategy-label": "Strategie", - "client-strategy-only-observe": "Alleen Observe-verzoek na eerste verbinding", - "client-strategy-read-all": "Lees alle bronnen & Observe-verzoek na registratie", + "client-strategy-only-observe": "Alleen Observe-verzoek naar de client na de initiële verbinding", + "client-strategy-read-all": "Alle resources lezen & Observe-verzoek na registratie verzenden", "fw-update": "Firmware-update", "fw-update-strategy": "Firmware-updatestrategie", "fw-update-strategy-data": "Firmware als binair bestand pushen via Object 19, Resource 0 (Data)", @@ -2201,7 +2317,17 @@ "default-object-id": "Standaard objectversie (Attribuut)", "default-object-id-ver": { "v1-0": "1.0", - "v1-1": "1.1" + "v1-1": "1.1", + "v1-2": "1.2" + }, + "observe-strategy": { + "observe-strategy": "Observe-strategie", + "single": "Enkelvoudig", + "single-description": "Eén Observe-verzoek per resource (hogere precisie, meer netwerkverkeer)", + "composite-all": "Alle samengesteld", + "composite-all-description": "Alle resources worden geobserveerd met één samengesteld Observe-verzoek (efficiënter, minder flexibel)", + "composite-by-object": "Samengesteld per object", + "composite-by-object-description": "Resources worden gegroepeerd per objecttype en geobserveerd via afzonderlijke samengestelde Observe-verzoeken (gebalanceerde aanpak)" } }, "snmp": { @@ -2514,19 +2640,21 @@ "type-rulechains": "Regelketens", "list-of-rulechains": "{ count, plural, =1 {Eén regelketen} other {Lijst van # regelketens} }", "rulechain-name-starts-with": "Regelketens met namen die beginnen met '{{prefix}}'", - "type-rulenode": "Regelknooppunt", - "type-rulenodes": "Regelknooppunten", - "list-of-rulenodes": "{ count, plural, =1 {Eén regelknooppunt} other {Lijst van # regelknooppunten} }", - "rulenode-name-starts-with": "Regelknooppunten met namen die beginnen met '{{prefix}}'", + "type-rulenode": "Regelknoop", + "type-rulenodes": "Regelknopen", + "list-of-rulenodes": "{ count, plural, =1 {Eén regelknoop} other {Lijst van # regelknopen} }", + "rulenode-name-starts-with": "Regelknopen waarvan de namen beginnen met '{{prefix}}'", "type-current-customer": "Huidige klant", "type-current-tenant": "Huidige tenant", "type-current-user": "Huidige gebruiker", - "type-current-user-owner": "Eigenaar huidige gebruiker", + "type-current-user-owner": "Eigenaar van huidige gebruiker", "type-calculated-field": "Berekend veld", "type-calculated-fields": "Berekende velden", - "type-widgets-bundle": "Widget-bundel", - "type-widgets-bundles": "Widget-bundels", - "list-of-widgets-bundles": "{ count, plural, =1 {Eén widget-bundel} other {Lijst van # widget-bundels} }", + "type-ai-model": "AI-model", + "type-ai-models": "AI-modellen", + "type-widgets-bundle": "Widgetbundel", + "type-widgets-bundles": "Widgetbundels", + "list-of-widgets-bundles": "{ count, plural, =1 {Eén widgetbundel} other {Lijst van # widgetbundels} }", "type-widget": "Widget", "type-widgets": "Widgets", "list-of-widgets": "{ count, plural, =1 {Eén widget} other {Lijst van # widgets} }", @@ -2553,6 +2681,8 @@ "type-tb-resources": "Resources", "list-of-tb-resources": "{ count, plural, =1 {Eén resource} other {Lijst van # resources} }", "type-ota-package": "OTA-pakket", + "type-ota-packages": "OTA-pakketten", + "list-of-ota-packages": "{ count, plural, =1 {Eén OTA-pakket} other {Lijst van # OTA-pakketten} }", "type-rpc": "RPC", "type-queue": "Wachtrij", "type-queue-stats": "Wachtrijstatistieken", @@ -2604,92 +2734,92 @@ "owner-type": "Eigenaartype" }, "entity-view": { - "entity-view": "Entity view", - "entity-view-required": "Entity view is vereist.", - "entity-views": "Entity views", - "management": "Beheer van Entity Views", - "view-entity-views": "Bekijk Entity Views", - "entity-view-alias": "Entity view-alias", - "aliases": "Entity view-aliasen", + "entity-view": "Entiteitweergave", + "entity-view-required": "Entiteitweergave is verplicht.", + "entity-views": "Entiteitweergaven", + "management": "Beheer van entiteitweergaven", + "view-entity-views": "Bekijk entiteitweergaven", + "entity-view-alias": "Alias voor entiteitweergave", + "aliases": "Aliassen voor entiteitweergave", "no-alias-matching": "'{{alias}}' niet gevonden.", - "no-aliases-found": "Geen aliasen gevonden.", + "no-aliases-found": "Geen aliassen gevonden.", "no-key-matching": "'{{key}}' niet gevonden.", "no-keys-found": "Geen sleutels gevonden.", "create-new-alias": "Maak een nieuwe aan!", "create-new-key": "Maak een nieuwe aan!", - "duplicate-alias-error": "Dubbele alias gevonden '{{alias}}'.
Entity view-aliasen moeten uniek zijn binnen het dashboard.", + "duplicate-alias-error": "Dubbele alias gevonden '{{alias}}'.
Aliassen voor entiteitweergaven moeten uniek zijn binnen het dashboard.", "configure-alias": "Configureer alias '{{alias}}'", - "no-entity-views-matching": "Geen entity views gevonden die overeenkomen met '{{entity}}'.", + "no-entity-views-matching": "Geen entiteitweergaven gevonden die overeenkomen met '{{entity}}'.", "public": "Openbaar", "alias": "Alias", - "alias-required": "Entity view-alias is vereist.", - "remove-alias": "Verwijder entity view-alias", - "add-alias": "Voeg entity view-alias toe", - "name-starts-with": "Entity view naamexpressie", - "help-text": "Gebruik '%' naar behoefte: '%entity-view_name_contains%', '%entity-view_name_ends', 'entity-view_starts_with'.", - "entity-view-list": "Entity view-lijst", - "use-entity-view-name-filter": "Gebruik filter", - "entity-view-list-empty": "Geen entity views geselecteerd.", - "entity-view-name-filter-required": "Entity view naamfilter is vereist.", - "entity-view-name-filter-no-entity-view-matched": "Geen entity views gevonden die beginnen met '{{entityView}}'.", - "add": "Voeg entity view toe", - "entity-view-public": "Entity view is openbaar", + "alias-required": "Alias voor entiteitweergave is verplicht.", + "remove-alias": "Alias van entiteitweergave verwijderen", + "add-alias": "Alias voor entiteitweergave toevoegen", + "name-starts-with": "Naamexpressie van entiteitweergave", + "help-text": "Gebruik '%' waar nodig: '%entity-view_name_contains%', '%entity-view_name_ends', 'entity-view_starts_with'.", + "entity-view-list": "Lijst van entiteitweergaven", + "use-entity-view-name-filter": "Filter gebruiken", + "entity-view-list-empty": "Geen entiteitweergaven geselecteerd.", + "entity-view-name-filter-required": "Naamfilter voor entiteitweergave is verplicht.", + "entity-view-name-filter-no-entity-view-matched": "Geen entiteitweergaven gevonden die beginnen met '{{entityView}}'.", + "add": "Entiteitweergave toevoegen", + "entity-view-public": "Entiteitweergave is openbaar", "assign-to-customer": "Toewijzen aan klant", - "assign-entity-view-to-customer": "Wijs entity view(s) toe aan klant", - "assign-entity-view-to-customer-text": "Selecteer de entity views die u aan de klant wilt toewijzen", - "no-entity-views-text": "Geen entity views gevonden", - "assign-to-customer-text": "Selecteer de klant om de entity view(s) aan toe te wijzen", - "entity-view-details": "Details van entity view", - "add-entity-view-text": "Voeg nieuwe entity view toe", - "delete": "Verwijder entity view", - "assign-entity-views": "Wijs entity views toe", - "assign-entity-views-text": "{ count, plural, =1 {1 entity view} other {# entity views} } toewijzen aan klant", - "delete-entity-views": "Verwijder entity views", - "make-public": "Maak entity view openbaar", - "make-private": "Maak entity view privé", + "assign-entity-view-to-customer": "Entiteitweergave(n) toewijzen aan klant", + "assign-entity-view-to-customer-text": "Selecteer de entiteitweergaven die u aan de klant wilt toewijzen", + "no-entity-views-text": "Geen entiteitweergaven gevonden", + "assign-to-customer-text": "Selecteer de klant aan wie u de entiteitweergave(n) wilt toewijzen", + "entity-view-details": "Details van entiteitweergave", + "add-entity-view-text": "Nieuwe entiteitweergave toevoegen", + "delete": "Entiteitweergave verwijderen", + "assign-entity-views": "Entiteitweergaven toewijzen", + "assign-entity-views-text": "{ count, plural, =1 {1 entiteitweergave toewijzen aan klant} other {# entiteitweergaven toewijzen aan klant} }", + "delete-entity-views": "Entiteitweergaven verwijderen", + "make-public": "Maak entiteitweergave openbaar", + "make-private": "Maak entiteitweergave privé", "unassign-from-customer": "Ontkoppel van klant", - "unassign-entity-views": "Ontkoppel entity views", - "unassign-entity-views-action-title": "{ count, plural, =1 {1 entity view} other {# entity views} } ontkoppelen van klant", - "assign-new-entity-view": "Wijs nieuwe entity view toe", - "delete-entity-view-title": "Weet u zeker dat u de entity view '{{entityViewName}}' wilt verwijderen?", - "delete-entity-view-text": "Wees voorzichtig, na bevestiging wordt de entity view en alle gerelateerde gegevens permanent verwijderd.", - "delete-entity-views-title": "Weet u zeker dat u { count, plural, =1 {1 entity view} other {# entity views} } wilt verwijderen?", - "delete-entity-views-action-title": "Verwijder { count, plural, =1 {1 entity view} other {# entity views} }", - "delete-entity-views-text": "Wees voorzichtig, na bevestiging worden alle geselecteerde entity views verwijderd en worden gerelateerde gegevens permanent verwijderd.", - "make-public-entity-view-title": "Weet u zeker dat u de entity view '{{entityViewName}}' openbaar wilt maken?", - "make-public-entity-view-text": "Na bevestiging wordt de entity view en alle gegevens openbaar en toegankelijk voor anderen.", - "make-private-entity-view-title": "Weet u zeker dat u de entity view '{{entityViewName}}' privé wilt maken?", - "make-private-entity-view-text": "Na bevestiging wordt de entity view en alle gegevens privé en niet langer toegankelijk voor anderen.", - "unassign-entity-view-title": "Weet u zeker dat u de entity view '{{entityViewName}}' wilt ontkoppelen?", - "unassign-entity-view-text": "Na bevestiging wordt de entity view ontkoppeld en niet langer toegankelijk voor de klant.", - "unassign-entity-view": "Ontkoppel entity view", - "unassign-entity-views-title": "Weet u zeker dat u { count, plural, =1 {1 entity view} other {# entity views} } wilt ontkoppelen?", - "unassign-entity-views-text": "Na bevestiging worden alle geselecteerde entity views ontkoppeld en niet langer toegankelijk voor de klant.", - "entity-view-type": "Entity view-type", - "entity-view-type-required": "Entity view-type is vereist.", - "select-entity-view-type": "Selecteer entity view-type", - "enter-entity-view-type": "Voer entity view-type in", - "any-entity-view": "Elke entity view", - "no-entity-view-types-matching": "Geen entity view-types gevonden die overeenkomen met '{{entitySubtype}}'.", - "entity-view-type-list-empty": "Geen entity view-types geselecteerd.", - "entity-view-types": "Entity view-types", + "unassign-entity-views": "Entiteitweergaven ontkoppelen", + "unassign-entity-views-action-title": "{ count, plural, =1 {1 entiteitweergave ontkoppelen van klant} other {# entiteitweergaven ontkoppelen van klant} }", + "assign-new-entity-view": "Nieuwe entiteitweergave toewijzen", + "delete-entity-view-title": "Weet u zeker dat u de entiteitweergave '{{entityViewName}}' wilt verwijderen?", + "delete-entity-view-text": "Let op: na bevestiging wordt de entiteitweergave en alle bijbehorende gegevens permanent verwijderd.", + "delete-entity-views-title": "Weet u zeker dat u { count, plural, =1 {1 entiteitweergave} other {# entiteitweergaven} } wilt verwijderen?", + "delete-entity-views-action-title": "Verwijder { count, plural, =1 {1 entiteitweergave} other {# entiteitweergaven} }", + "delete-entity-views-text": "Let op: na bevestiging worden alle geselecteerde entiteitweergaven en bijbehorende gegevens permanent verwijderd.", + "make-public-entity-view-title": "Weet u zeker dat u de entiteitweergave '{{entityViewName}}' openbaar wilt maken?", + "make-public-entity-view-text": "Na bevestiging wordt de entiteitweergave en alle gegevens openbaar gemaakt en toegankelijk voor anderen.", + "make-private-entity-view-title": "Weet u zeker dat u de entiteitweergave '{{entityViewName}}' privé wilt maken?", + "make-private-entity-view-text": "Na bevestiging wordt de entiteitweergave en alle gegevens privé gemaakt en niet toegankelijk voor anderen.", + "unassign-entity-view-title": "Weet u zeker dat u de entiteitweergave '{{entityViewName}}' wilt ontkoppelen?", + "unassign-entity-view-text": "Na bevestiging wordt de entiteitweergave ontkoppeld en is deze niet langer toegankelijk voor de klant.", + "unassign-entity-view": "Ontkoppel entiteitweergave", + "unassign-entity-views-title": "Weet u zeker dat u { count, plural, =1 {1 entiteitweergave} other {# entiteitweergaven} } wilt ontkoppelen?", + "unassign-entity-views-text": "Na bevestiging worden alle geselecteerde entiteitweergaven ontkoppeld en zijn ze niet langer toegankelijk voor de klant.", + "entity-view-type": "Type entiteitweergave", + "entity-view-type-required": "Type entiteitweergave is verplicht.", + "select-entity-view-type": "Selecteer type entiteitweergave", + "enter-entity-view-type": "Voer type entiteitweergave in", + "any-entity-view": "Elke entiteitweergave", + "no-entity-view-types-matching": "Geen entiteitweergavetypes gevonden die overeenkomen met '{{entitySubtype}}'.", + "entity-view-type-list-empty": "Geen entiteitweergavetypes geselecteerd.", + "entity-view-types": "Entiteitweergavetypes", "created-time": "Aangemaakt op", "name": "Naam", - "name-required": "Naam is vereist.", + "name-required": "Naam is verplicht.", "name-max-length": "Naam moet minder dan 256 tekens zijn", - "type-max-length": "Entity view-type moet minder dan 256 tekens zijn", + "type-max-length": "Type entiteitweergave moet minder dan 256 tekens zijn", "description": "Beschrijving", "events": "Gebeurtenissen", "details": "Details", - "copyId": "Kopieer entity view-ID", - "idCopiedMessage": "Entity view-ID is gekopieerd naar klembord", + "copyId": "Kopieer entiteitweergave-ID", + "idCopiedMessage": "Entiteitweergave-ID is gekopieerd naar het klembord", "assignedToCustomer": "Toegewezen aan klant", - "unable-entity-view-device-alias-title": "Kan entity view-alias niet verwijderen", - "unable-entity-view-device-alias-text": "Device-alias '{{entityViewAlias}}' kan niet worden verwijderd omdat deze wordt gebruikt door de volgende widget(s):
{{widgetsList}}", - "select-entity-view": "Selecteer entity view", + "unable-entity-view-device-alias-title": "Kan alias voor entiteitweergave niet verwijderen", + "unable-entity-view-device-alias-text": "Apparaatalias '{{entityViewAlias}}' kan niet worden verwijderd omdat deze wordt gebruikt door de volgende widget(s):
{{widgetsList}}", + "select-entity-view": "Selecteer entiteitweergave", "start-ts": "Starttijd", "end-ts": "Eindtijd", - "date-limits": "Datumbeperkingen", + "date-limits": "Datumlimieten", "client-attributes": "Clientattributen", "shared-attributes": "Gedeelde attributen", "server-attributes": "Serverattributen", @@ -2699,20 +2829,20 @@ "server-attributes-placeholder": "Serverattributen", "timeseries-placeholder": "Tijdreeks", "target-entity": "Doelentiteit", - "attributes-propagation": "Attributenpropagatie", - "attributes-propagation-hint": "Entity View zal automatisch gespecificeerde attributen kopiëren van de Doelentiteit telkens wanneer u deze entity view opslaat of bijwerkt. Omwille van prestatie-redenen worden attributen van de doelentiteit niet automatisch gesynchroniseerd bij elke wijziging. U kunt automatische propagatie inschakelen door een \"copy to view\" regelnode te configureren in uw regelketen en \"Post attributes\" en \"Attributes Updated\" berichten te koppelen aan de nieuwe regelnode.", + "attributes-propagation": "Attribuutpropagatie", + "attributes-propagation-hint": "De entiteitweergave kopieert automatisch opgegeven attributen van de doelentiteit telkens wanneer je deze entiteitweergave opslaat of bijwerkt. Om prestatieredenen worden attributen van de doelentiteit niet bij elke wijziging doorgegeven. Je kunt automatische propagatie inschakelen door een \"copy to view\"-regelnode te configureren in je regelketen en \"Post attributes\" en \"Attributes Updated\" berichten eraan te koppelen.", "timeseries-data": "Tijdreeksgegevens", - "timeseries-data-hint": "Configureer tijdreeksgegevenssleutels van de doelentiteit die toegankelijk zullen zijn voor de entity view. Deze tijdreeksgegevens zijn alleen-lezen.", - "search": "Zoek entity views", - "selected-entity-views": "{ count, plural, =1 {1 entity view} other {# entity views} } geselecteerd", - "assign-entity-view-to-edge": "Wijs entity view(s) toe aan Edge", - "assign-entity-view-to-edge-text": "Selecteer de entity views die u aan de edge wilt toewijzen", - "unassign-entity-view-from-edge-title": "Weet u zeker dat u de entity view '{{entityViewName}}' wilt ontkoppelen?", - "unassign-entity-view-from-edge-text": "Na bevestiging wordt de entity view ontkoppeld en niet langer toegankelijk door de edge.", - "unassign-entity-views-from-edge-action-title": "{ count, plural, =1 {1 entity view} other {# entity views} } ontkoppelen van edge", - "unassign-entity-view-from-edge": "Ontkoppel entity view", - "unassign-entity-views-from-edge-title": "Weet u zeker dat u { count, plural, =1 {1 entity view} other {# entity views} } wilt ontkoppelen?", - "unassign-entity-views-from-edge-text": "Na bevestiging worden alle geselecteerde entity views ontkoppeld en niet langer toegankelijk door de edge." + "timeseries-data-hint": "Configureer de sleutels van tijdreeksgegevens van de doelentiteit die toegankelijk zullen zijn voor de entiteitweergave. Deze tijdreeksgegevens zijn alleen-lezen.", + "search": "Zoek entiteitweergaven", + "selected-entity-views": "{ count, plural, =1 {1 entiteitweergave} other {# entiteitweergaven} } geselecteerd", + "assign-entity-view-to-edge": "Wijs entiteitweergave(n) toe aan edge", + "assign-entity-view-to-edge-text": "Selecteer de entiteitweergaven om toe te wijzen aan de edge", + "unassign-entity-view-from-edge-title": "Weet je zeker dat je de entiteitweergave '{{entityViewName}}' wilt loskoppelen?", + "unassign-entity-view-from-edge-text": "Na bevestiging wordt de entiteitweergave losgekoppeld en is deze niet langer toegankelijk via de edge.", + "unassign-entity-views-from-edge-action-title": "Koppel { count, plural, =1 {1 entiteitweergave} other {# entiteitweergaven} } los van edge", + "unassign-entity-view-from-edge": "Koppel entiteitweergave los", + "unassign-entity-views-from-edge-title": "Weet je zeker dat je { count, plural, =1 {1 entiteitweergave} other {# entiteitweergaven} } wilt loskoppelen?", + "unassign-entity-views-from-edge-text": "Na bevestiging worden alle geselecteerde entiteitweergaven losgekoppeld en zijn ze niet langer toegankelijk via de edge." }, "event": { "event-type": "Gebeurtenistype", @@ -2929,15 +3059,16 @@ "add": "Filter toevoegen", "edit": "Filter bewerken", "name": "Filternaam", - "name-required": "Filternaam is vereist.", - "duplicate-filter": "Er bestaat al een filter met dezelfde naam.", + "name-required": "Filternaam is verplicht.", + "duplicate-filter": "Een filter met dezelfde naam bestaat al.", "filters": "Filters", "unable-delete-filter-title": "Kan filter niet verwijderen", "unable-delete-filter-text": "Filter '{{filter}}' kan niet worden verwijderd omdat deze wordt gebruikt door de volgende widget(s):
{{widgetsList}}", - "duplicate-filter-error": "Duplicaatfilter gevonden '{{filter}}'.
Filters moeten uniek zijn binnen het dashboard.", + "duplicate-filter-error": "Dubbele filter gevonden '{{filter}}'.
Filters moeten uniek zijn binnen het dashboard.", "missing-key-filters-error": "Sleutelfilters ontbreken voor filter '{{filter}}'.", "filter": "Filter", "editable": "Bewerkbaar", + "editable-hint": "Sta gebruikers toe de filterwaarde in dashboards aan te passen.", "no-filters-found": "Geen filters gevonden.", "no-filter-text": "Geen filter opgegeven", "add-filter-prompt": "Voeg een filter toe", @@ -2962,22 +3093,24 @@ "in": "in", "not-in": "niet in" }, - "ignore-case": "negeer hoofdlettergebruik", + "ignore-case": "Hoofdlettergevoeligheid negeren", "value": "Waarde", - "remove-filter": "Verwijder filter", - "duplicate-filter-action": "Dupliceer filter", + "remove-filter": "Filter verwijderen", + "duplicate-filter-action": "Filter dupliceren", "preview": "Filtervoorbeeld", "no-filters": "Geen filters geconfigureerd", "add-filter": "Filter toevoegen", - "add-complex-filter": "Complex filter toevoegen", - "add-complex": "Voeg complex toe", - "complex-filter": "Complex filter", - "edit-complex-filter": "Complex filter bewerken", - "edit-filter-user-params": "Filtergebruikersparameters bewerken", - "filter-user-params": "Filtergebruikersparameters", + "add-complex-filter": "Complexe filter toevoegen", + "add-complex": "Complex toevoegen", + "complex-filter": "Complexe filter", + "edit-complex-filter": "Complexe filter bewerken", + "edit-filter-user-params": "Gebruikersparameters van filtervoorwaarde bewerken", + "filter-user-params": "Gebruikersparameters van filtervoorwaarde", "user-parameters": "Gebruikersparameters", - "display-label": "Label om weer te geven", - "order-priority": "Volgordeprioriteit van veld", + "display-label": "Weergavelabel", + "custom-label": "Aangepast label", + "custom-label-hint": "Inschakelen om je eigen label voor de filter in te stellen. Wanneer uitgeschakeld, wordt automatisch een label gegenereerd.", + "order-priority": "Weergavevolgorde", "key-filter": "Sleutelfilter", "key-filters": "Sleutelfilters", "key-name": "Sleutelnaam", @@ -3021,7 +3154,8 @@ "switch-to-dynamic-value": "Overschakelen naar dynamische waarde", "switch-to-default-value": "Overschakelen naar standaardwaarde", "inherit-owner": "Overnemen van eigenaar", - "source-attribute-not-set": "Als het bronattribuut niet is ingesteld" + "source-attribute-not-set": "Als bronattribuut niet is ingesteld", + "unit": "Eenheid" }, "fullscreen": { "expand": "Vergroot naar volledig scherm", @@ -3406,10 +3540,11 @@ "power-button-background": "Achtergrond stroomknop", "value-box-background": "Achtergrond waardeveld", "value-units": "Waarde-eenheden", + "enable-units-scale": "Eenheden op schaal inschakelen", "filtration-mode": "Filtratiemodus", - "filtration-mode-hint": "Geheel getal dat huidige filtratiemodus aangeeft.", - "filtration-mode-update": "Filtratiemodus bijwerken", - "filtration-mode-update-hint": "Actie uitgevoerd bij wijziging van filtratiemodus.", + "filtration-mode-hint": "Geheel getal dat de huidige filtratiemodus aangeeft.", + "filtration-mode-update": "Update-status filtratiemodus", + "filtration-mode-update-hint": "Actie die wordt uitgevoerd wanneer de gebruiker klikt om de huidige filtratiemodus te wijzigen.", "filter-mode": "Filter", "waste-mode": "Afval", "backwash-mode": "Terugspoelen", @@ -3721,7 +3856,9 @@ "mobile-package": "Applicatiepakket", "mobile-package-max-length": "Applicatiepakket mag niet langer zijn dan 256 tekens", "mobile-package-required": "Applicatiepakket is verplicht.", - "mobile-package-pattern": "Ongeldig formaat applicatiepakket", + "mobile-package-pattern": "Ongeldig formaat van applicatiepakket", + "mobile-package-title": "Applicatietitel", + "mobile-package-title-max-length": "Applicatietitel mag niet langer zijn dan 256 tekens", "no-application": "Geen applicaties gevonden", "no-bundles": "Geen pakketten gevonden", "platform-type": "Platformtype", @@ -3802,20 +3939,16 @@ "configuration-app": "Configuratie-app", "configuration-step": { "prepare-environment-title": "Ontwikkelomgeving voorbereiden", - "prepare-environment-text": "Flutter ThingsBoard Mobile App vereist Flutter SDK. Volg de instructies om de Flutter SDK in te stellen.", - "get-source-code-title": "App-broncode verkrijgen", - "get-source-code-text": "Je kunt de broncode van de Flutter ThingsBoard Mobile App verkrijgen door deze uit de GitHub-repository te klonen:", - "configure-api-title": "ThingsBoard API-eindpunt configureren", - "configure-api-text": "Open het flutter_thingsboard_pe_app-project in je editor/IDE. Bewerk:", - "configure-api-hint": "Stel de waarde van de constant thingsBoardApiEndpoint in op het API-eindpunt van je ThingsBoard-serverinstantie. Gebruik geen 'localhost' of '127.0.0.1'.", - "run-app-title": "De app uitvoeren", - "run-app-text": "Voer de app uit zoals beschreven in je IDE.\nGebruik je de terminal, voer de app dan uit met het volgende commando:", - "more-information": "Gedetailleerde informatie vind je in onze Getting Started-documentatie.", - "getting-started": "Aan de slag", - "configure-package-title": "Applicatiepakket configureren", - "configure-package-text": "Je kunt het applicatiepakket handmatig wijzigen of een CLI-hulpprogramma van derden gebruiken.", - "configure-package-text-install": "Voer het volgende commando uit om de Rename CLI Tool te installeren:", - "configure-package-run-commands": "Voer deze commando’s uit in de hoofdmap van je project:" + "prepare-environment-text": "Flutter ThingsBoard Mobiele Applicatie vereist de Flutter SDK. Volg de instructies om de Flutter SDK in te stellen.", + "get-source-code-title": "Broncode van de app verkrijgen", + "get-source-code-text": "Je kunt de broncode van de Flutter ThingsBoard Mobiele Applicatie verkrijgen door deze te clonen vanuit de GitHub-repository:", + "configure-app-settings-title": "App-instellingen configureren", + "configure-app-settings-text": "Download het configuratiebestand en plaats het in de hoofdmap van het project dat je in de vorige stap hebt gekloond.", + "download-file": "Bestand downloaden", + "run-app-title": "App uitvoeren", + "run-app-text": "Voer de app uit zoals beschreven in je IDE.\nIndien je de terminal gebruikt, voer de app uit met het volgende commando:", + "more-information": "Gedetailleerde informatie vind je in onze documentatie voor een snelle start.", + "getting-started": "Snel starten" } }, "notification": { @@ -3839,20 +3972,22 @@ "new-platform-version-trigger-settings": "Triggerinstellingen voor nieuwe platformversie", "rate-limits-trigger-settings": "Triggerinstellingen voor overschreden snelheidslimieten", "task-processing-failure-trigger-settings": "Triggerinstellingen voor taakverwerkingsfouten", - "at-least-one-should-be-selected": "Ten minste één moet worden geselecteerd", + "resources-shortage-trigger-settings": "Instellingen voor triggers bij tekort aan middelen", + "at-least-one-should-be-selected": "Ten minste één optie moet geselecteerd zijn", "basic-settings": "Basisinstellingen", "button-text": "Knoptekst", "button-text-required": "Knoptekst is verplicht", - "button-text-max-length": "Knoptekst mag niet langer zijn dan {{ length }} tekens", + "button-text-max-length": "Knoptekst mag maximaal {{ length }} tekens bevatten", "compose": "Samenstellen", "conversation": "Gesprek", "conversation-required": "Gesprek is verplicht", - "copy-notification-template": "Meldingssjabloon kopiëren", - "copy-rule": "Regel kopiëren", - "copy-template": "Sjabloon kopiëren", + "copy-notification-template": "Kopieer notificatiesjabloon", + "copy-rule": "Kopieer regel", + "copy-template": "Kopieer sjabloon", "create-new": "Nieuw aanmaken", - "created": "Gemaakt", + "created": "Aangemaakt", "customize-messages": "Berichten aanpassen", + "cpu-threshold": "CPU-drempelwaarde", "delete-notification-text": "Wees voorzichtig, na bevestiging is de melding niet meer herstelbaar.", "delete-notification-title": "Weet u zeker dat u de melding wilt verwijderen?", "delete-notifications-text": "Wees voorzichtig, na bevestiging zijn meldingen niet meer herstelbaar.", @@ -3889,9 +4024,9 @@ "mobile-app": "Mobiele app", "mobile-app-preview": "Voorbeeld mobiele app-melding" }, - "delivery-method-not-configure-click": "Bezorgmethode is niet geconfigureerd. Klik om in te stellen.", - "delivery-method-not-configure-contact": "Bezorgmethode is niet geconfigureerd. Neem contact op met uw systeembeheerder.", - "delivery-methods": "Bezorgmethodes", + "delivery-method-not-configure-click": "Verzendmethode is niet geconfigureerd. Klik om in te stellen.", + "delivery-method-not-configure-contact": "Verzendmethode is niet geconfigureerd. Neem contact op met je systeembeheerder.", + "delivery-methods": "Verzendmethoden", "description": "Beschrijving", "device-activity-trigger-settings": "Triggerinstellingen voor apparaatactiviteit", "device-list-rule-hint": "Als dit veld leeg is, wordt de trigger toegepast op alle apparaten", @@ -3919,6 +4054,7 @@ "input-fields-support-templatization": "Invoervelden ondersteunen templatization.", "link": "Link", "link-required": "Link is verplicht", + "link-max-length": "Link mag maximaal {{ length }} tekens bevatten", "link-type": { "dashboard": "Dashboard openen", "link": "URL-link openen" @@ -3945,13 +4081,14 @@ "no-severity-found": "Geen ernstniveau gevonden", "no-severity-matching": "'{{severity}}' niet gevonden.", "no-template-matching": "Geen bron gevonden die overeenkomt met '{{template}}'.", + "create-new-template": "Maak een nieuwe aan!", "not-found-slack-recipient": "Slack-ontvanger niet gevonden", - "notification": "Melding", - "notification-center": "Meldingscentrum", - "notification-tap-action": "Actie bij tikken op melding", + "notification": "Notificatie", + "notification-center": "Notificatiecentrum", + "notification-tap-action": "Actie bij tikken op notificatie", "notification-tap-action-hint": "Indien niet ingeschakeld, wordt het standaard alarmdashboard gebruikt", - "notify": "Melden", - "notify-again": "Opnieuw melden", + "notify": "notificeren", + "notify-again": "Opnieuw notificeren", "notify-alarm-action": { "acknowledged": "Alarm bevestigd", "assigned": "Alarm toegewezen", @@ -3968,6 +4105,7 @@ "only-rule-chain-lifecycle-failures": "Alleen fouten in levenscyclus van regelketen", "only-rule-node-lifecycle-failures": "Alleen fouten in levenscyclus van regelknooppunt", "platform-users": "Platformgebruikers", + "ram-threshold": "RAM-drempelwaarde", "rate-limits": "Snelheidslimieten", "rate-limits-hint": "Als dit veld leeg is, wordt de trigger toegepast op alle snelheidslimieten", "recipient": "Ontvanger", @@ -4033,6 +4171,7 @@ "start-from-scratch": "Begin opnieuw", "status": "Status", "stop-escalation-alarm-status-become": "Stop escalatie wanneer de alarmstatus wordt:", + "storage-threshold": "Opslagdrempelwaarde", "subject": "Onderwerp", "subject-required": "Onderwerp is verplicht", "subject-max-length": "Onderwerp mag maximaal {{ length }} tekens bevatten", @@ -4041,20 +4180,21 @@ "template-required": "Sjabloon is verplicht", "template-type": { "alarm": "Alarm", - "alarm-assignment": "Alarmaanwijzing", + "alarm-assignment": "Toewijzing van alarm", "alarm-comment": "Alarmopmerking", - "api-usage-limit": "API-gebruiksgrens", + "api-usage-limit": "API-gebruikslimiet", "device-activity": "Apparaatactiviteit", "entities-limit": "Entiteitenlimiet", - "entity-action": "Entiteitactie", + "entity-action": "Entiteithandeling", "general": "Algemeen", "rule-engine-lifecycle-event": "Levenscyclusgebeurtenis van regelengine", "rule-node": "Regelknooppunt", "new-platform-version": "Nieuwe platformversie", - "rate-limits": "Overschreden snelheidslimieten", - "edge-communication-failure": "Edge communicatie storing", - "edge-connection": "Edge verbinding", - "task-processing-failure": "Taakverwerkingsfout" + "rate-limits": "Snelheidslimieten overschreden", + "edge-communication-failure": "Communicatiefout met edge", + "edge-connection": "Edge-verbinding", + "task-processing-failure": "Fout bij taakverwerking", + "resources-shortage": "Gebrek aan middelen" }, "templates": "Sjablonen", "notification-templates": "Meldingen / Sjablonen", @@ -4066,18 +4206,19 @@ "track-rule-node-events": "Volg gebeurtenissen van regelknooppunten", "trigger": { "alarm": "Alarm", - "alarm-assignment": "Alarmaanwijzing", + "alarm-assignment": "Toewijzing van alarm", "alarm-comment": "Alarmopmerking", - "api-usage-limit": "API-gebruiksgrens", + "api-usage-limit": "API-gebruikslimiet", "device-activity": "Apparaatactiviteit", "entities-limit": "Entiteitenlimiet", - "entity-action": "Entiteitactie", + "entity-action": "Entiteithandeling", "rule-engine-lifecycle-event": "Levenscyclusgebeurtenis van regelengine", "new-platform-version": "Nieuwe platformversie", - "rate-limits": "Overschreden snelheidslimieten", - "edge-connection": "Edge verbinding", - "edge-communication-failure": "Edge communicatie storing", - "task-processing-failure": "Taakverwerkingsfout", + "rate-limits": "Snelheidslimieten overschreden", + "edge-connection": "Edge-verbinding", + "edge-communication-failure": "Communicatiefout met edge", + "task-processing-failure": "Fout bij taakverwerking", + "resources-shortage": "Gebrek aan middelen", "trigger": "Trigger", "trigger-required": "Trigger is verplicht" }, @@ -4117,11 +4258,12 @@ "checksum-hint": "Als checksum leeg is, wordt deze automatisch gegenereerd", "checksum-algorithm": "Checksum-algoritme", "checksum-copied-message": "Pakket-checksum is gekopieerd naar het klembord", - "change-firmware": "Het wijzigen van de firmware kan een update van { count, plural, =1 {1 apparaat} other {# apparaten} } veroorzaken.", - "change-software": "Het wijzigen van de software kan een update van { count, plural, =1 {1 apparaat} other {# apparaten} } veroorzaken.", + "change-firmware": "Het wijzigen van de firmware kan leiden tot een update van { count, plural, =1 {1 apparaat} other {# apparaten} }.", + "change-software": "Het wijzigen van de software kan leiden tot een update van { count, plural, =1 {1 apparaat} other {# apparaten} }.", + "change-ota-setting-title": "Weet u zeker dat u de OTA-instellingen wilt wijzigen?", "chose-compatible-device-profile": "Het geüploade pakket is alleen beschikbaar voor apparaten met het gekozen profiel.", - "chose-firmware-distributed-device": "Kies firmware die wordt verspreid naar apparaten", - "chose-software-distributed-device": "Kies software die wordt verspreid naar apparaten", + "chose-firmware-distributed-device": "Kies de firmware die wordt verspreid naar de apparaten", + "chose-software-distributed-device": "Kies de software die wordt verspreid naar de apparaten", "content-type": "Inhoudstype", "copy-checksum": "Checksum kopiëren", "copy-direct-url": "Directe URL kopiëren", @@ -4314,8 +4456,9 @@ "add-relation-filter": "Relatiefilter toevoegen", "any-relation": "Elke relatie", "relation-filters": "Relatiefilters", + "relation-filter": "Relatiefilter", "additional-info": "Aanvullende info (JSON)", - "invalid-additional-info": "Kan aanvullende info JSON niet verwerken.", + "invalid-additional-info": "Kan aanvullende info JSON niet ontleden.", "no-relations-text": "Geen relaties gevonden", "not": "Niet" }, @@ -4354,15 +4497,21 @@ "jks": "JKS", "js-module": "JS-module", "lwm2m-model": "LWM2M-model", - "pkcs-12": "PKCS #12" + "pkcs-12": "PKCS #12", + "general": "Algemeen" }, "resource-sub-type": "Subtype", "sub-type": { "image": "afbeelding", - "scada-symbol": "Scada-symbool", + "scada-symbol": "SCADA-symbool", "extension": "Extensie", "module": "Module" - } + }, + "resource-is-in-use": "Resource wordt gebruikt door andere entiteiten", + "resources-are-in-use": "Resources worden gebruikt door andere entiteiten", + "resource-is-in-use-text": "De resource '{{title}}' is niet verwijderd omdat deze wordt gebruikt door de volgende entiteiten:", + "resources-are-in-use-text": "Niet alle resources zijn verwijderd omdat ze worden gebruikt door andere entiteiten.
U kunt de verwijzende entiteiten bekijken door op de knop Referenties in de overeenkomstige resource-rij te klikken.
Als u deze resources toch wilt verwijderen, selecteer ze dan in de onderstaande tabel en klik op de knop Selectie verwijderen.", + "delete-resource-in-use-text": "Als u de resource toch wilt verwijderen, klik dan op de knop Toch verwijderen." }, "javascript": { "add": "JavaScript-bron toevoegen", @@ -4902,8 +5051,8 @@ "credentials-anonymous": "Anoniem", "credentials-basic": "Basis", "credentials-pem": "PEM", - "credentials-pem-hint": "Minstens een Server CA-certificaatbestand of een paar Client-certificaat en Client privésleutelbestanden zijn vereist", - "credentials-sas": "Gedeelde Toegangshandtekening", + "credentials-pem-hint": "Minstens een Server CA-certificaatbestand of een paar Clientcertificaat en Client private key-bestanden zijn vereist", + "credentials-sas": "Gedeelde Toegangssleutel (SAS)", "sas-key": "SAS-sleutel", "sas-key-required": "SAS-sleutel is verplicht.", "hostname": "Hostnaam", @@ -4993,29 +5142,29 @@ "entity-details-phone": "Telefoon", "entity-details-email": "E-mail", "email-sender": "E-mailsender", - "fields-to-check": "Velden om te controleren", + "fields-to-check": "Te controleren velden", "add-detail": "Detail toevoegen", - "check-all-keys-tooltip": "Controleer of alle opgegeven velden aanwezig zijn in gegevens en metadata van het bericht.", - "fields-to-check-hint": "Druk op 'Enter' om veldnaam te voltooien. Meerdere namen ondersteund.", - "entity-details-list-empty": "Selecteer ten minste één detail.", + "check-all-keys-tooltip": "Indien ingeschakeld, wordt gecontroleerd of alle vermelde velden in de boodschap en de metagegevens aanwezig zijn.", + "fields-to-check-hint": "Druk op \"Enter\" om de invoer van veldnaam te voltooien. Meerdere veldnamen worden ondersteund.", + "entity-details-list-empty": "Minstens één detail moet geselecteerd zijn.", "alarm-status": "Alarmstatus", - "alarm-required": "Minstens één alarmstatus is vereist.", + "alarm-required": "Minstens één alarmstatus moet geselecteerd zijn.", "no-entity-details-matching": "Geen overeenkomende entiteitsdetails gevonden.", "custom-table-name": "Aangepaste tabelnaam", "custom-table-name-required": "Tabelnaam is verplicht", - "custom-table-hint": "Tabel moet bestaan in Cassandra-cluster en beginnen met 'cs_tb_'. Geef naam zonder prefix op.", + "custom-table-hint": "De tabel moet zijn aangemaakt in je Cassandra-cluster en de naam moet beginnen met het voorvoegsel 'cs_tb_' om te voorkomen dat gegevens in algemene TB-tabellen worden geschreven. Voer hier de tabelnaam in zonder het voorvoegsel 'cs_tb_'.", "message-field": "Berichtveld", "message-field-required": "Berichtveld is verplicht.", "table-col": "Tabelkolom", "table-col-required": "Tabelkolom is verplicht.", - "latitude-field-name": "Breedtegraadveldnaam", - "longitude-field-name": "Lengtegraadveldnaam", - "latitude-field-name-required": "Breedtegraadveldnaam is verplicht.", - "longitude-field-name-required": "Lengtegraadveldnaam is verplicht.", - "fetch-perimeter-info-from-metadata": "Perimeterinformatie uit metadata ophalen", - "fetch-perimeter-info-from-metadata-tooltip": "Bij 'Polygon' wordt waarde direct gebruikt. Bij 'Circle' worden velden 'latitude', 'longitude', 'radius' en 'radiusUnit' verwacht.", + "latitude-field-name": "Naam breedtegraadveld", + "longitude-field-name": "Naam lengtegraadveld", + "latitude-field-name-required": "Naam van breedtegraadveld is verplicht.", + "longitude-field-name-required": "Naam van lengtegraadveld is verplicht.", + "fetch-perimeter-info-from-metadata": "Perimeterinformatie ophalen uit metadata", + "fetch-perimeter-info-from-metadata-tooltip": "Als het perimetertype is ingesteld op 'Polygon', wordt de waarde van het metagegevensveld '{{perimeterKeyName}}' rechtstreeks gebruikt als perimetrische definitie. Als het perimetertype 'Circle' is, wordt deze waarde geparseerd om 'latitude', 'longitude', 'radius', en 'radiusUnit' te extraheren voor de definitie van de cirkelperimeter.", "perimeter-key-name": "Perimeter sleutelnaam", - "perimeter-key-name-hint": "Metadata veldnaam met perimeterinformatie.", + "perimeter-key-name-hint": "Naam van het metagegevensveld dat perimeterinformatie bevat.", "perimeter-key-name-required": "Perimeter sleutelnaam is verplicht.", "perimeter-circle": "Cirkel", "perimeter-polygon": "Polygoon", @@ -5035,19 +5184,19 @@ "range-required": "Bereik is verplicht.", "polygon-definition": "Polygoondefinitie", "polygon-definition-required": "Polygoondefinitie is verplicht.", - "polygon-definition-hint": "Gebruik formaat: [[lat1,lon1],[lat2,lon2],...,[latN,lonN]].", - "min-inside-duration": "Minimale binnentijdsduur", - "min-inside-duration-value-required": "Minimale binnentijdsduur is verplicht", - "min-inside-duration-time-unit": "Tijdseenheid minimale binnentijdsduur", - "min-outside-duration": "Minimale buitentijdsduur", - "min-outside-duration-value-required": "Minimale buitentijdsduur is verplicht", - "min-outside-duration-time-unit": "Tijdseenheid minimale buitentijdsduur", - "tell-failure-if-absent": "Meld mislukking", - "tell-failure-if-absent-hint": "Indien geselecteerd, genereert fout bij ontbrekende sleutelwaarden.", - "get-latest-value-with-ts": "Ophalen met tijdstempel", - "get-latest-value-with-ts-hint": "Geeft ook tijdstempel bij laatste telemetrie, bijv.: \"temp\": {\"ts\":1574329385897, \"value\":42}", - "ignore-null-strings": "Negeer lege strings", - "ignore-null-strings-hint": "Indien geselecteerd, worden lege waarden genegeerd.", + "polygon-definition-hint": "Gebruik het volgende formaat voor handmatige definitie van een polygoon: [[lat1,lon1],[lat2,lon2], ... ,[latN,lonN]].", + "min-inside-duration": "Minimale tijd binnen gebied", + "min-inside-duration-value-required": "Minimale tijd binnen gebied is verplicht", + "min-inside-duration-time-unit": "Tijdseenheid voor minimale tijd binnen gebied", + "min-outside-duration": "Minimale tijd buiten gebied", + "min-outside-duration-value-required": "Minimale tijd buiten gebied is verplicht", + "min-outside-duration-time-unit": "Tijdseenheid voor minimale tijd buiten gebied", + "tell-failure-if-absent": "Melding bij afwezigheid", + "tell-failure-if-absent-hint": "Indien ten minste één geselecteerde sleutel ontbreekt, rapporteert het uitgaande bericht \"Mislukt\".", + "get-latest-value-with-ts": "Tijdstempel ophalen voor laatste telemetriegegevens", + "get-latest-value-with-ts-hint": "Indien geselecteerd, bevatten de laatste telemetriegegevens ook een tijdstempel, bijvoorbeeld: \"temp\": \"{\"ts\":1574329385897, \"value\":42}\"", + "ignore-null-strings": "Negeer lege tekenreeksen", + "ignore-null-strings-hint": "Indien geselecteerd, negeert de regelnode entiteitsvelden met een lege waarde.", "add-metadata-key-values-as-kafka-headers": "Voeg metadata toe aan Kafka headers", "add-metadata-key-values-as-kafka-headers-hint": "Metadata key-value paren worden als byte arrays met charset toegevoegd.", "charset-encoding": "Tekenset codering", @@ -5058,44 +5207,44 @@ "charset-utf-16be": "UTF-16BE", "charset-utf-16le": "UTF-16LE", "charset-utf-16": "UTF-16", - "select-queue-hint": "De naam van de wachtrij kan uit de lijst gekozen worden of als aangepaste naam worden ingevoerd.", - "device-profile-node-hint": "Nuttig bij duur- of herhalingscondities om consistentie van alarmstatus te waarborgen.", - "persist-alarm-rules": "Alarmregelstatus opslaan", - "persist-alarm-rules-hint": "Indien ingeschakeld, slaat deze knooppunt de status van verwerking op in de database.", - "fetch-alarm-rules": "Haal alarmregelstatus op", - "fetch-alarm-rules-hint": "Herstelt status bij initialisatie, zodat alarmen na herstart blijven functioneren.", - "input-value-key": "Sleutel invoerwaarde", - "input-value-key-required": "Sleutel invoerwaarde is verplicht.", - "output-value-key": "Sleutel uitvoerwaarde", - "output-value-key-required": "Sleutel uitvoerwaarde is verplicht.", - "number-of-digits-after-floating-point": "Aantal decimalen na komma", - "number-of-digits-after-floating-point-range": "Moet tussen 0 en 15 liggen.", - "failure-if-delta-negative": "Foutmelding bij negatieve delta", - "failure-if-delta-negative-tooltip": "Veroorzaakt fout als delta negatief is.", - "use-caching": "Gebruik caching", - "use-caching-tooltip": "Cache waarde van \"{{inputValueKey}}\" voor betere prestaties.", - "add-time-difference-between-readings": "Voeg tijdsverschil toe tussen \"{{inputValueKey}}\" metingen", - "add-time-difference-between-readings-tooltip": "Voegt \"{{periodValueKey}}\" toe aan uitgaand bericht.", - "period-value-key": "Periode sleutel", - "period-value-key-required": "Periode sleutel is verplicht.", - "general-pattern-hint": "Gebruik ${metadataKey} voor metadata en $[messageKey] voor berichtgegevens.", - "alarm-severity-pattern-hint": "Gebruik ${metadataKey} voor de waarde uit de metadata, $[messageKey] voor de waarde uit de berichtinhoud. De alarmernst moet een systeemwaarde zijn (CRITICAL, MAJOR, enz.)", - "output-node-name-hint": "Naam van rule node is het relatietype dat berichten doorstuurt naar andere nodes.", - "use-server-ts": "Gebruik server tijdstempel", - "use-server-ts-hint": "Gebruik server tijdstempel bij ontbreken van expliciete tijd in gegevens.", - "kv-map-pattern-hint": "Alle invoervelden ondersteunen templates. Gebruik $[messageKey] of ${metadataKey}.", - "kv-map-single-pattern-hint": "Ondersteunt templates. Gebruik $[messageKey] of ${metadataKey}.", - "shared-scope": "Gedeeld bereik", - "server-scope": "Serverbereik", - "client-scope": "Clientbereik", + "select-queue-hint": "De wachtrijnaam kan worden geselecteerd via een keuzelijst of handmatig worden ingevoerd.", + "device-profile-node-hint": "Handig bij duur- of herhalingsvoorwaarden om continuïteit van alarmevaluatie te waarborgen.", + "persist-alarm-rules": "Status van alarmregels opslaan", + "persist-alarm-rules-hint": "Indien ingeschakeld, slaat de regelnode de verwerkingsstatus op in de database.", + "fetch-alarm-rules": "Status van alarmregels ophalen", + "fetch-alarm-rules-hint": "Indien ingeschakeld, herstelt de regelnode de verwerkingsstatus bij initialisatie en zorgt ervoor dat alarmen ook na serverherstart worden geactiveerd. Anders wordt de status hersteld wanneer het eerste bericht van het apparaat binnenkomt.", + "input-value-key": "Invoerwaarde-sleutel", + "input-value-key-required": "Invoerwaarde-sleutel is verplicht.", + "output-value-key": "Uitvoerwaarde-sleutel", + "output-value-key-required": "Uitvoerwaarde-sleutel is verplicht.", + "number-of-digits-after-floating-point": "Aantal cijfers na de komma", + "number-of-digits-after-floating-point-range": "Aantal cijfers na de komma moet tussen 0 en 15 liggen.", + "failure-if-delta-negative": "Melding bij negatieve delta", + "failure-if-delta-negative-tooltip": "De regelnode dwingt een verwerkingsfout af als de deltawaarde negatief is.", + "use-caching": "Caching gebruiken", + "use-caching-tooltip": "De regel‑node cacheert de waarde van \"{{inputValueKey}}\" die binnenkomt via het inkomende bericht om de prestaties te verbeteren. Houd er rekening mee dat de cache niet wordt bijgewerkt als u de waarde van \"{{inputValueKey}}\" elders wijzigt.", + "add-time-difference-between-readings": "Tijdsverschil toevoegen tussen \"{{inputValueKey}}\" metingen", + "add-time-difference-between-readings-tooltip": "Indien ingeschakeld, voegt de regel‑node de \"{{periodValueKey}}\" toe aan het uitgaande bericht.", + "period-value-key": "Sleutel voor periode‑waarde", + "period-value-key-required": "Sleutel voor periode‑waarde is verplicht.", + "general-pattern-hint": "Gebruik ${metadataKey} voor waarden uit metadata, $[messageKey] voor waarden uit het berichtlichaam.", + "alarm-severity-pattern-hint": "Gebruik ${metadataKey} voor een waarde uit metadata, en $[messageKey] voor een waarde uit het berichtlichaam. De alarmernst moet een systeemniveau zijn (CRITICAL, MAJOR, enz.).", + "output-node-name-hint": "De regel‑node‑naam komt overeen met het relatietype van het uitgaande bericht, en wordt gebruikt om berichten door te sturen naar andere regel‑nodes in de oproepende regelketen.", + "use-server-ts": "Gebruik de tijdstempel van de server", + "use-server-ts-hint": "Gebruik de huidige tijdstempel van de server voor tijdreeksgegevens die geen expliciete tijdstempel bevatten. Dit helpt om de juiste volgorde te behouden wanneer berichten uit meerdere bronnen komen of buiten volgorde binnenkomen.", + "kv-map-pattern-hint": "Alle invoervelden ondersteunen templatisering. Gebruik $[messageKey] om een waarde uit het bericht te halen en ${metadataKey} om een waarde uit de metadata te halen.", + "kv-map-single-pattern-hint": "Invoerveld ondersteunt templatisering. Gebruik $[messageKey] voor een waarde uit het bericht en ${metadataKey} voor een waarde uit de metadata.", + "shared-scope": "Gedeelde scope", + "server-scope": "Server‑scope", + "client-scope": "Client‑scope", "attribute-type": "Attribuut", - "attribute-type-description": "Waarde uit database ophalen", - "attribute-type-result-description": "Resultaat opslaan als attribuut", + "attribute-type-description": "Haal attribuutwaarde op uit de database", + "attribute-type-result-description": "Sla resultaat op als entiteitsattribuut in de database", "constant-type": "Constante", - "constant-type-description": "Stel vaste waarde in", + "constant-type-description": "Definieer een constante waarde", "time-series-type": "Tijdreeks", - "time-series-type-description": "Laatste tijdreekswaarde ophalen", - "time-series-type-result-description": "Resultaat opslaan als tijdreeks", + "time-series-type-description": "Haal de laatste tijdreekswaarde op uit de database", + "time-series-type-result-description": "Sla het resultaat op als een entiteits‑tijdreeks in de database", "message-body-type": "Bericht", "message-body-type-description": "Waarde uit bericht ophalen", "message-body-type-result-description": "Resultaat toevoegen aan bericht", @@ -5113,8 +5262,8 @@ "argument-key-field-input-required": "Sleutel is verplicht.", "constant-value-field-input": "Constante waarde", "constant-value-field-input-required": "Constante waarde is verplicht.", - "attribute-scope-field-input": "Attribuutbereik", - "attribute-scope-field-input-required": "Attribuutbereik is verplicht.", + "attribute-scope-field-input": "Attribuutscope", + "attribute-scope-field-input-required": "Attribuutscope is verplicht.", "default-value-field-input": "Standaardwaarde", "type-field-input": "Type", "type-field-input-required": "Type is verplicht.", @@ -5167,19 +5316,19 @@ "first-name": "Voornaam", "last-name": "Achternaam", "label": "Label", - "originator-fields-mapping": "Bronveld-mapping", - "add-mapped-originator-fields-to": "Voeg gemapte bronvelden toe aan", + "originator-fields-mapping": "Toewijzing oorsprongsvelden", + "add-mapped-originator-fields-to": "Toegevoegde oorsprongsvelden plaatsen in", "fields": "Velden", "skip-empty-fields": "Lege velden overslaan", - "skip-empty-fields-tooltip": "Velden zonder waarde worden niet toegevoegd aan bericht of metadata.", - "fetch-interval": "Ophaalinterval", + "skip-empty-fields-tooltip": "Velden met lege waarden worden niet toegevoegd aan het uitgaande bericht/uitgaande metadata.", + "fetch-interval": "Ophaalfrequentie", "fetch-strategy": "Ophaalstrategie", - "fetch-timeseries-from-to": "Ophaal tijdreeks van {{startInterval}} {{startIntervalTimeUnit}} geleden tot {{endInterval}} {{endIntervalTimeUnit}} geleden.", - "fetch-timeseries-from-to-invalid": "\"Interval start\" moet kleiner zijn dan \"Interval einde\".", - "use-metadata-dynamic-interval-tooltip": "Gebruikt dynamisch interval op basis van bericht/metadata.", - "all-mode-hint": "Met 'All' worden alle tijdreeksen binnen het interval opgehaald.", - "first-mode-hint": "'First' haalt dichtstbijzijnde tijdreeks op bij start van interval.", - "last-mode-hint": "'Last' haalt dichtstbijzijnde tijdreeks op bij einde van interval.", + "fetch-timeseries-from-to": "Haal tijdreeksen op van {{startInterval}} {{startIntervalTimeUnit}} geleden tot {{endInterval}} {{endIntervalTimeUnit}} geleden.", + "fetch-timeseries-from-to-invalid": "Ophalen tijdreeksen ongeldig (\"Intervalstart\" moet kleiner zijn dan \"Intervaleind\").", + "use-metadata-dynamic-interval-tooltip": "Indien geselecteerd zal de regel‑node dynamische intervalstart en eind gebruiken op basis van berichten- en metadata‑patronen.", + "all-mode-hint": "Indien de ophaalmodus \"Alle\" is geselecteerd, haalt de regel‑node telemetrie op binnen het ophaalinterval met configureerbare query‑parameters.", + "first-mode-hint": "Indien de ophaalmodus \"Eerste\" is geselecteerd, haalt de regel‑node de dichtstbijzijnde telemetrie op ten opzichte van het begin van het ophaalinterval.", + "last-mode-hint": "Indien de ophaalmodus \"Laatste\" is geselecteerd, haalt de regel‑node de dichtstbijzijnde telemetrie op ten opzichte van het einde van het ophaalinterval.", "ascending": "Oplopend", "descending": "Aflopend", "min": "Min", @@ -5188,45 +5337,45 @@ "sum": "Som", "count": "Aantal", "none": "Geen", - "last-level-relation-tooltip": "Zoekt alleen gerelateerde entiteiten op laatste niveau.", - "last-level-device-relation-tooltip": "Zoekt alleen gerelateerde apparaten op laatste niveau.", - "data-to-fetch": "Gegevens op te halen", - "mapping-of-customers": "Mapping van klant", - "map-fields-required": "Alle mapping-velden zijn verplicht.", + "last-level-relation-tooltip": "Als geselecteerd, zoekt de regel‑node gerelateerde entiteiten alleen op het niveau dat is ingesteld in de parameter 'max relation level'.", + "last-level-device-relation-tooltip": "Als geselecteerd, zoekt de regel‑node gerelateerde apparaten alleen op het niveau dat is ingesteld in de parameter 'max relation level'.", + "data-to-fetch": "Op te halen gegevens", + "mapping-of-customers": "Mapping van klanten", + "map-fields-required": "Alle mapping‑velden zijn verplicht.", "attributes": "Attributen", - "related-device-attributes": "Gerelateerde apparaat attributen", - "add-selected-attributes-to": "Voeg geselecteerde attributen toe aan", + "related-device-attributes": "Gerelateerde apparaatattributen", + "add-selected-attributes-to": "Geselecteerde attributen toevoegen aan", "device-profiles": "Apparaatprofielen", - "mapping-of-tenant": "Mapping van huurder", + "mapping-of-tenant": "Mapping van tenant", "add-attribute-key": "Attribuutsleutel toevoegen", "message-template": "Berichtsjabloon", "message-template-required": "Berichtsjabloon is verplicht", - "use-system-slack-settings": "Gebruik systeem Slack-instellingen", - "slack-api-token": "Slack API-token", - "slack-api-token-required": "Slack API-token is verplicht", + "use-system-slack-settings": "Systeem‑Slack‑instellingen gebruiken", + "slack-api-token": "Slack API‑token", + "slack-api-token-required": "Slack API‑token is verplicht", "keys-mapping": "Sleutelmapping", - "add-key": "Sleutel toevoegen", + "add-key": "Voeg sleutel toe", "recipients": "Ontvangers", - "message-subject-and-content": "Onderwerp en inhoud van bericht", - "template-rules-hint": "Gebruik $[messageKey] of ${metadataKey} om waarden te extraheren.", - "originator-customer-desc": "Gebruik klant van oorspronkelijke bron als nieuwe bron.", - "originator-tenant-desc": "Gebruik huidige huurder als nieuwe bron.", - "originator-related-entity-desc": "Gebruik gerelateerde entiteit als nieuwe bron.", - "originator-alarm-originator-desc": "Gebruik alarmbron als nieuwe bron.", - "originator-entity-by-name-pattern-desc": "Zoek entiteit op naam en gebruik als nieuwe bron.", - "email-from-template-hint": "Gebruik $[messageKey] of ${metadataKey} om waarden op te halen.", - "recipients-block-main-hint": "Komma-gescheiden lijst, ondersteunt templates.", - "forward-msg-default-rule-chain": "Stuur bericht naar standaard regelketen van bron", - "forward-msg-default-rule-chain-tooltip": "Gebruikt standaard of geconfigureerde regelketen van bron.", - "exclude-zero-deltas": "Negeer nulverschillen", - "exclude-zero-deltas-hint": "Voegt sleutel toe aan bericht indien waarde niet nul is.", - "exclude-zero-deltas-time-difference-hint": "Voegt alleen toe als waarde niet nul is.", - "search-direction-from": "Van bron naar doelentiteit", - "search-direction-to": "Van doelentiteit naar bron", - "del-relation-direction-from": "Van bron", - "del-relation-direction-to": "Naar bron", + "message-subject-and-content": "Onderwerp en inhoud bericht", + "template-rules-hint": "Beide invoervelden ondersteunen templatisering. Gebruik $[messageKey] om een waarde uit het bericht te halen en ${metadataKey} om een waarde uit de metadata te halen.", + "originator-customer-desc": "Gebruik klant van de binnenkomende bericht‑afzender als nieuwe afzender.", + "originator-tenant-desc": "Gebruik huidige tenant als nieuwe afzender.", + "originator-related-entity-desc": "Gebruik de gerelateerde entiteit als nieuwe afzender. Lookup op basis van geconfigureerd relatietype en richting.", + "originator-alarm-originator-desc": "Gebruik de alarm‑afzender als nieuwe afzender. Alleen indien de binnenkomende bericht‑afzender een alarm‑entiteit is.", + "originator-entity-by-name-pattern-desc": "Gebruik entiteit opgehaald uit DB als nieuwe afzender. Lookup op basis van entiteitstype en opgegeven naam‑patroon.", + "email-from-template-hint": "Gebruik $[messageKey] om een waarde uit het bericht te halen en ${metadataKey} om een waarde uit de metadata te halen.", + "recipients-block-main-hint": "Komma‑gescheiden adressenlijst. Alle invoervelden ondersteunen templatisering. Gebruik $[messageKey] voor waarde uit het bericht en ${metadataKey} voor waarde uit de metadata.", + "forward-msg-default-rule-chain": "Stuur bericht door naar de standaard regelketen van de afzender", + "forward-msg-default-rule-chain-tooltip": "Indien ingeschakeld wordt het bericht doorgestuurd naar de standaard regelketen van de afzender, of naar de regelketen uit de configuratie. Als de afzender geen standaard regelketen heeft gedefinieerd in het entiteitprofiel.", + "exclude-zero-deltas": "Sluit nul‑delta’s uit van het uitgaande bericht", + "exclude-zero-deltas-hint": "Indien ingeschakeld zal de output‑sleutel \"{{outputValueKey}}\" aan het uitgaande bericht worden toegevoegd **als** de waarde **niet** nul is.", + "exclude-zero-deltas-time-difference-hint": "Indien ingeschakeld zullen de output‑sleutels \"{{outputValueKey}}\" en \"{{periodValueKey}}\" alleen aan het uitgaande bericht worden toegevoegd **als** de waarde van \"{{outputValueKey}}\" niet nul is.", + "search-direction-from": "Van afzender naar doel‑entiteit", + "search-direction-to": "Van doel‑entiteit naar afzender", + "del-relation-direction-from": "Van afzender", + "del-relation-direction-to": "Naar afzender", "target-entity": "Doelentiteit", - "function-configuration": "Functieconfiguratie", + "function-configuration": "Functie‑configuratie", "function-name": "Functienaam", "function-name-required": "Functienaam is verplicht.", "qualifier": "Kwalificatie", @@ -5304,6 +5453,37 @@ "html-text-description": "Gebruik HTML-tags voor opmaak, links en afbeeldingen.", "dynamic-text-description": "Gebruik dynamisch platte tekst of HTML via sjabloon.", "after-template-evaluation-hint": "Na sjabloonevaluatie: true voor HTML, false voor platte tekst." + }, + "ai": { + "ai-model": "AI‑model", + "model": "Model", + "ai-model-hint": "Selecteer het vooraf geconfigureerde AI‑model voor verwerking van verzoeken door deze regel‑node, of gebruik \"Create new\" om een nieuw model te configureren.", + "prompt-settings": "Prompt‑instellingen", + "prompt-settings-hint": "De optionele system prompt bepaalt de algemene rol en beperkingen van de AI, terwijl de user prompt de specifieke taak beschrijft. Beide velden ondersteunen ook templatisering.", + "system-prompt": "System prompt", + "system-prompt-max-length": "System prompt mag maximaal 500000 tekens bevatten.", + "system-prompt-blank": "System prompt mag niet leeg zijn.", + "user-prompt": "User prompt", + "user-prompt-required": "User prompt is verplicht.", + "user-prompt-max-length": "User prompt mag maximaal 500000 tekens bevatten.", + "user-prompt-blank": "User prompt mag niet leeg zijn.", + "response-format": "Antwoordformaat", + "response-text": "Tekst", + "response-json": "JSON", + "response-json-schema": "JSON‑schema", + "response-format-hint-TEXT": "Staat het model toe willekeurige tekst te genereren, wat **niet** per se een geldig JSON‑object hoeft te zijn. Indien dit geen geldig JSON‑object is, wordt het automatisch ingepakt in een JSON‑object onder de sleutel \"response\".", + "response-format-hint-JSON": "Het model moet een geldig JSON‑object genereren. Indien dit geen geldig JSON‑object is, wordt het automatisch ingepakt in een JSON‑object onder de sleutel \"response\".", + "response-format-hint-JSON_SCHEMA": "Het model moet een JSON genereren die overeenkomt met de gespecificeerde structuur en datatypes van het opgegeven schema. Indien dit geen geldig JSON‑object is, wordt het automatisch ingepakt in een JSON‑object onder de sleutel \"response\".", + "response-json-schema-hint": "Hoewel elk geldig JSON‑schema kan worden ingevoerd, ondersteunt deze regel‑node slechts een beperkte subset van de functies. Zie de documentatie van de node voor details.", + "response-json-schema-required": "JSON‑schema is verplicht", + "advanced-settings": "Geavanceerde instellingen", + "timeout": "Timeout", + "timeout-hint": "Maximale tijd om te wachten op een antwoord \nvan het AI‑model voordat het verzoek wordt beëindigd.", + "timeout-required": "Timeout is verplicht", + "timeout-validation": "Moet tussen 1 seconde en 10 minuten zijn.", + "force-acknowledgement": "Verplicht bevestigen", + "force-acknowledgement-hint": "Indien ingeschakeld, wordt het inkomende bericht direct bevestigd. Het ant­woord van het model wordt dan in de wachtrij geplaatst als een afzonderlijk, nieuw bericht.", + "ai-resources": "AI‑resources" } }, "timezone": { @@ -5625,7 +5805,10 @@ "too-small-value-zero": "De waarde moet groter zijn dan 0", "too-small-value-one": "De waarde moet groter zijn dan 1", "queue-size-is-limited-by-system-configuration": "De grootte van de wachtrij is ook beperkt door de systeemconfiguratie.", - "cassandra-tenant-limits-configuration": "Cassandra-query voor tenant", + "cassandra-write-tenant-core-limits-configuration": "Cassandra schrijfqueries via REST API", + "cassandra-read-tenant-core-limits-configuration": "Cassandra leesqueries voor telemetrie via REST API en WS", + "cassandra-write-tenant-rule-engine-limits-configuration": "Cassandra schrijfqueries voor telemetrie via Rule Engine", + "cassandra-read-tenant-rule-engine-limits-configuration": "Cassandra leesqueries voor telemetrie via Rule Engine", "ws-limit-max-sessions-per-tenant": "Maximaal aantal sessies per tenant", "ws-limit-max-sessions-per-customer": "Maximaal aantal sessies per klant", "ws-limit-max-sessions-per-regular-user": "Maximaal aantal sessies per reguliere gebruiker", @@ -5638,27 +5821,30 @@ "ws-limit-updates-per-session": "WS-updates per sessie", "rate-limits": { "add-limit": "Limiet toevoegen", + "and-also-less-than": "en ook minder dan", "advanced-settings": "Geavanceerde instellingen", "edit-limit": "Limiet bewerken", - "but-less-than": "maar minder dan", "calculated-field-debug-event-rate-limit": "Debuggebeurtenissen van berekende velden", - "edit-calculated-field-debug-event-rate-limit": "Bewerk rate-limieten voor debuggebeurtenissen van berekende velden", - "edit-transport-tenant-msg-title": "Bewerk rate-limieten voor tenanttransportberichten", - "edit-transport-tenant-telemetry-msg-title": "Bewerk rate-limieten voor tenanttelemetrieberichten", - "edit-transport-tenant-telemetry-data-points-title": "Bewerk rate-limieten voor tenant telemetriegegevenspunten", - "edit-transport-device-msg-title": "Bewerk rate-limieten voor apparaatberichten", - "edit-transport-device-telemetry-msg-title": "Bewerk rate-limieten voor apparaattelmetrieberichten", - "edit-transport-device-telemetry-data-points-title": "Bewerk rate-limieten voor apparaattelmetriegegevenspunten", - "edit-transport-gateway-msg-title": "Bewerk rate-limieten voor gatewayberichten", - "edit-transport-gateway-telemetry-msg-title": "Bewerk rate-limieten voor gatewaytelemetrieberichten", - "edit-transport-gateway-telemetry-data-points-title": "Bewerk rate-limieten voor gatewaytelemetriegegevenspunten", - "edit-transport-gateway-device-msg-title": "Bewerk rate-limieten voor gatewayapparaatberichten", - "edit-transport-gateway-device-telemetry-msg-title": "Bewerk rate-limieten voor gatewayapparaattelemetrieberichten", - "edit-transport-gateway-device-telemetry-data-points-title": "Bewerk rate-limieten voor gatewayapparaattelemetriegegevenspunten", - "edit-tenant-rest-limits-title": "Bewerk REST-verzoeken voor tenant", - "edit-customer-rest-limits-title": "Bewerk REST-verzoeken voor klant", - "edit-ws-limit-updates-per-session-title": "Bewerk WS-updates per sessie", - "edit-cassandra-tenant-limits-configuration-title": "Bewerk Cassandra-query voor tenant", + "edit-calculated-field-debug-event-rate-limit": "Beperkingen voor debuggebeurtenissen van berekende velden bewerken", + "edit-transport-tenant-msg-title": "Beperkingen voor transporttenantberichten bewerken", + "edit-transport-tenant-telemetry-msg-title": "Beperkingen voor transporttenanttelemetrieberichten bewerken", + "edit-transport-tenant-telemetry-data-points-title": "Beperkingen voor datapoints van transporttenanttelemetrie bewerken", + "edit-transport-device-msg-title": "Beperkingen voor transportapparaatberichten bewerken", + "edit-transport-device-telemetry-msg-title": "Beperkingen voor transportapparaattelemetrieberichten bewerken", + "edit-transport-device-telemetry-data-points-title": "Beperkingen voor datapoints van transportapparaattelemetrie bewerken", + "edit-transport-gateway-msg-title": "Beperkingen voor transportgatewayberichten bewerken", + "edit-transport-gateway-telemetry-msg-title": "Beperkingen voor transportgatewaytelemetrieberichten bewerken", + "edit-transport-gateway-telemetry-data-points-title": "Beperkingen voor datapoints van transportgatewaytelemetrie bewerken", + "edit-transport-gateway-device-msg-title": "Beperkingen voor transportgatewayapparaatberichten bewerken", + "edit-transport-gateway-device-telemetry-msg-title": "Beperkingen voor transportgatewayapparaattelemetrieberichten bewerken", + "edit-transport-gateway-device-telemetry-data-points-title": "Beperkingen voor datapoints van transportgatewayapparaattelemetrie bewerken", + "edit-tenant-rest-limits-title": "Beperkingen voor REST-verzoeken van tenant bewerken", + "edit-customer-rest-limits-title": "Beperkingen voor REST-verzoeken van klant bewerken", + "edit-ws-limit-updates-per-session-title": "Beperkingen voor WS-updates per sessie bewerken", + "edit-cassandra-write-tenant-core-limits-configuration": "Cassandra schrijfqueries voor REST API bewerken", + "edit-cassandra-read-tenant-core-limits-configuration": "Cassandra leesqueries voor REST API en WS-telemetrie bewerken", + "edit-cassandra-write-tenant-rule-engine-limits-configuration": "Cassandra schrijfqueries voor Rule Engine-telemetrie bewerken", + "edit-cassandra-read-tenant-rule-engine-limits-configuration": "Cassandra leesqueries voor Rule Engine-telemetrie bewerken", "edit-tenant-entity-export-rate-limit-title": "Bewerk rate-limieten voor entiteitsversie-aanmaak", "edit-tenant-entity-import-rate-limit-title": "Bewerk rate-limieten voor entiteitsversielading", "edit-tenant-notification-request-rate-limit-title": "Bewerk rate-limieten voor meldingsverzoeken", @@ -5680,6 +5866,7 @@ "per-seconds": "Per seconden", "per-seconds-required": "Tijdslimiet is verplicht.", "per-seconds-min": "Minimale waarde is 1.", + "per-seconds-duplicate": "Dubbele tijdsinterval. Elk tijdsinterval moet uniek zijn.", "rate-limits": "Rate-limieten", "remove-limit": "Limiet verwijderen", "transport-tenant-msg": "Transport tenantberichten", @@ -5769,11 +5956,11 @@ "sec": "{{ sec }} sec", "sec-short": "{{ sec }}s", "short": { - "years": "{ years, plural, =1 {1 jaar } other {# jaren } }", + "years": "{ years, plural, =1 {1 jaar } other {# jaar } }", "days": "{ days, plural, =1 {1 dag } other {# dagen } }", - "hours": "{ hours, plural, =1 {1 uur } other {# uren } }", - "minutes": "{{minutes}} min", - "seconds": "{{seconds}} sec" + "hours": "{ hours, plural, =1 {1 uur } other {# uur } }", + "minutes": "{{minutes}} min ", + "seconds": "{{seconds}} sec " }, "realtime": "Realtime", "history": "Geschiedenis", @@ -5826,38 +6013,152 @@ "label": "Label", "value": "Waarde", "date": "Datum", - "show-date-time-interval": "Toon datum-tijdinterval", - "show-date-time-interval-hint": "Toon datum-tijdinterval volgens de gegevensaggregatie.", + "show-date-time-interval": "Datumtijdinterval weergeven", + "show-date-time-interval-hint": "Toon datumtijdinterval volgens de gegevensaggregatie.", + "hide-zero-tooltip-values": "Verberg nulwaarden", + "show-stack-total": "Totale waarde weergeven in stapelmodus", "background-color": "Achtergrondkleur", "background-blur": "Achtergrondvervaging" }, "unit": { + "set-unit-conversion": "Eenheidsconversie instellen", + "unit-settings": { + "unit-settings": "Eenheidsinstellingen", + "source-unit": "Bron-eenheid", + "source-unit-hint": "Dit is de eenheid van de opgeslagen waarde. De eenheid waarvan je converteert. Voer het symbool in dat je brongegevens gebruiken (bijv. m, km, ft, in).", + "target-metric-unit": "Doel-metrische eenheid", + "target-metric-unit-hint": "Kies in welke metrische eenheid (SI) je de bronwaarde wilt converteren (bijv. cm, mm, km).", + "target-imperial-unit": "Doel-imperiale eenheid", + "target-imperial-unit-hint": "Kies in welke imperiale eenheid je de bronwaarde wilt converteren (bijv. in, ft, yd).", + "target-hybrid-unit": "Doel-hybride eenheid", + "target-hybrid-unit-hint": "Kies in welke hybride eenheid je de bronwaarde wilt converteren (bijv. cm, in, km). Hybride eenheden combineren metrische of imperiale eenheden.", + "enable-unit-conversion": "Eenheidsconversie inschakelen", + "enable-unit-conversion-hint": "Zet aan om conversie te activeren. Wanneer uitgeschakeld, wordt de bronwaarde ongewijzigd doorgegeven. Uitgeschakeld indien er slechts één eenheid bestaat in de betreffende meetgroep (bijv. Lichtstroom, AQI)." + }, + "unit-system": "Eenheidssysteem", + "unit-system-type": { + "AUTO": "Auto", + "METRIC": "Metrisch", + "IMPERIAL": "Imperiaal", + "HYBRID": "Hybride" + }, + "measures": { + "absorbed-dose-rate": "Geabsorbeerde dosis per tijdseenheid", + "acceleration": "Versnelling", + "acidity": "Zuurtegraad", + "air-quality-index": "Luchtkwaliteitsindex", + "amount-of-substance": "Hoeveelheid stof", + "angle": "Hoek", + "angular-acceleration": "Hoeksversnelling", + "area": "Oppervlakte", + "area-density": "Oppervlaktedichtheid", + "capacitance": "Capaciteit", + "catalytic-activity": "Katalytische activiteit", + "catalytic-concentration": "Katalytische concentratie", + "charge": "Lading", + "current-density": "Stroomdichtheid", + "data-transfer-rate": "Gegevensoverdrachtsnelheid", + "density": "Dichtheid", + "digital": "Digitaal", + "dimension-ratio": "Afmetingsverhouding", + "dynamic-viscosity": "Dynamische viscositeit", + "earthquake-magnitude": "Aardbevingskracht", + "electric-charge-density": "Elektrische ladingsdichtheid", + "electric-current": "Elektrische stroom", + "electric-dipole-moment": "Elektrisch dipoolmoment", + "electric-field-strength": "Sterkte van het elektrisch veld", + "electric-flux": "Elektrische flux", + "electric-permittivity": "Elektrische permittiviteit", + "electric-polarizability": "Elektrische polariseerbaarheid", + "electrical-conductance": "Elektrische conductantie", + "electrical-conductivity": "Elektrische geleidbaarheid", + "energy": "Energie", + "energy-density": "Energiedichtheid", + "force": "Kracht", + "frequency": "Frequentie", + "fuel-efficiency": "Brandstofefficiëntie", + "heat-capacity": "Warmtecapaciteit", + "illuminance": "Verlichtingssterkte", + "inductance": "Inductantie", + "kinematic-viscosity": "Kinematische viscositeit", + "length": "Lengte", + "light-exposure": "Lichtblootstelling", + "linear-charge-density": "Lineaire ladingsdichtheid", + "logarithmic-ratio": "Logaritmische verhouding", + "luminous-efficacy": "Lichtopbrengst", + "luminous-flux": "Lichtstroom", + "luminous-intensity": "Lichtsterkte", + "magnetic-field-gradient": "Magnetisch veldgradiënt", + "magnetic-flux": "Magnetische flux", + "magnetic-flux-density": "Magnetische fluxdichtheid", + "magnetic-moment": "Magnetisch moment", + "magnetic-permeability": "Magnetische permeabiliteit", + "mass": "Massa", + "mass-fraction": "Massafractie", + "molar-concentration": "Molconcentratie", + "molar-energy": "Molaire energie", + "molar-heat-capacity": "Molaire warmtecapaciteit", + "molar-mass": "Molmassa", + "number-concentration": "Aantalconcentratie", + "parts-per-million": "Deeltjes per miljoen", + "power": "Vermogen", + "power-density": "Vermogensdichtheid", + "pressure": "Druk", + "radiance": "Stralingsintensiteit", + "radiant-intensity": "Stralingssterkte", + "radiation-dose": "Stralingsdosis", + "radioactive-decay": "Radioactief verval", + "radioactivity": "Radioactiviteit", + "radioactivity-concentration": "Radioactiviteitsconcentratie", + "reciprocal-length": "Reciproque lengte", + "resistance": "Weerstand", + "reynolds-number": "Reynoldsgetal", + "signal-level": "Signaalniveau", + "solid-angle": "Ruimtehoek", + "specific-energy": "Specifieke energie", + "specific-heat-capacity": "Soortelijke warmtecapaciteit", + "specific-humidity": "Specifieke luchtvochtigheid", + "specific-volume": "Specifiek volume", + "speed": "Snelheid", + "surface-charge-density": "Oppervlakteladingsdichtheid", + "surface-tension": "Oppervlaktespanning", + "temperature": "Temperatuur", + "thermal-conductivity": "Thermische geleidbaarheid", + "time": "Tijd", + "torque": "Koppel", + "turbidity": "Troebelheid", + "voltage": "Spanning", + "volume": "Volume", + "volume-flow": "Volumestroom" + }, "millimeter": "Millimeter", "centimeter": "Centimeter", - "angstrom": "Angström", + "decimeter": "Decimeter", + "angstrom": "Ångström", "nanometer": "Nanometer", "micrometer": "Micrometer", "meter": "Meter", "kilometer": "Kilometer", "inch": "Inch", "foot": "Voet", + "foot-us": "Voet (VS-metingsysteem)", "yard": "Yard", "mile": "Mijl", "nautical-mile": "Zeemijl", "astronomical-unit": "Astronomische eenheid", - "reciprocal-metre": "Reciproque meter", + "reciprocal-metre": "Reciproke meter", "meter-per-meter": "Meter per meter", "steradian": "Steradiaal", - "thou": "Duizendste inch", + "thou": "Duizendste inch (Thou)", "barleycorn": "Barleycorn", "hand": "Hand", - "chain": "Ketting", + "chain": "Kettting", "furlong": "Furlong", "league": "League", "fathom": "Vadem", "cable": "Kabel", - "link": "Schakel", - "rod": "Roede", + "link": "Link", + "rod": "Staaf", "nanogram": "Nanogram", "microgram": "Microgram", "milligram": "Milligram", @@ -5887,6 +6188,7 @@ "cubic-foot": "Kubieke voet", "cubic-yard": "Kubieke yard", "fluid-ounce": "Fluid ounce", + "fluid-ounce-per-second": "Fluid ounce per seconde", "pint": "Pint", "quart": "Quart", "gallon": "Gallon", @@ -5905,9 +6207,13 @@ "meter-per-second": "Meter per seconde", "kilometer-per-hour": "Kilometer per uur", "foot-per-second": "Voet per seconde", + "foot-per-minute": "Voet per minuut", "mile-per-hour": "Mijl per uur", "knot": "Knoop", + "inch-per-second": "Inch per seconde", + "inch-per-hour": "Inch per uur", "millimeters-per-minute": "Millimeter per minuut", + "meter-per-minute": "Meter per minuut", "kilometer-per-hour-squared": "Kilometer per uur kwadraat", "foot-per-second-squared": "Voet per seconde kwadraat", "pascal": "Pascal", @@ -5922,8 +6228,9 @@ "foot-pounds": "Voet-pond", "inch-pounds": "Inch-pond", "newton-per-meter": "Newton per meter", - "atmospheres": "Atmospferen", - "pounds-per-square-inch": "Ponden per vierkante inch", + "atmospheres": "Atmosferen", + "pounds-per-square-inch": "Pond per vierkante inch", + "kilopound-per-square-inch": "Kilopond per vierkante inch", "torr": "Torr", "inches-of-mercury": "Inches kwik", "pascal-per-square-meter": "Pascal per vierkante meter", @@ -5941,18 +6248,24 @@ "megajoule": "Megajoule", "gigajoule": "Gigajoule", "watt-hour": "Wattuur", + "watt-minute": "Wattminuut", "kilowatt-hour": "Kilowattuur", + "milliwatt-hour": "Milliwattuur", + "megawatt-hour": "Megawattuur", + "gigawatt-hour": "Gigawattuur", "electron-volts": "Elektronvolt", - "joules-per-coulomb": "Joules per coulomb", + "joules-per-coulomb": "Joule per coulomb", "british-thermal-unit": "Britse thermische eenheid", + "thousand-british-thermal-unit": "Duizend Britse thermische eenheden", + "million-british-thermal-unit": "Miljoen Britse thermische eenheden", "foot-pound": "Voet-pond", "calorie": "Calorie", "small-calorie": "Kleine calorie", "kilocalorie": "Kilocalorie", - "joule-per-kelvin": "Joule per Kelvin", - "joule-per-kilogram-kelvin": "Joule per kilogram-Kelvin", + "joule-per-kelvin": "Joule per kelvin", + "joule-per-kilogram-kelvin": "Joule per kilogram-kelvin", "joule-per-kilogram": "Joule per kilogram", - "watt-per-meter-kelvin": "Watt per meter-Kelvin", + "watt-per-meter-kelvin": "Watt per meter-kelvin", "joule-per-cubic-meter": "Joule per kubieke meter", "therm": "Therm", "electric-dipole-moment": "Elektrisch dipoolmoment", @@ -5965,7 +6278,7 @@ "kilowatt": "Kilowatt", "megawatt": "Megawatt", "gigawatt": "Gigawatt", - "metric-horsepower": "Metrisch paardekracht", + "metric-horsepower": "Metrische paardekracht", "milliwatt-per-square-centimeter": "Milliwatt per vierkante centimeter", "watt-per-square-centimeter": "Watt per vierkante centimeter", "kilowatt-per-square-centimeter": "Kilowatt per vierkante centimeter", @@ -5974,11 +6287,21 @@ "kilowatt-per-square-meter": "Kilowatt per vierkante meter", "watt-per-square-inch": "Watt per vierkante inch", "kilowatt-per-square-inch": "Kilowatt per vierkante inch", - "horsepower": "Paardenkracht", - "btu-per-hour": "BTU per uur", + "horsepower": "Paardekracht", + "btu-per-hour": "Britse thermische eenheden per uur", + "btu-per-second": "Britse thermische eenheden per seconde", + "btu-per-day": "Britse thermische eenheden per dag", + "mbtu-per-hour": "Duizend Britse thermische eenheden per uur", + "mbtu-per-second": "Duizend Britse thermische eenheden per seconde", + "mbtu-per-day": "Duizend Britse thermische eenheden per dag", + "mmbtu-per-hour": "Miljoen Britse thermische eenheden per uur", + "mmbtu-per-second": "Miljoen Britse thermische eenheden per seconde", + "mmbtu-per-day": "Miljoen Britse thermische eenheden per dag", + "foot-pound-per-second": "Voet-pond per seconde", "coulomb": "Coulomb", "millicoulomb": "Millicoulomb", "microcoulomb": "Microcoulomb", + "nanocoulomb": "Nanocoulomb", "picocoulomb": "Picocoulomb", "coulomb-per-meter": "Coulomb per meter", "coulomb-per-cubic-meter": "Coulomb per kubieke meter", @@ -5997,24 +6320,31 @@ "barn": "Barn", "circular-inch": "Circulaire inch", "milliampere-hour": "Milliampère-uur", - "ampere-hours": "Ampère-uren", - "kiloampere-hours": "Kiloampère-uren", + "ampere-hours": "Ampère-uur", + "kiloampere-hours": "Kiloampère-uur", "nanoampere": "Nanoampère", "picoampere": "Picoampère", "microampere": "Microampère", "milliampere": "Milliampère", "ampere": "Ampère", + "kiloampere": "Kiloampère", + "megaampere": "Megaampère", + "gigaampere": "Gigaampère", "microampere-per-square-centimeter": "Microampère per vierkante centimeter", "ampere-per-square-meter": "Ampère per vierkante meter", "ampere-per-meter": "Ampère per meter", "oersted": "Oersted", - "bohr-magneton": "Bohr Magneton", - "ampere-meter-squared": "Ampère-meter in het kwadraat", + "bohr-magneton": "Bohr-magneton", + "ampere-meter-squared": "Ampère-meter kwadraat", "nanovolt": "Nanovolt", "picovolt": "Picovolt", + "millivolt": "Millivolt", + "microvolt": "Microvolt", "volt": "Volt", - "dbmV": "dBmV", - "dbm": "dBm", + "kilovolt": "Kilovolt", + "megavolt": "Megavolt", + "dbmV": "Decibel volt", + "dbm": "Decibel-milliwatt", "volt-meter": "Volt-meter", "kilovolt-meter": "Kilovolt-meter", "megavolt-meter": "Megavolt-meter", @@ -6027,16 +6357,18 @@ "kilohm": "Kilo-ohm", "megohm": "Mega-ohm", "gigohm": "Giga-ohm", + "millihertz": "Millihertz", "hertz": "Hertz", "kilohertz": "Kilohertz", "megahertz": "Megahertz", "gigahertz": "Gigahertz", + "terahertz": "Terahertz", "rpm": "Omwentelingen per minuut", "candela-per-square-meter": "Candela per vierkante meter", "candela": "Candela", "lumen": "Lumen", "lux": "Lux", - "foot-candle": "Voet-candela", + "foot-candle": "Foot-candle", "lumen-per-square-meter": "Lumen per vierkante meter", "lux-second": "Lux-seconde", "lumen-second": "Lumen-seconde", @@ -6047,11 +6379,11 @@ "millimole": "Millimol", "kilomole": "Kilomol", "mole-per-cubic-meter": "Mol per kubieke meter", - "rssi": "RSSI", - "ppm": "Deeltjes per miljoen (ppm)", - "ppb": "Deeltjes per miljard (ppb)", + "rssi": "Ontvangen signaalsterkte-indicator", + "ppm": "Deeltjes per miljoen", + "ppb": "Deeltjes per miljard", "micrograms-per-cubic-meter": "Microgram per kubieke meter", - "aqi": "Luchtkwaliteitsindex (AQI)", + "aqi": "Luchtkwaliteitsindex", "gram-per-cubic-meter": "Gram per kubieke meter", "gram-per-kilogram": "Specifieke vochtigheid", "millimeters-per-second": "Millimeter per seconde", @@ -6064,7 +6396,7 @@ "gray": "Gray", "sievert": "Sievert", "roentgen": "Röntgen", - "cps": "Tellingen per seconde", + "cps": "Tel per seconde", "rad": "Rad", "rem": "Rem", "dps": "Desintegraties per seconde", @@ -6077,7 +6409,7 @@ "gy-per-second": "Gray per seconde", "watt-per-steradian": "Watt per steradiaal", "watt-per-square-metre-steradian": "Watt per vierkante meter-steradiaal", - "ph-level": "pH-waarde", + "ph-level": "pH-niveau", "turbidity": "Troebelheid", "mg-per-liter": "Milligram per liter", "microsiemens-per-centimeter": "Microsiemens per centimeter", @@ -6116,6 +6448,9 @@ "millibars": "Millibar", "inch-of-mercury": "Inch kwik", "richter-scale": "Richterschaal", + "nanosecond": "Nanoseconde", + "microsecond": "Microseconde", + "millisecond": "Milliseco nde", "second": "Seconde", "minute": "Minuut", "hour": "Uur", @@ -6131,6 +6466,7 @@ "gallons-per-minute": "Gallon per minuut", "cubic-foot-per-second": "Kubieke voet per seconde", "milliliters-per-minute": "Milliliter per minuut", + "cubic-decimeter-per-second": "Kubieke decimeter per seconde", "bit": "Bit", "byte": "Byte", "kilobyte": "Kilobyte", @@ -6153,6 +6489,9 @@ "degree": "Graad", "radian": "Radiaal", "gradian": "Gradiënt", + "arcminute": "Boogminuut", + "arcsecond": "Boogseconde", + "milliradian": "Milliradiaal", "revolution": "Omwenteling", "siemens": "Siemens", "millisiemens": "Millisiemens", @@ -6168,7 +6507,7 @@ "kilofarad": "Kilofarad", "megafarad": "Megafarad", "gigafarad": "Gigafarad", - "terfarad": "Terafarad", + "terfarad": "Terfarad", "farad-per-meter": "Farad per meter", "tesla": "Tesla", "gauss": "Gauss", @@ -6184,7 +6523,7 @@ "square-meter-per-second": "Vierkante meter per seconde", "square-centimeter-per-second": "Vierkante centimeter per seconde", "stoke": "Stoke", - "centistokes": "Centistokes", + "centistokes": "Centistoke", "square-foot-per-second": "Vierkante voet per seconde", "square-inch-per-second": "Vierkante inch per seconde", "pascal-second": "Pascal-seconde", @@ -6195,7 +6534,7 @@ "newton-second-per-square-meter": "Newton-seconde per vierkante meter", "dyne-second-per-square-centimeter": "Dyne-seconde per vierkante centimeter", "kilogram-per-meter-second": "Kilogram per meter-seconde", - "tesla-square-meters": "Tesla vierkante meters", + "tesla-square-meters": "Tesla vierkante meter", "maxwell": "Maxwell", "tesla-per-meter": "Tesla per meter", "gauss-per-centimeter": "Gauss per centimeter", @@ -6209,13 +6548,13 @@ "microhenry": "Microhenry", "nanohenry": "Nanohenry", "henry-per-meter": "Henry per meter", - "tesla-meter-per-ampere": "Tesla-meter per ampère", + "tesla-meter-per-ampere": "Tesla meter per ampère", "gauss-per-oersted": "Gauss per oersted", "kilogram-per-mole": "Kilogram per mol", "gram-per-mole": "Gram per mol", "milligram-per-mole": "Milligram per mol", "joule-per-mole": "Joule per mol", - "joule-per-mole-kelvin": "Joule per mol-Kelvin", + "joule-per-mole-kelvin": "Joule per mol-kelvin", "millivolts-per-meter": "Millivolt per meter", "volts-per-meter": "Volt per meter", "kilovolts-per-meter": "Kilovolt per meter", @@ -6223,9 +6562,11 @@ "radian-per-second-squared": "Radiaal per seconde kwadraat", "revolutions-per-minute-per-second": "Hoeksversnelling", "deg-per-second": "Graden per seconde", + "rotation-per-minute": "Rotatie per minuut", "degrees-brix": "Graden Brix", "katal": "Katal", - "katal-per-cubic-metre": "Katal per kubieke meter" + "katal-per-cubic-metre": "Katal per kubieke meter", + "paris-inch": "Parijse inch" }, "user": { "user": "Gebruiker", @@ -6387,17 +6728,17 @@ "no-widgets": "Nog geen widgets", "no-widgets-text": "Geen widgets gevonden", "management": "Widgetbeheer", - "editor": "Widgeteditor", + "editor": "Widget-editor", "confirm-to-exit-editor-html": "U heeft niet-opgeslagen widgetinstellingen.
Weet u zeker dat u deze pagina wilt verlaten?", - "widget-type-not-found": "Probleem bij het laden van widgetconfiguratie.
Mogelijk is het bijbehorende widgettype verwijderd.", - "widget-type-load-error": "Widget kon niet worden geladen vanwege de volgende fouten:", + "widget-type-not-found": "Probleem bij het laden van de widgetconfiguratie.
Waarschijnlijk is het bijbehorende\n widgettype verwijderd.", + "widget-type-load-error": "Widget werd niet geladen vanwege de volgende fouten:", "remove": "Widget verwijderen", "delete": "Widget verwijderen", "edit": "Widget bewerken", "remove-widget-title": "Weet u zeker dat u de widget '{{widgetTitle}}' wilt verwijderen?", - "remove-widget-text": "Na bevestiging worden de widget en alle gerelateerde gegevens onherstelbaar verwijderd.", + "remove-widget-text": "Na bevestiging wordt de widget en alle gerelateerde gegevens onherroepelijk verwijderd.", "replace-reference-with-widget-copy": "Vervang referentie door widgetkopie", - "timeseries": "Tijdreeksen", + "timeseries": "Tijdreeks", "search-data": "Gegevens zoeken", "no-data-found": "Geen gegevens gevonden", "latest": "Laatste waarden", @@ -6673,16 +7014,16 @@ "not-set": "Niet ingesteld", "action-name": "Naam", "action-name-required": "Actienaam is verplicht.", - "action-name-not-unique": "Er bestaat al een andere actie met dezelfde naam.\nActienaam moet uniek zijn binnen dezelfde actiebron.", - "action-icon": "Pictogram", + "action-name-not-unique": "Er bestaat al een andere actie met dezelfde naam.\nDe actienaam moet uniek zijn binnen dezelfde actiebasis.", + "action-icon": "Icoon", "header-button": { "button-settings": "Knopinstellingen", "button-type": "Knoptype", "button-type-basic": "Basis", "button-type-raised": "Verhoogd", - "button-type-stroked": "Omtrokken", + "button-type-stroked": "Omlijnd", "button-type-flat": "Vlak", - "button-type-icon": "Pictogram", + "button-type-icon": "Icoon", "button-type-mini-fab": "FAB", "colors": "Kleuren", "color": "Kleur", @@ -6691,26 +7032,26 @@ "advanced-button-style": "Geavanceerde knopstijl", "button-style": "Knopstijl" }, - "show-hide-action-using-function": "Toon/verberg actie met functie", - "show-action-function": "Toon actiefunctie", + "show-hide-action-using-function": "Toon/verberg actie met behulp van functie", + "show-action-function": "Actie tonen functie", "action-type": "Type", "action-type-required": "Actietype is verplicht.", - "edit-action": "Bewerk actie", - "delete-action": "Verwijder actie", - "delete-action-title": "Verwijder widgetactie", + "edit-action": "Actie bewerken", + "delete-action": "Actie verwijderen", + "delete-action-title": "Widgetactie verwijderen", "delete-action-text": "Weet je zeker dat je de widgetactie met de naam '{{actionName}}' wilt verwijderen?", - "title-icon": "Titelpictogram", - "display-icon": "Toon titelpictogram", - "card-icon": "Kaartpictogram", - "icon": "Pictogram", - "icon-color": "Pictogramkleur", - "icon-size": "Pictogramgrootte", + "title-icon": "Titelicoon", + "display-icon": "Titelicoon weergeven", + "card-icon": "Kaarticoon", + "icon": "Icoon", + "icon-color": "Icoonkleur", + "icon-size": "Icoongrootte", "advanced-settings": "Geavanceerde instellingen", "data-settings": "Gegevensinstellingen", "limits": "Limieten", "no-data-display-message": "Alternatief bericht voor \"Geen gegevens om weer te geven\"", - "data-page-size": "Maximaal aantal entiteiten per gegevensbron", - "settings-component-not-found": "Instellingencomponent niet gevonden voor selector '{{selector}}'", + "data-page-size": "Maximum aantal entiteiten per gegevensbron", + "settings-component-not-found": "Instellingenformuliercomponent niet gevonden voor selector '{{selector}}'", "preview": "Voorbeeld", "set": "Instellen", "set-message": "Bericht instellen", @@ -6748,19 +7089,19 @@ }, "widgets": { "mobile-app-qr-code": { - "configuration-hint": "De configuratie is afhankelijk van de Mobile app QR-code widget in de hoofdinstellingen van het platform", - "get-it-on-google-play": "Download in Google Play", - "download-on-the-app-store": "Download in de App Store" + "configuration-hint": "De configuratie is afhankelijk van de QR-codewidget van de mobiele app in de hoofdinstellingen van het platform", + "get-it-on-google-play": "Downloaden via Google Play", + "download-on-the-app-store": "Downloaden via de App Store" }, "action-button": { "behavior": "Gedrag", "on-click": "Bij klikken", - "on-click-hint": "Actie die wordt geactiveerd wanneer op de knop wordt geklikt", - "first-button-click": "Klik op eerste knop", + "on-click-hint": "Actie geactiveerd wanneer op de knop wordt geklikt", + "first-button-click": "Eerste knopklik", "first-button-click-hint": "Actie bij indrukken van de eerste knop.", - "second-button-click": "Klik op tweede knop", + "second-button-click": "Tweede knopklik", "second-button-click-hint": "Actie bij indrukken van de tweede knop.", - "button-click-hint": "Actie bij klikken op de widget." + "button-click-hint": "Actie bij indrukken van de widget." }, "command-button": { "behavior": "Gedrag", @@ -7288,18 +7629,18 @@ "gateway": { "general-settings": "Algemene instellingen", "widget-title": "Widgettitel", - "default-archive-file-name": "Standaard naam archiefbestand", - "device-type-for-new-gateway": "Type apparaat voor nieuwe gateway", + "default-archive-file-name": "Standaard bestandsnaam voor archief", + "device-type-for-new-gateway": "Apparaattype voor nieuwe gateway", "messages-settings": "Berichtinstellingen", - "save-config-success-message": "Bericht bij succesvol opslaan van gatewayconfiguratie", - "device-name-exists-message": "Bericht wanneer apparaatnaam al bestaat", + "save-config-success-message": "Tekstbericht over succesvol opgeslagen gatewayconfiguratie", + "device-name-exists-message": "Tekstbericht wanneer apparaat met ingevoerde naam al bestaat", "gateway-title": "Gatewayformulier", "read-only": "Alleen-lezen", - "events-title": "Titel gatewaygebeurtenissenformulier", - "events-filter": "Filter gebeurtenissen", + "events-title": "Titel van gatewaygebeurtenissenformulier", + "events-filter": "Gebeurtenissenfilter", "event-key-contains": "Gebeurtenissleutel bevat...", "show-connector": "Tonen voor de connector", - "connector-state-param-key": "Sleutel statusparameter connector", + "connector-state-param-key": "Connectortoestand parameter sleutel", "message": "Bericht", "level": "Niveau", "created-time": "Aangemaakt op" @@ -7505,26 +7846,26 @@ "max-value-error": "Maximale waarde is {{value}}", "not-allowed-entity": "Geselecteerde entiteit kan geen gedeelde attributen hebben", "no-attribute-selected": "Geen attribuut geselecteerd", - "no-datakey-selected": "Geen datatoets geselecteerd", - "no-coordinate-specified": "Datatoets voor breedte-/lengtegraad niet opgegeven", + "no-datakey-selected": "Geen gegevenssleutel geselecteerd", + "no-coordinate-specified": "Gegevenssleutel voor breedtegraad/lengtegraad is niet opgegeven", "no-entity-selected": "Geen entiteit geselecteerd", "no-image": "Geen afbeelding", - "no-support-geolocation": "Je browser ondersteunt geen geolocatie", - "no-support-web-camera": "Je browser ondersteunt geen camera’s", - "enable-https-use-widget": "Activeer HTTPS om deze widget te gebruiken", - "no-found-your-camera": "Kan je camera niet vinden", - "no-permission-camera": "Toestemming geweigerd of geen toegang tot camera", + "no-support-geolocation": "Uw browser ondersteunt geen geolocatie", + "no-support-web-camera": "Uw browser ondersteunt geen camera's", + "enable-https-use-widget": "Schakel HTTPS in om deze widget te gebruiken", + "no-found-your-camera": "Kan uw camera niet vinden", + "no-permission-camera": "Toegang geweigerd door gebruiker / Deze site heeft geen toestemming om de camera te gebruiken", "no-timeseries-selected": "Geen tijdreeks geselecteerd", "secret-key": "Geheime sleutel", - "secret-key-required": "Geheime sleutel is verplicht", - "switch-attribute-value": "Schakel attribuutwaarde van entiteit", + "secret-key-required": "Geheime sleutel is vereist", + "switch-attribute-value": "Wijzig waarde van entiteitsattribuut", "switch-camera": "Schakel camera", - "switch-timeseries-value": "Schakel tijdreekswaarde van entiteit", - "take-photo": "Foto maken", + "switch-timeseries-value": "Wijzig waarde van entiteitstijdreeks", + "take-photo": "Maak foto", "time": "Tijd", "timeseries-not-allowed": "Tijdreeksparameter mag niet worden gebruikt in deze widget", - "update-failed": "Update mislukt", - "update-successful": "Update succesvol", + "update-failed": "Bijwerken mislukt", + "update-successful": "Bijwerken geslaagd", "update-attribute": "Attribuut bijwerken", "update-timeseries": "Tijdreeks bijwerken", "value": "Waarde", @@ -7592,47 +7933,47 @@ "image-format-jpeg": "JPEG", "image-format-png": "PNG", "image-format-webp": "WEBP", - "image-quality": "Afbeeldingskwaliteit voor verliescompressie (zoals jpeg/webp)", + "image-quality": "Afbeeldingskwaliteit voor formaten met verliescompressie zoals JPEG en WEBP", "max-image-width": "Maximale afbeeldingsbreedte", "max-image-height": "Maximale afbeeldingshoogte", "action-buttons": "Actieknoppen", "show-action-buttons": "Toon actieknoppen", - "update-all-values": "Alle waarden bijwerken, niet alleen gewijzigde", - "save-button-label": "Label voor 'OPSLAAN'-knop", - "reset-button-label": "Label voor 'ONGEDAAAN MAKEN'-knop", + "update-all-values": "Werk alle waarden bij, niet alleen gewijzigde", + "save-button-label": "Label van de knop 'OPSLAAN'", + "reset-button-label": "Label van de knop 'ONGED. MAKEN'", "group-settings": "Groepsinstellingen", - "show-group-title": "Toon titel voor groep van velden", + "show-group-title": "Toon titel voor groep van velden die bij verschillende entiteiten horen", "group-title": "Groepstitel", - "fields-alignment": "Velduitlijning", + "fields-alignment": "Uitlijning van velden", "fields-alignment-row": "Rij (standaard)", "fields-alignment-column": "Kolom", - "fields-in-row": "Aantal velden per rij", - "option-value": "Waarde (schrijf 'null' voor lege optie)", + "fields-in-row": "Aantal velden in de rij", + "option-value": "Waarde (schrijf 'null' om lege optie te maken)", "option-label": "Label", "hide-input-field": "Verberg invoerveld", - "datakey-type": "Type datatoets", + "datakey-type": "Type gegevenssleutel", "datakey-type-server": "Serverattribuut (standaard)", "datakey-type-shared": "Gedeeld attribuut", "datakey-type-timeseries": "Tijdreeks", - "datakey-value-type": "Datatoets waarde type", + "datakey-value-type": "Waarde type van gegevenssleutel", "datakey-value-type-string": "Tekenreeks", - "datakey-value-type-double": "Decimaal", + "datakey-value-type-double": "Double", "datakey-value-type-integer": "Geheel getal", "datakey-value-type-json": "JSON", - "datakey-value-type-boolean-checkbox": "Boolean (Selectievakje)", - "datakey-value-type-boolean-switch": "Boolean (Schakelaar)", - "datakey-value-type-date-time": "Datum & Tijd", + "datakey-value-type-boolean-checkbox": "Boolean (selectievakje)", + "datakey-value-type-boolean-switch": "Boolean (schakelaar)", + "datakey-value-type-date-time": "Datum en tijd", "datakey-value-type-date": "Datum", "datakey-value-type-time": "Tijd", - "datakey-value-type-select": "Keuzelijst", + "datakey-value-type-select": "Selecteer", "datakey-value-type-radio": "Radio", "datakey-value-type-color": "Kleur", "value-is-required": "Waarde is verplicht", - "ability-to-edit-attribute": "Mogelijkheid om attribuut te bewerken", + "ability-to-edit-attribute": "Bewerkbaarheid van attribuut", "ability-to-edit-attribute-editable": "Bewerkbaar (standaard)", "ability-to-edit-attribute-disabled": "Uitgeschakeld", "ability-to-edit-attribute-readonly": "Alleen-lezen", - "disable-on-datakey-name": "Uitschakelen bij false-waarde van andere datatoets (geef naam op)", + "disable-on-datakey-name": "Uitschakelen bij waarde 'false' van andere gegevenssleutel (geef naam op)", "field-appearance": "Veldweergave", "appearance-fill": "Opvulling", "appearance-outline": "Omlijning", @@ -7775,6 +8116,18 @@ "fill-area-opacity": "Opaciteit van het gevulde gebied", "range-chart-style": "Stijl van bereikgrafiek" }, + "knob": { + "behavior": "Gedrag", + "initial-value": "Initiële waarde", + "initial-value-hint": "Actie om de initiële waarde van de knop op te halen.", + "on-value-change": "Bij waarde wijziging", + "on-value-change-hint": "Actie die wordt uitgevoerd wanneer de waarde van de knop verandert.", + "range": "Bereik", + "min": "min", + "max": "max", + "value": "Waarde", + "fallback-initial-value": "Terugval initiële waarde" + }, "rpc": { "value-settings": "Waardesinstellingen", "initial-value": "Initiële waarde", @@ -7831,9 +8184,7 @@ "led-status-value-timeseries": "Tijdreeks met LED-statuswaarde", "check-status-method": "RPC-methode voor statuscontrole", "parse-led-status-value-function": "LED-statuswaarde parsing functie", - "knob-title": "Knoptitel", - "min-value": "Minimale waarde", - "max-value": "Maximale waarde" + "knob-title": "Knoptitel" }, "maps": { "map-type": { @@ -8011,10 +8362,10 @@ "action-move": "Verplaatsen", "action-remove": "Verwijderen", "edit-instruments": "Instrumenten", - "persist-location-attribute-scope": "Reikwijdte van attribuut om locatie op te slaan", - "enable-snapping": "Uitlijnen met andere punten inschakelen", - "enable-snapping-hint": "Lijnt automatisch nieuwe punten uit met bestaande vormen om tekenen eenvoudiger en nauwkeuriger te maken.", - "drag-drop-mode": "Sleepmodus", + "persist-location-attribute-scope": "Bereik van het attribuut om locatie op te slaan", + "enable-snapping": "Snapping naar andere hoekpunten inschakelen voor nauwkeurig tekenen", + "enable-snapping-hint": "Lijnt automatisch nieuwe punten uit met bestaande vormen voor eenvoudiger en nauwkeuriger tekenen.", + "drag-drop-mode": "Slepen-en-neerzetten-modus", "trip": { "no-trips": "Geen reizen geconfigureerd", "add-trip": "Reis toevoegen", @@ -8563,17 +8914,17 @@ "counter-value": "Waarde", "counter-color": "Kleur", "notification-button": "Meldingsknoppen", - "button-view-all": "Bekijk alles", + "button-view-all": "Alles bekijken", "button-filter": "Filter", "type-filter": "Typefilter", - "button-mark-read": "Markeer alles als gelezen", - "notification-types": "Meldingstypes", + "button-mark-read": "Alles als gelezen markeren", + "notification-types": "Meldingstypen", "notification-type": "Meldingstype", "search-type": "Zoektype", "any-type": "Elk type" }, "alarm-count": { - "alarm-count-card-style": "Stijl van alarmtellerkaart" + "alarm-count-card-style": "Stijl van de alarmtellerkaart" }, "entity-count": { "entity-count-card-style": "Stijl van entiteittellerkaart" @@ -8677,18 +9028,22 @@ "pie-chart-card-style": "Stijl van cirkeldiagramkaart" }, "radar-chart": { - "radar-appearance": "Uiterlijk van radardiagram", + "radar-appearance": "Radarweergave", "shape": "Vorm", - "shape-polygon": "Veelhoek", + "shape-polygon": "Polygoon", "shape-circle": "Cirkel", "color": "Kleur", "line": "Lijn", "points": "Punten", - "points-label": "Puntlabel", - "radar-axis": "Radar-as", + "points-label": "Puntenlabel", + "radar-axis": "Radaras", "axis-label": "Aslabel", - "ticks-label": "Label van streepjes", - "radar-chart-style": "Stijl van radardiagram" + "ticks-label": "Ticks-label", + "radar-chart-style": "Radarstijl", + "max-axes-scaling": "Maximale asschaling", + "max-axes-scaling-hint": "Kies of elke radarias zijn eigen maximumwaarde heeft (Gescheiden) of dat alle assen dezelfde hoogste waarde delen op basis van de widgetdataset (Gemeenschappelijk).", + "separate": "Gescheiden", + "common": "Gemeenschappelijk" }, "time-series-chart": { "chart": "Diagram", @@ -8965,12 +9320,12 @@ "cpu": "CPU", "ram": "RAM", "disk": "Schijf", - "cpu-warning-text": "Hoge CPU-belasting. Optimaliseer de systeemprestaties om systeemfouten te voorkomen.", - "cpu-critical-text": "Kritieke CPU-belasting. Optimaliseer de systeemprestaties om systeemfouten te voorkomen.", - "ram-warning-text": "Weinig RAM beschikbaar. Optimaliseer de systeemprestaties of verhoog de RAM om systeemfouten te voorkomen.", - "ram-critical-text": "Kritiek laag RAM-geheugen. Optimaliseer de systeemprestaties of verhoog de RAM om systeemfouten te voorkomen.", - "disk-warning-text": "Weinig schijfruimte beschikbaar. Maak ruimte vrij of breid de schijfruimte uit om dataverlies te voorkomen.", - "disk-critical-text": "Kritiek weinig schijfruimte beschikbaar. Maak ruimte vrij of breid de schijfruimte uit om dataverlies te voorkomen." + "cpu-warning-text": "Hoge CPU-belasting. Optimaliseer de systeemprestaties om storingen te voorkomen.", + "cpu-critical-text": "Kritieke CPU-belasting. Optimaliseer de systeemprestaties om storingen te voorkomen.", + "ram-warning-text": "Weinig RAM beschikbaar. Verhoog RAM of optimaliseer prestaties om storingen te voorkomen.", + "ram-critical-text": "Kritiek tekort aan RAM. Verhoog RAM of optimaliseer prestaties om storingen te voorkomen.", + "disk-warning-text": "Weinig schijfruimte beschikbaar. Maak ruimte vrij of vergroot de opslagcapaciteit om dataverlies te voorkomen.", + "disk-critical-text": "Kritieke schijfruimte. Maak ruimte vrij of vergroot de opslagcapaciteit om dataverlies te voorkomen." }, "cluster-info": { "service-id": "Service-ID", @@ -9194,4 +9549,4 @@ "language": { "language": "Taal" } -} +} \ No newline at end of file diff --git a/ui-ngx/yarn.lock b/ui-ngx/yarn.lock index dc79929cc8..56dc0f47a5 100644 --- a/ui-ngx/yarn.lock +++ b/ui-ngx/yarn.lock @@ -5604,11 +5604,6 @@ fs-minipass@^3.0.0: dependencies: minipass "^7.0.3" -fs.realpath@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" - integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== - fsevents@^2.3.2, fsevents@~2.3.2, fsevents@~2.3.3: version "2.3.3" resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" @@ -5738,10 +5733,10 @@ glob-to-regexp@^0.4.1: resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz#c75297087c851b9a578bd217dd59a92f59fe546e" integrity sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw== -glob@^10.2.2, glob@^10.3.10, glob@^10.3.3, glob@^10.3.7: - version "10.4.5" - resolved "https://registry.yarnpkg.com/glob/-/glob-10.4.5.tgz#f4d9f0b90ffdbab09c9d77f5f29b4262517b0956" - integrity sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg== +glob@10.5.0, glob@^10.2.2, glob@^10.3.10, glob@^10.3.3, glob@^10.3.7, glob@^7.1.3: + version "10.5.0" + resolved "https://registry.yarnpkg.com/glob/-/glob-10.5.0.tgz#8ec0355919cd3338c28428a23d4f24ecc5fe738c" + integrity sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg== dependencies: foreground-child "^3.1.0" jackspeak "^3.1.2" @@ -5750,18 +5745,6 @@ glob@^10.2.2, glob@^10.3.10, glob@^10.3.3, glob@^10.3.7: package-json-from-dist "^1.0.0" path-scurry "^1.11.1" -glob@^7.1.3: - version "7.2.3" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" - integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== - dependencies: - fs.realpath "^1.0.0" - inflight "^1.0.4" - inherits "2" - minimatch "^3.1.1" - once "^1.3.0" - path-is-absolute "^1.0.0" - global-prefix@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/global-prefix/-/global-prefix-4.0.0.tgz#e9cc79aab9be1d03287e156a3f912dd0895463ed" @@ -6104,24 +6087,16 @@ indent-string@^4.0.0: resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-4.0.0.tgz#624f8f4497d619b2d9768531d58f4122854d7251" integrity sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg== -inflight@^1.0.4: - version "1.0.6" - resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" - integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== - dependencies: - once "^1.3.0" - wrappy "1" - -inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.3: - version "2.0.4" - resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" - integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== - inherits@2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" integrity sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw== +inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.3: + version "2.0.4" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + ini@4.1.3, ini@^4.1.3: version "4.1.3" resolved "https://registry.yarnpkg.com/ini/-/ini-4.1.3.tgz#4c359675a6071a46985eb39b14e4a2c0ec98a795" @@ -7170,7 +7145,7 @@ minimatch@9.0.1: dependencies: brace-expansion "^2.0.1" -minimatch@^3.1.1, minimatch@^3.1.2: +minimatch@^3.1.2: version "3.1.2" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== @@ -7493,10 +7468,10 @@ node-fetch@^3.3.2: fetch-blob "^3.1.4" formdata-polyfill "^4.0.10" -node-forge@^1: - version "1.3.1" - resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-1.3.1.tgz#be8da2af243b2417d5f646a770663a92b7e9ded3" - integrity sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA== +node-forge@1.3.3, node-forge@^1: + version "1.3.3" + resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-1.3.3.tgz#0ad80f6333b3a0045e827ac20b7f735f93716751" + integrity sha512-rLvcdSyRCyouf6jcOIPe/BgwG/d7hKjzMKOas33/pHEr6gbq18IK9zV7DiPvzsz0oBJPme6qr6H6kGZuI9/DZg== node-gyp-build-optional-packages@5.2.2: version "5.2.2" @@ -7711,13 +7686,6 @@ on-headers@~1.0.2: resolved "https://registry.yarnpkg.com/on-headers/-/on-headers-1.0.2.tgz#772b0ae6aaa525c399e489adfad90c403eb3c28f" integrity sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA== -once@^1.3.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" - integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== - dependencies: - wrappy "1" - onetime@^5.1.0, onetime@^5.1.2: version "5.1.2" resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e" @@ -7982,11 +7950,6 @@ path-exists@^5.0.0: resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-5.0.0.tgz#a6aad9489200b21fab31e49cf09277e5116fb9e7" integrity sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ== -path-is-absolute@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" - integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== - path-key@^3.0.0, path-key@^3.1.0: version "3.1.1" resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" @@ -8005,10 +7968,10 @@ path-scurry@^1.11.1: lru-cache "^10.2.0" minipass "^5.0.0 || ^6.0.2 || ^7.0.0" -path-to-regexp@0.1.10: - version "0.1.10" - resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.10.tgz#67e9108c5c0551b9e5326064387de4763c4d5f8b" - integrity sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w== +path-to-regexp@0.1.10, path-to-regexp@0.1.12: + version "0.1.12" + resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.12.tgz#d5e1a12e478a976d432ef3c58d534b9923164bb7" + integrity sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ== path-type@^5.0.0: version "5.0.0" @@ -10079,11 +10042,6 @@ wrap-ansi@^9.0.0: string-width "^7.0.0" strip-ansi "^7.1.0" -wrappy@1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" - integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== - ws@^8.16.0: version "8.18.0" resolved "https://registry.yarnpkg.com/ws/-/ws-8.18.0.tgz#0d7505a6eafe2b0e712d232b42279f53bc289bbc"