From 09fc025e12b15352f18d11484c841897f2007410 Mon Sep 17 00:00:00 2001 From: Ivan Raznatovskyi Date: Tue, 16 Jan 2024 15:39:47 +0200 Subject: [PATCH] Initial commit from another fork --- .github/release.yml | 2 +- .../workflows/check-configuration-files.yml | 2 +- application/pom.xml | 4 +- application/src/main/conf/logback.xml | 2 +- application/src/main/conf/thingsboard.conf | 2 +- .../data/json/demo/dashboards/gateways.json | 1315 ---- .../docker/localhost_warning.md | 3 - .../install}/centos/instructions.md | 24 +- .../install}/docker/instructions.md | 35 +- .../install}/ubuntu/instructions.md | 4 +- .../upgrade/centos/instructions.md | 15 + .../upgrade/docker/instructions.md | 10 + .../upgrade/docker/start_service.md | 23 + .../instructions/upgrade/docker/upgrade_db.md | 61 + .../upgrade/docker/upgrade_preparing.md | 95 + .../instructions/upgrade/start_service.md | 6 + .../upgrade/ubuntu/instructions.md | 15 + .../edge/instructions/upgrade/upgrade_db.md | 8 + .../instructions/upgrade/upgrade_preparing.md | 36 + .../rule_chains/edge_root_rule_chain.json | 8 +- .../system/widget_bundles/air_quality.json | 44 +- .../json/system/widget_bundles/charts.json | 5 +- .../widget_bundles/indoor_environment.json | 3 + .../widget_bundles/industial_widgets.json | 84 + .../widget_bundles/outdoor_environment.json | 3 + .../widget_types/bar_chart_with_labels.json | 30 + .../system/widget_types/battery_level.json | 2 +- .../carbon_monoxide__co__card.json | 37 + ...on_monoxide__co__card_with_background.json | 37 + .../carbon_monoxide__co__chart_card.json | 39 + ...oxide__co__chart_card_with_background.json | 39 + .../json/system/widget_types/doughnut.json | 2 +- .../system/widget_types/efficiency_card.json | 29 + .../efficiency_card_with_background.json | 29 + .../widget_types/efficiency_chart_card.json | 31 + ...efficiency_chart_card_with_background.json | 31 + .../widget_types/efficiency_progress_bar.json | 29 + ...ficiency_progress_bar_with_background.json | 29 + .../widget_types/efficiency_range_chart.json | 32 + ...fficiency_range_chart_with_background.json | 32 + .../system/widget_types/flow_rate_card.json | 32 + .../flow_rate_card_with_background.json | 32 + .../widget_types/flow_rate_chart_card.json | 34 + .../flow_rate_chart_card_with_background.json | 34 + .../system/widget_types/flow_rate_gauge.json | 33 + .../widget_types/flow_rate_progress_bar.json | 32 + ...low_rate_progress_bar_with_background.json | 32 + .../widget_types/flow_rate_range_chart.json | 35 + ...flow_rate_range_chart_with_background.json | 35 + .../widget_types/fluid_pressure_card.json | 34 + .../fluid_pressure_card_with_background.json | 34 + .../fluid_pressure_chart_card.json | 36 + ...d_pressure_chart_card_with_background.json | 36 + .../widget_types/fluid_pressure_gauge.json | 35 + .../fluid_pressure_progress_bar.json | 34 + ...pressure_progress_bar_with_background.json | 34 + .../fluid_pressure_range_chart.json | 37 + ..._pressure_range_chart_with_background.json | 37 + .../horizontal_carbon_monoxide__co__card.json | 37 + ...on_monoxide__co__card_with_background.json | 37 + .../widget_types/horizontal_doughnut.json | 2 +- .../horizontal_efficiency_card.json | 29 + ...ontal_efficiency_card_with_background.json | 29 + .../horizontal_flow_rate_card.json | 32 + ...zontal_flow_rate_card_with_background.json | 32 + .../horizontal_fluid_pressure_card.json | 34 + ...l_fluid_pressure_card_with_background.json | 34 + ...l_individual_allergy_index__iai__card.json | 32 + ...ergy_index__iai__card_with_background.json | 32 + ...orizontal_nitrogen_dioxide__no2__card.json | 36 + ...en_dioxide__no2__card_with_background.json | 37 + .../horizontal_ozone__o3__card.json | 37 + ...ontal_ozone__o3__card_with_background.json | 37 + .../horizontal_power_consumption_card.json | 32 + ...ower_consumption_card_with_background.json | 32 + .../horizontal_pump_vibration_card.json | 33 + ...l_pump_vibration_card_with_background.json | 33 + .../horizontal_rotational_speed_card.json | 30 + ...rotational_speed_card_with_background.json | 30 + .../horizontal_sulfur_dioxide__so2__card.json | 38 + ...ur_dioxide__so2__card_with_background.json | 38 + .../json/system/widget_types/image_map.json | 2 +- .../individual_allergy_index__iai__card.json | 24 + ...ergy_index__iai__card_with_background.json | 24 + ...vidual_allergy_index__iai__chart_card.json | 34 + ...ndex__iai__chart_card_with_background.json | 34 + .../indoor_temperature_gauge.json | 29 + .../indoor_temperature_range_chart.json | 31 + ...mperature_range_chart_with_background.json | 31 + .../system/widget_types/label_widget.json | 2 +- .../markers_placement___image_map.json | 2 +- .../nitrogen_dioxide__no2__card.json | 37 + ...en_dioxide__no2__card_with_background.json | 37 + .../nitrogen_dioxide__no2__chart_card.json | 39 + ...xide__no2__chart_card_with_background.json | 39 + .../system/widget_types/ozone__o3__card.json | 37 + .../ozone__o3__card_with_background.json | 37 + .../widget_types/ozone__o3__chart_card.json | 39 + ...ozone__o3__chart_card_with_background.json | 39 + .../widget_types/power_consumption_card.json | 32 + ...ower_consumption_card_with_background.json | 32 + .../power_consumption_chart_card.json | 34 + ...onsumption_chart_card_with_background.json | 34 + .../power_consumption_range_chart.json | 35 + ...nsumption_range_chart_with_background.json | 35 + .../widget_types/pump_vibration_card.json | 33 + .../pump_vibration_card_with_background.json | 33 + .../pump_vibration_chart_card.json | 35 + ..._vibration_chart_card_with_background.json | 35 + .../pump_vibration_range_chart.json | 36 + ...vibration_range_chart_with_background.json | 36 + .../json/system/widget_types/range_chart.json | 31 + .../widget_types/rotational_speed_card.json | 30 + ...rotational_speed_card_with_background.json | 30 + .../rotational_speed_chart_card.json | 32 + ...onal_speed_chart_card_with_background.json | 32 + .../widget_types/rotational_speed_gauge.json | 31 + .../rotational_speed_progress_bar.json | 30 + ...al_speed_progress_bar_with_background.json | 30 + .../rotational_speed_range_chart.json | 33 + ...nal_speed_range_chart_with_background.json | 33 + ...imple_carbon_monoxide__co__chart_card.json | 40 + ...oxide__co__chart_card_with_background.json | 40 + .../simple_efficiency_chart_card.json | 32 + ...efficiency_chart_card_with_background.json | 32 + .../simple_flow_rate_chart_card.json | 35 + ..._flow_rate_chart_card_with_background.json | 35 + .../simple_fluid_pressure_chart_card.json | 37 + ...d_pressure_chart_card_with_background.json | 37 + ...vidual_allergy_index__iai__chart_card.json | 35 + ...ndex__iai__chart_card_with_background.json | 35 + ...ple_nitrogen_dioxide__no2__chart_card.json | 40 + ...xide__no2__chart_card_with_background.json | 40 + .../simple_ozone__o3__chart_card.json | 40 + ...ozone__o3__chart_card_with_background.json | 40 + .../simple_power_consumption_chart_card.json | 35 + ...onsumption_chart_card_with_background.json | 35 + .../simple_pump_vibration_chart_card.json | 36 + ..._vibration_chart_card_with_background.json | 36 + .../simple_rotational_speed_chart_card.json | 33 + ...onal_speed_chart_card_with_background.json | 33 + ...imple_sulfur_dioxide__so2__chart_card.json | 40 + ...xide__so2__chart_card_with_background.json | 40 + .../json/system/widget_types/speed_gauge.json | 3 +- .../sulfur_dioxide__so2__card.json | 37 + ...ur_dioxide__so2__card_with_background.json | 37 + .../sulfur_dioxide__so2__chart_card.json | 39 + ...xide__so2__chart_card_with_background.json | 39 + .../widget_types/temperature_gauge.json | 29 + .../temperature_radial_gauge.json | 3 +- .../widget_types/temperature_range_chart.json | 31 + ...mperature_range_chart_with_background.json | 31 + .../widget_types/thermometer_scale.json | 2 +- .../update_location_timeseries.json | 2 +- .../update_server_location_attribute.json | 2 +- .../update_shared_location_attribute.json | 2 +- .../dashboards/gateways.json} | 175 +- .../device_profile/rule_chain_template.json | 8 +- .../tenant/rule_chains/root_rule_chain.json | 8 +- .../main/data/upgrade/1.3.0/schema_update.cql | 2 +- .../main/data/upgrade/1.3.1/schema_update.sql | 2 +- .../main/data/upgrade/1.4.0/schema_update.cql | 2 +- .../main/data/upgrade/1.4.0/schema_update.sql | 2 +- .../main/data/upgrade/2.0.0/schema_update.cql | 2 +- .../main/data/upgrade/2.0.0/schema_update.sql | 2 +- .../main/data/upgrade/2.1.1/schema_update.cql | 2 +- .../main/data/upgrade/2.1.1/schema_update.sql | 2 +- .../main/data/upgrade/2.1.2/schema_update.cql | 2 +- .../main/data/upgrade/2.1.2/schema_update.sql | 2 +- .../main/data/upgrade/2.2.0/schema_update.sql | 2 +- .../main/data/upgrade/2.3.1/schema_update.sql | 2 +- .../main/data/upgrade/2.4.0/schema_update.sql | 2 +- .../main/data/upgrade/2.4.2/schema_update.sql | 2 +- .../schema_update_psql_drop_partitions.sql | 2 +- .../upgrade/2.4.3/schema_update_psql_ts.sql | 2 +- .../2.4.3/schema_update_timescale_ts.sql | 2 +- .../data/upgrade/2.4.3/schema_update_ttl.sql | 2 +- .../data/upgrade/3.0.1/schema_ts_latest.sql | 2 +- .../upgrade/3.0.1/schema_update_to_uuid.sql | 2 +- .../main/data/upgrade/3.1.0/schema_update.sql | 2 +- .../upgrade/3.1.1/schema_update_after.sql | 2 +- .../upgrade/3.1.1/schema_update_before.sql | 2 +- .../main/data/upgrade/3.2.1/schema_update.sql | 2 +- .../data/upgrade/3.2.1/schema_update_ttl.sql | 2 +- .../main/data/upgrade/3.2.2/schema_update.sql | 2 +- .../upgrade/3.2.2/schema_update_event.sql | 2 +- .../data/upgrade/3.2.2/schema_update_ttl.sql | 2 +- .../main/data/upgrade/3.3.2/schema_update.sql | 2 +- .../3.3.2/schema_update_lwm2m_bootstrap.sql | 2 +- .../3.3.3/schema_event_ttl_procedure.sql | 2 +- .../main/data/upgrade/3.3.3/schema_update.sql | 2 +- .../main/data/upgrade/3.3.4/schema_update.sql | 2 +- .../main/data/upgrade/3.4.0/schema_update.sql | 2 +- .../main/data/upgrade/3.4.1/schema_update.sql | 2 +- .../upgrade/3.4.1/schema_update_after.sql | 2 +- .../upgrade/3.4.1/schema_update_before.sql | 2 +- .../main/data/upgrade/3.4.4/schema_update.sql | 2 +- .../main/data/upgrade/3.5.0/schema_update.sql | 2 +- .../main/data/upgrade/3.5.1/schema_update.sql | 2 +- .../main/data/upgrade/3.6.0/schema_update.sql | 2 +- .../3.6.1/save_attributes_node_update.sql | 26 + .../main/data/upgrade/3.6.1/schema_update.sql | 59 + .../main/data/upgrade/3.6.2/schema_update.sql | 30 + .../server/ThingsboardInstallApplication.java | 2 +- .../server/ThingsboardServerApplication.java | 2 +- .../server/actors/ActorSystemContext.java | 14 +- .../actors/TbEntityTypeActorIdPredicate.java | 2 +- .../server/actors/app/AppActor.java | 2 +- .../server/actors/app/AppInitMsg.java | 2 +- .../server/actors/device/DeviceActor.java | 5 +- .../actors/device/DeviceActorCreator.java | 2 +- .../device/DeviceActorMessageProcessor.java | 18 +- .../server/actors/device/SessionInfo.java | 2 +- .../actors/device/SessionInfoMetaData.java | 2 +- .../actors/device/SessionTimeoutCheckMsg.java | 2 +- .../device/ToDeviceRpcRequestMetadata.java | 2 +- .../device/ToServerRpcRequestMetadata.java | 2 +- .../actors/ruleChain/DefaultTbContext.java | 35 +- .../actors/ruleChain/RuleChainActor.java | 2 +- .../RuleChainActorMessageProcessor.java | 2 +- .../actors/ruleChain/RuleChainInputMsg.java | 2 +- .../ruleChain/RuleChainManagerActor.java | 2 +- .../actors/ruleChain/RuleChainOutputMsg.java | 2 +- .../ruleChain/RuleChainToRuleChainMsg.java | 2 +- .../ruleChain/RuleChainToRuleNodeMsg.java | 2 +- .../ruleChain/RuleEngineComponentActor.java | 2 +- .../actors/ruleChain/RuleNodeActor.java | 2 +- .../RuleNodeActorMessageProcessor.java | 2 +- .../server/actors/ruleChain/RuleNodeCtx.java | 2 +- .../actors/ruleChain/RuleNodeRelation.java | 2 +- .../RuleNodeToRuleChainTellNextMsg.java | 2 +- .../actors/ruleChain/RuleNodeToSelfMsg.java | 2 +- .../ruleChain/TbToRuleChainActorMsg.java | 2 +- .../ruleChain/TbToRuleNodeActorMsg.java | 2 +- .../server/actors/service/ActorService.java | 2 +- .../server/actors/service/ComponentActor.java | 2 +- .../actors/service/ContextAwareActor.java | 2 +- .../actors/service/ContextBasedCreator.java | 2 +- .../actors/service/DefaultActorService.java | 2 +- .../AbstractContextAwareMsgProcessor.java | 2 +- .../actors/shared/ActorTerminationMsg.java | 2 +- .../actors/shared/ComponentMsgProcessor.java | 2 +- .../actors/shared/RuleChainErrorActor.java | 2 +- .../server/actors/stats/StatsActor.java | 2 +- .../server/actors/stats/StatsPersistMsg.java | 2 +- .../server/actors/stats/StatsPersistTick.java | 2 +- .../actors/tenant/DebugTbRateLimits.java | 2 +- .../server/actors/tenant/TenantActor.java | 23 +- .../server/config/CryptoConfig.java | 2 +- ...tomOAuth2AuthorizationRequestResolver.java | 4 +- .../server/config/MvcCorsProperties.java | 2 +- .../config/RateLimitProcessingFilter.java | 2 +- .../config/SchedulingConfiguration.java | 2 +- .../server/config/SwaggerConfiguration.java | 4 +- .../TbRuleEngineSecurityConfiguration.java | 44 + .../ThingsboardMessageConfiguration.java | 2 +- .../ThingsboardSecurityConfiguration.java | 28 +- .../thingsboard/server/config/WebConfig.java | 2 +- .../server/config/WebSocketConfiguration.java | 53 +- .../controller/AbstractRpcController.java | 2 +- .../server/controller/AdminController.java | 6 +- .../controller/AlarmCommentController.java | 2 +- .../server/controller/AlarmController.java | 2 +- .../server/controller/AssetController.java | 6 +- .../controller/AssetProfileController.java | 36 +- .../server/controller/AuditLogController.java | 2 +- .../server/controller/AuthController.java | 10 +- .../controller/AutoCommitController.java | 2 +- .../server/controller/BaseController.java | 27 +- .../ComponentDescriptorController.java | 2 +- .../controller/ControllerConstants.java | 7 +- .../server/controller/CustomerController.java | 2 +- .../controller/DashboardController.java | 16 +- .../DeviceConnectivityController.java | 57 +- .../server/controller/DeviceController.java | 21 +- .../controller/DeviceProfileController.java | 34 +- .../server/controller/EdgeController.java | 58 +- .../controller/EdgeEventController.java | 2 +- .../EntitiesVersionControlController.java | 10 +- .../controller/EntityQueryController.java | 2 +- .../controller/EntityRelationController.java | 2 +- .../controller/EntityViewController.java | 2 +- .../server/controller/EventController.java | 2 +- .../controller/HttpValidationCallback.java | 2 +- .../server/controller/ImageController.java | 346 + .../server/controller/Lwm2mController.java | 2 +- .../MailConfigTemplateController.java | 2 +- .../controller/NotificationController.java | 2 +- .../NotificationRuleController.java | 2 +- .../NotificationTargetController.java | 2 +- .../NotificationTemplateController.java | 2 +- .../OAuth2ConfigTemplateController.java | 2 +- .../server/controller/OAuth2Controller.java | 2 +- .../controller/OtaPackageController.java | 2 +- .../server/controller/QueueController.java | 2 +- .../server/controller/RpcV1Controller.java | 2 +- .../server/controller/RpcV2Controller.java | 2 +- .../controller/RuleChainController.java | 2 +- .../controller/SystemInfoController.java | 7 +- .../controller/TbResourceController.java | 130 +- .../server/controller/TbUrlConstants.java | 2 +- .../controller/TelemetryController.java | 25 +- .../server/controller/TenantController.java | 2 +- .../controller/TenantProfileController.java | 3 +- .../TwoFactorAuthConfigController.java | 2 +- .../controller/TwoFactorAuthController.java | 2 +- .../controller/UiSettingsController.java | 2 +- .../controller/UsageInfoController.java | 2 +- .../server/controller/UserController.java | 2 +- .../controller/WidgetTypeController.java | 40 +- .../controller/WidgetsBundleController.java | 20 +- .../controller/plugin/TbWebSocketHandler.java | 322 +- .../controller/plugin/TbWebSocketMsg.java | 2 +- .../controller/plugin/TbWebSocketMsgType.java | 2 +- .../controller/plugin/TbWebSocketPingMsg.java | 2 +- .../controller/plugin/TbWebSocketTextMsg.java | 2 +- .../exception/AccessDeniedException.java | 2 +- .../exception/EntityNotFoundException.java | 2 +- .../exception/InternalErrorException.java | 2 +- .../exception/InvalidParametersException.java | 2 +- ...ThingsboardCredentialsExpiredResponse.java | 2 +- ...ingsboardCredentialsViolationResponse.java | 33 + .../exception/ThingsboardErrorResponse.java | 2 +- .../ThingsboardErrorResponseHandler.java | 6 +- .../exception/ToErrorResponseEntity.java | 2 +- .../exception/UnauthorizedException.java | 2 +- .../exception/UncheckedApiException.java | 2 +- .../ThingsboardInstallConfiguration.java | 2 +- .../install/ThingsboardInstallException.java | 2 +- .../install/ThingsboardInstallService.java | 20 +- .../service/action/EntityActionService.java | 2 +- .../service/apiusage/BaseApiUsageState.java | 2 +- .../apiusage/CustomerApiUsageState.java | 2 +- .../DefaultTbApiUsageStateService.java | 5 +- .../apiusage/TbApiUsageStateService.java | 2 +- .../service/apiusage/TenantApiUsageState.java | 2 +- .../service/asset/AssetBulkImportService.java | 2 +- .../AnnotationComponentDiscoveryService.java | 3 +- .../component/ComponentDiscoveryService.java | 2 +- .../service/component/RuleNodeClassInfo.java | 2 +- .../device/ClaimDevicesServiceImpl.java | 2 +- .../device/DeviceBulkImportService.java | 2 +- .../device/DeviceProvisionServiceImpl.java | 2 +- .../edge/DefaultEdgeNotificationService.java | 36 +- .../service/edge/EdgeBulkImportService.java | 2 +- .../service/edge/EdgeContextComponent.java | 44 +- .../edge/EdgeEventSourcingListener.java | 49 +- .../service/edge/EdgeNotificationService.java | 2 +- ...efaultEdgeInstallInstructionsService.java} | 40 +- ...DefaultEdgeUpgradeInstructionsService.java | 193 + ...va => EdgeInstallInstructionsService.java} | 11 +- .../EdgeUpgradeInstructionsService.java | 34 + .../edge/rpc/EdgeEventStorageSettings.java | 2 +- .../service/edge/rpc/EdgeGrpcService.java | 2 +- .../service/edge/rpc/EdgeGrpcSession.java | 90 +- .../service/edge/rpc/EdgeRpcService.java | 2 +- .../service/edge/rpc/EdgeSessionState.java | 2 +- .../service/edge/rpc/EdgeSyncCursor.java | 4 +- .../rpc/constructor/AssetMsgConstructor.java | 60 - .../BaseMsgConstructorFactory.java | 46 + .../DeviceProfileMsgConstructor.java | 90 - .../rpc/constructor/MsgConstructor.java} | 8 +- .../TenantProfileMsgConstructor.java | 52 - .../WidgetsBundleMsgConstructor.java | 65 - .../alarm/AlarmMsgConstructor.java | 30 + .../alarm/AlarmMsgConstructorFactory.java | 26 + .../AlarmMsgConstructorV1.java} | 13 +- .../alarm/AlarmMsgConstructorV2.java | 36 + .../alarm/BaseAlarmMsgConstructor.java | 29 + .../asset/AssetMsgConstructor.java | 36 + .../asset/AssetMsgConstructorFactory.java | 26 + .../AssetMsgConstructorV1.java} | 50 +- .../asset/AssetMsgConstructorV2.java | 44 + .../asset/BaseAssetMsgConstructor.java | 41 + .../customer/BaseCustomerMsgConstructor.java | 31 + .../customer/CustomerMsgConstructor.java | 29 + .../CustomerMsgConstructorFactory.java | 26 + .../CustomerMsgConstructorV1.java} | 15 +- .../customer/CustomerMsgConstructorV2.java | 35 + .../BaseDashboardMsgConstructor.java | 31 + .../dashboard/DashboardMsgConstructor.java | 29 + .../DashboardMsgConstructorFactory.java | 26 + .../DashboardMsgConstructorV1.java} | 22 +- .../dashboard/DashboardMsgConstructorV2.java | 35 + .../device/BaseDeviceMsgConstructor.java | 102 + .../device/DeviceMsgConstructor.java | 46 + .../device/DeviceMsgConstructorFactory.java | 26 + .../DeviceMsgConstructorV1.java} | 107 +- .../device/DeviceMsgConstructorV2.java | 51 + .../{ => edge}/EdgeMsgConstructor.java | 4 +- .../BaseEntityViewMsgConstructor.java | 31 + .../entityview/EntityViewMsgConstructor.java | 29 + .../EntityViewMsgConstructorFactory.java | 26 + .../EntityViewMsgConstructorV1.java} | 37 +- .../EntityViewMsgConstructorV2.java | 35 + .../ota/BaseOtaPackageMsgConstructor.java | 31 + .../ota/OtaPackageMsgConstructor.java | 29 + .../ota/OtaPackageMsgConstructorFactory.java | 26 + .../OtaPackageMsgConstructorV1.java} | 16 +- .../ota/OtaPackageMsgConstructorV2.java | 35 + .../queue/BaseQueueMsgConstructor.java | 31 + .../queue/QueueMsgConstructor.java | 29 + .../queue/QueueMsgConstructorFactory.java | 26 + .../QueueMsgConstructorV1.java} | 13 +- .../queue/QueueMsgConstructorV2.java | 35 + .../relation/RelationMsgConstructor.java | 26 + .../RelationMsgConstructorFactory.java | 26 + .../RelationMsgConstructorV1.java} | 7 +- .../relation/RelationMsgConstructorV2.java | 34 + .../resource/BaseResourceMsgConstructor.java | 31 + .../resource/ResourceMsgConstructor.java | 29 + .../ResourceMsgConstructorFactory.java | 26 + .../ResourceMsgConstructorV1.java} | 25 +- .../resource/ResourceMsgConstructorV2.java | 35 + ... => BaseRuleChainMetadataConstructor.java} | 23 +- .../BaseRuleChainMsgConstructor.java} | 49 +- .../rule/RuleChainMetadataConstructor.java | 6 +- .../RuleChainMetadataConstructorFactory.java | 8 +- .../RuleChainMetadataConstructorV330.java | 6 +- .../RuleChainMetadataConstructorV340.java | 6 +- .../RuleChainMetadataConstructorV362.java | 29 + .../rule/RuleChainMsgConstructor.java | 38 + .../rule/RuleChainMsgConstructorFactory.java | 26 + .../rule/RuleChainMsgConstructorV1.java | 45 + .../rule/RuleChainMsgConstructorV2.java | 39 + .../settings/AdminSettingsMsgConstructor.java | 25 + .../AdminSettingsMsgConstructorFactory.java | 26 + .../AdminSettingsMsgConstructorV1.java} | 11 +- .../AdminSettingsMsgConstructorV2.java | 32 + .../EntityDataMsgConstructor.java | 9 +- .../tenant/TenantMsgConstructor.java | 31 + .../tenant/TenantMsgConstructorFactory.java | 26 + .../TenantMsgConstructorV1.java} | 35 +- .../tenant/TenantMsgConstructorV2.java | 41 + .../user/BaseUserMsgConstructor.java | 31 + .../constructor/user/UserMsgConstructor.java | 33 + .../user/UserMsgConstructorFactory.java | 26 + .../UserMsgConstructorV1.java} | 21 +- .../user/UserMsgConstructorV2.java | 42 + .../widget/BaseWidgetMsgConstructor.java | 43 + .../widget/WidgetMsgConstructor.java | 39 + .../widget/WidgetMsgConstructorFactory.java | 26 + .../WidgetMsgConstructorV1.java} | 52 +- .../widget/WidgetMsgConstructorV2.java | 48 + .../fetch/AdminSettingsEdgeEventFetcher.java | 2 +- .../fetch/AssetProfilesEdgeEventFetcher.java | 2 +- .../rpc/fetch/AssetsEdgeEventFetcher.java | 2 +- .../fetch/BasePageableEdgeEventFetcher.java | 2 +- .../fetch/BaseResourceEdgeEventFetcher.java | 49 - .../rpc/fetch/BaseUsersEdgeEventFetcher.java | 2 +- .../BaseWidgetTypesEdgeEventFetcher.java | 2 +- .../BaseWidgetsBundlesEdgeEventFetcher.java | 2 +- .../rpc/fetch/CustomerEdgeEventFetcher.java | 2 +- .../fetch/CustomerUsersEdgeEventFetcher.java | 2 +- .../rpc/fetch/DashboardsEdgeEventFetcher.java | 2 +- .../DefaultProfilesEdgeEventFetcher.java | 2 +- .../fetch/DeviceProfilesEdgeEventFetcher.java | 2 +- .../rpc/fetch/DevicesEdgeEventFetcher.java | 2 +- .../edge/rpc/fetch/EdgeEventFetcher.java | 2 +- .../fetch/EntityViewsEdgeEventFetcher.java | 2 +- .../rpc/fetch/GeneralEdgeEventFetcher.java | 2 +- .../fetch/OtaPackagesEdgeEventFetcher.java | 2 +- .../rpc/fetch/QueuesEdgeEventFetcher.java | 2 +- .../rpc/fetch/RuleChainsEdgeEventFetcher.java | 2 +- .../SystemResourcesEdgeEventFetcher.java | 34 - .../SystemWidgetTypesEdgeEventFetcher.java | 2 +- .../SystemWidgetsBundlesEdgeEventFetcher.java | 2 +- .../TenantAdminUsersEdgeEventFetcher.java | 2 +- .../rpc/fetch/TenantEdgeEventFetcher.java | 2 +- .../TenantResourcesEdgeEventFetcher.java | 23 +- .../TenantWidgetTypesEdgeEventFetcher.java | 2 +- .../TenantWidgetsBundlesEdgeEventFetcher.java | 2 +- .../edge/rpc/processor/BaseEdgeProcessor.java | 131 +- .../processor/BaseEdgeProcessorFactory.java | 46 + .../edge/rpc/processor/EdgeProcessor.java | 19 + .../processor/alarm/AlarmEdgeProcessor.java | 143 +- .../alarm/AlarmEdgeProcessorFactory.java | 26 + .../processor/alarm/AlarmEdgeProcessorV1.java | 72 + .../processor/alarm/AlarmEdgeProcessorV2.java | 43 + .../rpc/processor/alarm/AlarmProcessor.java | 37 + .../processor/alarm/BaseAlarmProcessor.java | 118 +- .../processor/asset/AssetEdgeProcessor.java | 26 +- .../asset/AssetEdgeProcessorFactory.java | 26 + .../processor/asset/AssetEdgeProcessorV1.java | 59 + .../processor/asset/AssetEdgeProcessorV2.java | 43 + .../rpc/processor/asset/AssetProcessor.java | 33 + .../processor/asset/BaseAssetProcessor.java | 39 +- .../AssetProfileEdgeProcessor.java | 40 +- .../AssetProfileEdgeProcessorFactory.java | 26 + .../profile/AssetProfileEdgeProcessorV1.java | 65 + .../profile/AssetProfileEdgeProcessorV2.java | 57 + .../asset/profile/AssetProfileProcessor.java | 33 + .../BaseAssetProfileProcessor.java | 48 +- .../customer/CustomerEdgeProcessor.java | 14 +- .../dashboard/BaseDashboardProcessor.java | 59 +- .../dashboard/DashboardEdgeProcessor.java | 27 +- .../DashboardEdgeProcessorFactory.java | 26 + .../dashboard/DashboardEdgeProcessorV1.java | 54 + .../dashboard/DashboardEdgeProcessorV2.java | 36 + .../dashboard/DashboardProcessor.java | 32 + .../processor/device/BaseDeviceProcessor.java | 82 +- .../device/BaseDeviceProfileProcessor.java | 115 - .../processor/device/DeviceEdgeProcessor.java | 50 +- .../device/DeviceEdgeProcessorFactory.java | 26 + .../device/DeviceEdgeProcessorV1.java | 87 + .../device/DeviceEdgeProcessorV2.java | 50 + .../rpc/processor/device/DeviceProcessor.java | 40 + .../profile/BaseDeviceProfileProcessor.java | 86 + .../DeviceProfileEdgeProcessor.java | 40 +- .../DeviceProfileEdgeProcessorFactory.java | 26 + .../profile/DeviceProfileEdgeProcessorV1.java | 98 + .../profile/DeviceProfileEdgeProcessorV2.java | 57 + .../profile/DeviceProfileProcessor.java | 33 + .../rpc/processor/edge/EdgeProcessor.java | 4 +- .../entityview/BaseEntityViewProcessor.java | 43 +- .../entityview/EntityViewEdgeProcessor.java | 25 +- .../entityview/EntityViewProcessor.java | 32 + .../EntityViewProcessorFactory.java | 26 + .../entityview/EntityViewProcessorV1.java | 65 + .../entityview/EntityViewProcessorV2.java | 43 + .../ota/OtaPackageEdgeProcessor.java | 14 +- .../processor/queue/QueueEdgeProcessor.java | 17 +- .../relation/BaseRelationProcessor.java | 33 +- .../relation/RelationEdgeProcessor.java | 18 +- .../RelationEdgeProcessorFactory.java | 26 + .../relation/RelationEdgeProcessorV1.java | 52 + .../relation/RelationEdgeProcessorV2.java | 34 + .../processor/relation/RelationProcessor.java | 32 + .../resource/BaseResourceProcessor.java | 34 +- .../resource/ResourceEdgeProcessor.java | 28 +- .../ResourceEdgeProcessorFactory.java | 26 + .../resource/ResourceEdgeProcessorV1.java | 48 + .../resource/ResourceEdgeProcessorV2.java | 36 + .../processor/resource/ResourceProcessor.java | 32 + .../rule/RuleChainEdgeProcessor.java | 20 +- .../settings/AdminSettingsEdgeProcessor.java | 12 +- .../telemetry/BaseTelemetryProcessor.java | 10 +- .../telemetry/TelemetryEdgeProcessor.java | 7 +- .../processor/tenant/TenantEdgeProcessor.java | 13 +- .../tenant/TenantProfileEdgeProcessor.java | 10 +- .../rpc/processor/user/UserEdgeProcessor.java | 15 +- .../widget/WidgetBundleEdgeProcessor.java | 10 +- .../widget/WidgetTypeEdgeProcessor.java | 10 +- .../rpc/sync/DefaultEdgeRequestsService.java | 4 +- .../edge/rpc/sync/EdgeRequestsService.java | 2 +- .../edge/rpc/utils/EdgeVersionUtils.java | 2 +- .../entitiy/AbstractTbEntityService.java | 2 +- .../DefaultTbNotificationEntityService.java | 43 +- .../entitiy/SimpleTbEntityService.java | 2 +- .../entitiy/TbNotificationEntityService.java | 2 +- .../alarm/DefaultTbAlarmCommentService.java | 2 +- .../entitiy/alarm/DefaultTbAlarmService.java | 2 +- .../entitiy/alarm/TbAlarmCommentService.java | 3 +- .../service/entitiy/alarm/TbAlarmService.java | 2 +- .../entitiy/asset/DefaultTbAssetService.java | 2 +- .../service/entitiy/asset/TbAssetService.java | 2 +- .../profile/DefaultTbAssetProfileService.java | 2 +- .../asset/profile/TbAssetProfileService.java | 2 +- .../customer/DefaultTbCustomerService.java | 2 +- .../entitiy/customer/TbCustomerService.java | 2 +- .../dashboard/DefaultTbDashboardService.java | 3 +- .../entitiy/dashboard/TbDashboardService.java | 2 +- .../device/DefaultTbDeviceService.java | 2 +- .../entitiy/device/TbDeviceService.java | 2 +- .../DefaultTbDeviceProfileService.java | 2 +- .../profile/TbDeviceProfileService.java | 2 +- .../entitiy/edge/DefaultTbEdgeService.java | 2 +- .../service/entitiy/edge/TbEdgeService.java | 2 +- .../DefaultTbEntityRelationService.java | 2 +- .../relation/TbEntityRelationService.java | 2 +- .../DefaultTbEntityViewService.java | 2 +- .../entityview/TbEntityViewService.java | 2 +- .../ota/DefaultTbOtaPackageService.java | 2 +- .../entitiy/ota/TbOtaPackageService.java | 2 +- .../entitiy/queue/DefaultTbQueueService.java | 2 +- .../service/entitiy/queue/TbQueueService.java | 2 +- .../tenant/DefaultTbTenantService.java | 3 +- .../entitiy/tenant/TbTenantService.java | 2 +- .../DefaultTbTenantProfileService.java | 2 +- .../profile/TbTenantProfileService.java | 2 +- .../user/DefaultTbUserSettingsService.java | 2 +- .../entitiy/user/DefaultUserService.java | 2 +- .../service/entitiy/user/TbUserService.java | 2 +- .../entitiy/user/TbUserSettingsService.java | 2 +- .../bundle/DefaultWidgetsBundleService.java | 2 +- .../bundle/TbWidgetsBundleService.java | 2 +- .../type/DefaultWidgetTypeService.java | 5 +- .../widgets/type/TbWidgetTypeService.java | 2 +- .../executors/DbCallbackExecutorService.java | 2 +- .../ExternalCallExecutorService.java | 2 +- .../GrpcCallbackExecutorService.java | 2 +- .../NotificationExecutorService.java | 2 +- .../PubSubRuleNodeExecutorProvider.java | 63 + .../SharedEventLoopGroupService.java | 2 +- .../executors/VersionControlExecutor.java | 32 + .../DefaultGatewayNotificationsService.java | 2 +- .../GatewayNotificationsService.java | 2 +- .../InMemoryHouseKeeperServiceService.java | 2 +- ...stractCassandraDatabaseUpgradeService.java | 2 +- .../AbstractSqlTsDatabaseUpgradeService.java | 2 +- ...assandraAbstractDatabaseSchemaService.java | 2 +- .../install/CassandraKeyspaceService.java | 2 +- .../CassandraTsDatabaseSchemaService.java | 2 +- .../CassandraTsDatabaseUpgradeService.java | 2 +- ...assandraTsLatestDatabaseSchemaService.java | 2 +- .../DatabaseEntitiesUpgradeService.java | 2 +- .../service/install/DatabaseHelper.java | 2 +- .../install/DatabaseSchemaService.java | 2 +- .../install/DatabaseTsUpgradeService.java | 2 +- .../install/DbUpgradeExecutorService.java | 2 +- .../DefaultSystemDataLoaderService.java | 51 +- .../install/EntityDatabaseSchemaService.java | 2 +- .../service/install/InstallScripts.java | 75 +- .../service/install/NoSqlKeyspaceService.java | 2 +- .../SqlAbstractDatabaseSchemaService.java | 2 +- .../install/SqlDatabaseUpgradeService.java | 134 +- .../SqlEntityDatabaseSchemaService.java | 2 +- .../install/SqlTsDatabaseSchemaService.java | 2 +- .../install/SqlTsDatabaseUpgradeService.java | 2 +- .../install/SystemDataLoaderService.java | 2 +- .../TbRuleEngineQueueConfigService.java | 2 +- .../TimescaleTsDatabaseSchemaService.java | 2 +- .../TimescaleTsDatabaseUpgradeService.java | 2 +- .../install/TsDatabaseSchemaService.java | 2 +- .../TsLatestDatabaseSchemaService.java | 2 +- .../install/cql/CQLStatementsParser.java | 2 +- .../install/cql/CassandraDbHelper.java | 2 +- .../CassandraEntitiesToSqlMigrateService.java | 2 +- .../install/migrate/CassandraToSqlColumn.java | 2 +- .../migrate/CassandraToSqlColumnData.java | 2 +- .../migrate/CassandraToSqlColumnType.java | 2 +- .../migrate/CassandraToSqlEventTsColumn.java | 2 +- .../install/migrate/CassandraToSqlTable.java | 2 +- .../CassandraTsLatestToSqlMigrateService.java | 2 +- .../migrate/EntitiesMigrateService.java | 2 +- .../migrate/TsLatestMigrateService.java | 2 +- .../service/install/sql/SqlDbHelper.java | 2 +- .../install/update/CacheCleanupService.java | 2 +- .../install/update/DataUpdateService.java | 2 +- .../update/DefaultCacheCleanupService.java | 10 +- .../update/DefaultDataUpdateService.java | 2 +- .../service/install/update/ImagesUpdater.java | 170 + .../install/update/PaginatedUpdater.java | 2 +- .../install/update/RateLimitsUpdater.java | 2 +- .../server/service/lwm2m/LwM2MService.java | 2 +- .../service/lwm2m/LwM2MServiceImpl.java | 2 +- .../service/mail/DefaultMailService.java | 2 +- .../DefaultTbMailConfigTemplateService.java | 2 +- .../service/mail/MailExecutorService.java | 2 +- .../mail/PasswordResetExecutorService.java | 2 +- .../mail/RefreshTokenExpCheckService.java | 2 +- .../mail/TbMailConfigTemplateService.java | 2 +- .../service/mail/TbMailContextComponent.java | 2 +- .../server/service/mail/TbMailSender.java | 2 +- .../DefaultNotificationCenter.java | 38 +- .../DefaultNotificationSchedulerService.java | 18 +- .../NotificationProcessingContext.java | 2 +- .../NotificationSchedulerService.java | 2 +- .../channels/EmailNotificationChannel.java | 2 +- .../MicrosoftTeamsNotificationChannel.java | 2 +- .../channels/NotificationChannel.java | 2 +- .../channels/SlackNotificationChannel.java | 2 +- .../channels/SmsNotificationChannel.java | 2 +- .../DefaultNotificationRuleProcessor.java | 2 +- .../cache/DefaultNotificationRulesCache.java | 2 +- .../rule/cache/NotificationRulesCache.java | 2 +- .../AlarmAssignmentTriggerProcessor.java | 2 +- .../trigger/AlarmCommentTriggerProcessor.java | 2 +- .../rule/trigger/AlarmTriggerProcessor.java | 2 +- .../ApiUsageLimitTriggerProcessor.java | 2 +- .../DeviceActivityTriggerProcessor.java | 2 +- .../EntitiesLimitTriggerProcessor.java | 2 +- .../trigger/EntityActionTriggerProcessor.java | 2 +- .../NewPlatformVersionTriggerProcessor.java | 2 +- .../NotificationRuleTriggerProcessor.java | 2 +- .../trigger/RateLimitsTriggerProcessor.java | 2 +- ...mponentLifecycleEventTriggerProcessor.java | 2 +- .../ota/DefaultOtaPackageStateService.java | 2 +- .../service/ota/OtaPackageStateService.java | 2 +- .../AbstractPartitionBasedService.java | 2 +- .../partition/TbCoreStartupService.java | 2 +- .../profile/DefaultTbAssetProfileCache.java | 2 +- .../profile/DefaultTbDeviceProfileCache.java | 2 +- .../service/profile/TbAssetProfileCache.java | 2 +- .../service/profile/TbDeviceProfileCache.java | 2 +- .../query/DefaultEntityQueryService.java | 2 +- .../service/query/EntityQueryService.java | 2 +- .../queue/DefaultQueueRoutingInfoService.java | 2 +- .../queue/DefaultTbClusterService.java | 34 +- .../queue/DefaultTbCoreConsumerService.java | 28 +- .../DefaultTbRuleEngineConsumerService.java | 3 +- .../DefaultTenantRoutingInfoService.java | 2 +- .../service/queue/TbCoreConsumerService.java | 2 +- .../service/queue/TbCoreConsumerStats.java | 2 +- .../service/queue/TbMsgPackCallback.java | 2 +- .../queue/TbMsgPackProcessingContext.java | 2 +- .../service/queue/TbMsgProfilerInfo.java | 2 +- .../server/service/queue/TbPackCallback.java | 2 +- .../queue/TbPackProcessingContext.java | 2 +- .../queue/TbRuleEngineConsumerService.java | 2 +- .../queue/TbRuleEngineConsumerStats.java | 2 +- .../service/queue/TbRuleNodeProfilerInfo.java | 2 +- .../queue/TbTenantRuleEngineStats.java | 2 +- .../TbTopicWithConsumerPerPartition.java | 2 +- .../processing/AbstractConsumerService.java | 2 +- .../AbstractTbRuleEngineSubmitStrategy.java | 2 +- .../BatchTbRuleEngineSubmitStrategy.java | 2 +- .../BurstTbRuleEngineSubmitStrategy.java | 2 +- .../service/queue/processing/IdMsgPair.java | 2 +- ...lByEntityIdTbRuleEngineSubmitStrategy.java | 2 +- ...riginatorIdTbRuleEngineSubmitStrategy.java | 2 +- ...lByTenantIdTbRuleEngineSubmitStrategy.java | 2 +- .../SequentialTbRuleEngineSubmitStrategy.java | 2 +- .../TbRuleEngineProcessingDecision.java | 2 +- .../TbRuleEngineProcessingResult.java | 2 +- .../TbRuleEngineProcessingStrategy.java | 2 +- ...TbRuleEngineProcessingStrategyFactory.java | 2 +- .../TbRuleEngineSubmitStrategy.java | 2 +- .../TbRuleEngineSubmitStrategyFactory.java | 2 +- .../service/queue/ruleengine/QueueEvent.java | 2 +- .../TbQueueConsumerManagerTask.java | 2 +- .../queue/ruleengine/TbQueueConsumerTask.java | 2 +- .../TbRuleEngineConsumerContext.java | 2 +- .../TbRuleEngineQueueConsumerManager.java | 2 +- .../resource/DefaultTbImageService.java | 188 + .../resource/DefaultTbResourceService.java | 132 +- .../service/resource/TbImageService.java | 38 + .../service/resource/TbResourceService.java | 20 +- .../rpc/DefaultTbCoreDeviceRpcService.java | 2 +- .../rpc/DefaultTbRuleEngineRpcService.java | 2 +- .../service/rpc/LocalRequestMetaData.java | 2 +- .../server/service/rpc/RpcSubmitStrategy.java | 2 +- .../service/rpc/TbCoreDeviceRpcService.java | 2 +- .../server/service/rpc/TbRpcService.java | 2 +- .../rpc/TbRuleEngineDeviceRpcService.java | 2 +- .../rule/DefaultTbRuleChainService.java | 16 +- .../service/rule/TbRuleChainService.java | 2 +- .../script/RuleNodeJsScriptEngine.java | 2 +- .../service/script/RuleNodeScriptEngine.java | 2 +- .../script/RuleNodeTbelScriptEngine.java | 2 +- .../service/security/AccessValidator.java | 2 +- .../service/security/ValidationCallback.java | 2 +- .../service/security/ValidationResult.java | 2 +- .../security/ValidationResultCode.java | 2 +- .../auth/AbstractJwtAuthenticationToken.java | 2 +- .../auth/DefaultTokenOutdatingService.java | 5 +- .../security/auth/JwtAuthenticationToken.java | 2 +- .../security/auth/MfaAuthenticationToken.java | 2 +- .../auth/RefreshAuthenticationToken.java | 2 +- .../security/auth/TokenOutdatingService.java | 5 +- .../auth/jwt/JwtAuthenticationProvider.java | 18 +- ...wtTokenAuthenticationProcessingFilter.java | 2 +- .../RefreshTokenAuthenticationProvider.java | 6 +- .../jwt/RefreshTokenProcessingFilter.java | 2 +- .../auth/jwt/RefreshTokenRequest.java | 2 +- .../auth/jwt/SkipPathRequestMatcher.java | 2 +- .../extractor/JwtHeaderTokenExtractor.java | 2 +- .../jwt/extractor/JwtQueryTokenExtractor.java | 2 +- .../auth/jwt/extractor/TokenExtractor.java | 2 +- .../settings/DefaultJwtSettingsService.java | 2 +- .../settings/DefaultJwtSettingsValidator.java | 2 +- .../settings/InstallJwtSettingsValidator.java | 2 +- .../auth/jwt/settings/JwtSettingsService.java | 2 +- .../jwt/settings/JwtSettingsValidator.java | 2 +- .../auth/mfa/DefaultTwoFactorAuthService.java | 2 +- .../auth/mfa/TwoFactorAuthService.java | 2 +- .../mfa/config/DefaultTwoFaConfigManager.java | 2 +- .../auth/mfa/config/TwoFaConfigManager.java | 2 +- .../auth/mfa/provider/TwoFaProvider.java | 2 +- .../impl/BackupCodeTwoFaProvider.java | 2 +- .../mfa/provider/impl/EmailTwoFaProvider.java | 2 +- .../provider/impl/OtpBasedTwoFaProvider.java | 2 +- .../mfa/provider/impl/SmsTwoFaProvider.java | 2 +- .../mfa/provider/impl/TotpTwoFaProvider.java | 2 +- .../oauth2/AbstractOAuth2ClientMapper.java | 2 +- .../auth/oauth2/AppleOAuth2ClientMapper.java | 2 +- .../auth/oauth2/BasicMapperUtils.java | 2 +- .../auth/oauth2/BasicOAuth2ClientMapper.java | 2 +- .../security/auth/oauth2/CookieUtils.java | 2 +- .../auth/oauth2/CustomOAuth2ClientMapper.java | 2 +- .../auth/oauth2/GithubOAuth2ClientMapper.java | 2 +- ...eOAuth2AuthorizationRequestRepository.java | 4 +- .../auth/oauth2/OAuth2ClientMapper.java | 2 +- .../oauth2/OAuth2ClientMapperProvider.java | 2 +- .../Oauth2AuthenticationFailureHandler.java | 2 +- .../Oauth2AuthenticationSuccessHandler.java | 2 +- .../auth/oauth2/TbOAuth2ParameterNames.java | 2 +- .../security/auth/rest/LoginRequest.java | 2 +- .../security/auth/rest/LoginResponse.java | 2 +- .../auth/rest/PublicLoginRequest.java | 2 +- .../auth/rest/RestAuthenticationDetails.java | 2 +- .../rest/RestAuthenticationDetailsSource.java | 2 +- .../auth/rest/RestAuthenticationProvider.java | 17 +- ...RestAwareAuthenticationFailureHandler.java | 2 +- ...RestAwareAuthenticationSuccessHandler.java | 2 +- .../auth/rest/RestLoginProcessingFilter.java | 2 +- .../rest/RestPublicLoginProcessingFilter.java | 2 +- .../device/DefaultDeviceAuthService.java | 2 +- .../AuthMethodNotSupportedException.java | 2 +- .../exception/JwtExpiredTokenException.java | 9 +- .../UserPasswordExpiredException.java | 2 +- .../UserPasswordNotValidException.java | 26 + .../security/model/ActivateUserRequest.java | 2 +- .../security/model/ChangePasswordRequest.java | 2 +- .../model/ResetPasswordEmailRequest.java | 2 +- .../security/model/ResetPasswordRequest.java | 2 +- .../service/security/model/SecurityUser.java | 2 +- .../service/security/model/UserPrincipal.java | 2 +- .../security/model/token/AccessJwtToken.java | 2 +- .../security/model/token/JwtTokenFactory.java | 14 +- .../model/token/OAuth2AppTokenFactory.java | 2 +- .../model/token/RawAccessJwtToken.java | 2 +- .../permission/AbstractPermissions.java | 2 +- .../permission/AccessControlService.java | 2 +- .../permission/CustomerUserPermissions.java | 2 +- .../DefaultAccessControlService.java | 2 +- .../security/permission/Operation.java | 2 +- .../permission/PermissionChecker.java | 2 +- .../security/permission/Permissions.java | 2 +- .../service/security/permission/Resource.java | 2 +- .../permission/SysAdminPermissions.java | 2 +- .../permission/TenantAdminPermissions.java | 2 +- .../system/DefaultSystemSecurityService.java | 67 +- .../system/SystemSecurityService.java | 11 +- .../DefaultDeviceSessionCacheService.java | 2 +- .../session/DeviceSessionCacheService.java | 2 +- .../service/session/SessionCaffeineCache.java | 2 +- .../service/session/SessionRedisCache.java | 2 +- .../service/slack/DefaultSlackService.java | 2 +- .../server/service/sms/AbstractSmsSender.java | 2 +- .../service/sms/DefaultSmsSenderFactory.java | 2 +- .../server/service/sms/DefaultSmsService.java | 2 +- .../service/sms/SmsExecutorService.java | 2 +- .../server/service/sms/aws/AwsSmsSender.java | 2 +- .../service/sms/smpp/SmppSmsSender.java | 2 +- .../service/sms/twilio/TwilioSmsSender.java | 2 +- .../state/DefaultDeviceStateService.java | 10 +- .../server/service/state/DeviceState.java | 2 +- .../server/service/state/DeviceStateData.java | 2 +- .../service/state/DeviceStateService.java | 2 +- .../service/stats/DefaultJsInvokeStats.java | 2 +- .../DefaultRuleEngineStatisticsService.java | 2 +- .../stats/RuleEngineStatisticsService.java | 2 +- .../DefaultSubscriptionManagerService.java | 2 +- ...efaultTbEntityDataSubscriptionService.java | 9 +- .../DefaultTbLocalSubscriptionService.java | 2 +- .../subscription/ReadTsKvQueryInfo.java | 2 +- .../subscription/SubscriptionErrorCode.java | 2 +- .../SubscriptionManagerService.java | 2 +- .../SubscriptionSchedulerComponent.java | 2 +- .../SubscriptionServiceStatistics.java | 2 +- .../subscription/TbAbstractDataSubCtx.java | 2 +- .../subscription/TbAbstractSubCtx.java | 4 +- .../subscription/TbAlarmCountSubCtx.java | 2 +- .../subscription/TbAlarmDataSubCtx.java | 2 +- .../subscription/TbAlarmsSubscription.java | 2 +- .../subscription/TbAttributeSubscription.java | 2 +- .../TbAttributeSubscriptionScope.java | 2 +- .../subscription/TbEntityCountSubCtx.java | 2 +- .../subscription/TbEntityDataSubCtx.java | 2 +- .../TbEntityDataSubscriptionService.java | 2 +- .../subscription/TbEntityLocalSubsInfo.java | 2 +- .../subscription/TbEntityRemoteSubsInfo.java | 2 +- .../subscription/TbEntitySubEvent.java | 2 +- .../subscription/TbEntityUpdatesInfo.java | 2 +- .../TbLocalSubscriptionService.java | 2 +- .../service/subscription/TbSubscription.java | 5 +- .../subscription/TbSubscriptionType.java | 2 +- .../subscription/TbSubscriptionUtils.java | 2 +- .../subscription/TbSubscriptionsInfo.java | 2 +- .../TbTimeSeriesSubscription.java | 2 +- .../DefaultEntitiesExportImportService.java | 6 +- .../sync/ie/EntitiesExportImportService.java | 2 +- .../DefaultExportableEntitiesService.java | 12 +- .../ie/exporting/EntityExportService.java | 2 +- .../exporting/ExportableEntitiesService.java | 4 +- .../ie/exporting/impl/AssetExportService.java | 2 +- .../impl/AssetProfileExportService.java | 3 +- .../impl/BaseEntityExportService.java | 2 +- .../impl/DashboardExportService.java | 3 +- .../impl/DefaultEntityExportService.java | 5 +- .../exporting/impl/DeviceExportService.java | 2 +- .../impl/DeviceProfileExportService.java | 3 +- .../impl/EntityViewExportService.java | 2 +- .../impl/NotificationRuleExportService.java | 2 +- .../impl/NotificationTargetExportService.java | 5 +- .../NotificationTemplateExportService.java | 2 +- .../exporting/impl/ResourceExportService.java | 44 + .../impl/RuleChainExportService.java | 2 +- .../impl/WidgetTypeExportService.java | 7 +- .../impl/WidgetsBundleExportService.java | 3 +- .../ie/importing/EntityImportService.java | 2 +- .../csv/AbstractBulkImportService.java | 4 +- .../ie/importing/csv/ImportedEntityInfo.java | 2 +- .../ie/importing/impl/AssetImportService.java | 2 +- .../impl/AssetProfileImportService.java | 2 +- .../impl/BaseEntityImportService.java | 2 +- .../importing/impl/CustomerImportService.java | 2 +- .../impl/DashboardImportService.java | 2 +- .../importing/impl/DeviceImportService.java | 2 +- .../impl/DeviceProfileImportService.java | 2 +- .../impl/EntityViewImportService.java | 2 +- .../impl/ImportServiceException.java | 2 +- .../impl/MissingEntityException.java | 2 +- .../impl/NotificationRuleImportService.java | 2 +- .../impl/NotificationTargetImportService.java | 9 +- .../NotificationTemplateImportService.java | 2 +- .../importing/impl/ResourceImportService.java | 93 + .../impl/RuleChainImportService.java | 3 +- .../impl/WidgetTypeImportService.java | 6 +- .../impl/WidgetsBundleImportService.java | 2 +- .../DefaultEntitiesVersionControlService.java | 54 +- .../DefaultGitVersionControlQueueService.java | 174 +- .../vc/EntitiesVersionControlService.java | 2 +- .../vc/GitVersionControlQueueService.java | 2 +- .../service/sync/vc/LoadEntityException.java | 2 +- ...AbstractVersionControlSettingsService.java | 2 +- .../sync/vc/VersionControlTaskCacheEntry.java | 2 +- .../vc/VersionControlTaskCaffeineCache.java | 2 +- .../sync/vc/VersionControlTaskRedisCache.java | 2 +- .../AutoCommitSettingsCaffeineCache.java | 2 +- .../AutoCommitSettingsRedisCache.java | 2 +- .../DefaultTbAutoCommitSettingsService.java | 2 +- .../TbAutoCommitSettingsService.java | 2 +- .../vc/data/ClearRepositoryGitRequest.java | 2 +- .../sync/vc/data/CommitGitRequest.java | 2 +- .../vc/data/ComplexEntitiesExportCtx.java | 2 +- .../sync/vc/data/ContentsDiffGitRequest.java | 2 +- .../vc/data/EntitiesContentGitRequest.java | 2 +- .../sync/vc/data/EntitiesExportCtx.java | 2 +- .../sync/vc/data/EntitiesImportCtx.java | 2 +- .../sync/vc/data/EntityContentGitRequest.java | 2 +- .../sync/vc/data/EntityTypeExportCtx.java | 2 +- .../sync/vc/data/ListBranchesGitRequest.java | 2 +- .../sync/vc/data/ListEntitiesGitRequest.java | 2 +- .../sync/vc/data/ListVersionsGitRequest.java | 2 +- .../sync/vc/data/PendingGitRequest.java | 2 +- .../service/sync/vc/data/ReimportTask.java | 2 +- .../sync/vc/data/SimpleEntitiesExportCtx.java | 2 +- .../sync/vc/data/VersionsDiffGitRequest.java | 2 +- .../service/sync/vc/data/VoidGitRequest.java | 2 +- .../DefaultTbRepositorySettingsService.java | 2 +- .../RepositorySettingsCaffeineCache.java | 2 +- .../RepositorySettingsRedisCache.java | 2 +- .../TbRepositorySettingsService.java | 2 +- .../system/DefaultSystemInfoService.java | 2 +- .../service/system/SystemInfoService.java | 2 +- .../AbstractSubscriptionService.java | 2 +- .../telemetry/AlarmSubscriptionService.java | 2 +- .../service/telemetry/AttributeData.java | 2 +- .../DefaultAlarmSubscriptionService.java | 2 +- .../DefaultTelemetrySubscriptionService.java | 2 +- .../telemetry/InternalTelemetryService.java | 2 +- .../TelemetrySubscriptionService.java | 2 +- .../server/service/telemetry/TsData.java | 2 +- .../BasicCredentialsValidationResult.java | 2 +- .../DefaultTbCoreToTransportService.java | 2 +- .../transport/DefaultTransportApiService.java | 18 +- .../transport/TbCoreToTransportService.java | 2 +- .../transport/TbCoreTransportApiService.java | 2 +- .../transport/TransportApiService.java | 2 +- .../msg/TransportToDeviceActorMsgWrapper.java | 2 +- .../service/ttl/AbstractCleanUpService.java | 2 +- .../service/ttl/AlarmsCleanUpService.java | 2 +- .../service/ttl/AuditLogsCleanUpService.java | 2 +- .../service/ttl/EdgeEventsCleanUpService.java | 2 +- .../service/ttl/EventsCleanUpService.java | 2 +- .../ttl/NotificationsCleanUpService.java | 2 +- .../service/ttl/TimeseriesCleanUpService.java | 2 +- .../service/ttl/rpc/RpcCleanUpService.java | 2 +- .../service/update/DefaultUpdateService.java | 22 +- .../server/service/update/UpdateService.java | 2 +- .../server/service/ws/AuthCmd.java | 19 +- .../service/ws/DefaultWebSocketService.java | 412 +- .../server/service/ws/SessionEvent.java | 2 +- .../service/ws/WebSocketMsgEndpoint.java | 2 +- .../server/service/ws/WebSocketService.java | 13 +- .../service/ws/WebSocketSessionRef.java | 24 +- .../service/ws/WebSocketSessionType.java | 20 +- .../thingsboard/server/service/ws/WsCmd.java | 28 + .../server/service/ws/WsCmdType.java | 39 + .../server/service/ws/WsCommandsWrapper.java | 71 + .../server/service/ws/WsSessionMetaData.java | 2 +- .../DefaultNotificationCommandsHandler.java | 4 +- .../NotificationCommandsHandler.java | 2 +- .../cmd/MarkAllNotificationsAsReadCmd.java | 9 +- .../cmd/MarkNotificationsAsReadCmd.java | 9 +- .../cmd/NotificationCmdsWrapper.java | 21 +- .../cmd/NotificationsCountSubCmd.java | 9 +- .../notification/cmd/NotificationsSubCmd.java | 9 +- .../cmd/NotificationsUnsubCmd.java | 9 +- .../cmd/UnreadNotificationsCountUpdate.java | 7 +- .../cmd/UnreadNotificationsUpdate.java | 7 +- .../sub/NotificationRequestUpdate.java | 2 +- .../notification/sub/NotificationUpdate.java | 2 +- .../sub/NotificationsCountSubscription.java | 3 +- .../sub/NotificationsSubscription.java | 5 +- .../sub/NotificationsSubscriptionUpdate.java | 2 +- .../ws/telemetry/TelemetryFeature.java | 2 +- .../telemetry/TelemetryWebSocketTextMsg.java | 2 +- ...Wrapper.java => TelemetryCmdsWrapper.java} | 28 +- .../cmd/v1/AttributesSubscriptionCmd.java | 8 +- .../ws/telemetry/cmd/v1/GetHistoryCmd.java | 7 +- .../ws/telemetry/cmd/v1/SubscriptionCmd.java | 4 +- .../telemetry/cmd/v1/TelemetryPluginCmd.java | 6 +- .../cmd/v1/TimeseriesSubscriptionCmd.java | 10 +- .../ws/telemetry/cmd/v2/AggHistoryCmd.java | 2 +- .../service/ws/telemetry/cmd/v2/AggKey.java | 2 +- .../ws/telemetry/cmd/v2/AggTimeSeriesCmd.java | 2 +- .../ws/telemetry/cmd/v2/AlarmCountCmd.java | 8 +- .../cmd/v2/AlarmCountUnsubscribeCmd.java | 7 +- .../ws/telemetry/cmd/v2/AlarmCountUpdate.java | 2 +- .../ws/telemetry/cmd/v2/AlarmDataCmd.java | 8 +- .../cmd/v2/AlarmDataUnsubscribeCmd.java | 7 +- .../ws/telemetry/cmd/v2/AlarmDataUpdate.java | 2 +- .../ws/telemetry/cmd/v2/CmdUpdate.java | 2 +- .../ws/telemetry/cmd/v2/CmdUpdateType.java | 2 +- .../service/ws/telemetry/cmd/v2/DataCmd.java | 5 +- .../ws/telemetry/cmd/v2/DataUpdate.java | 2 +- .../ws/telemetry/cmd/v2/EntityCountCmd.java | 8 +- .../cmd/v2/EntityCountUnsubscribeCmd.java | 7 +- .../telemetry/cmd/v2/EntityCountUpdate.java | 2 +- .../ws/telemetry/cmd/v2/EntityDataCmd.java | 7 +- .../cmd/v2/EntityDataUnsubscribeCmd.java | 7 +- .../ws/telemetry/cmd/v2/EntityDataUpdate.java | 2 +- .../ws/telemetry/cmd/v2/EntityHistoryCmd.java | 5 +- .../service/ws/telemetry/cmd/v2/GetTsCmd.java | 20 +- .../ws/telemetry/cmd/v2/LatestValueCmd.java | 2 +- .../ws/telemetry/cmd/v2/TimeSeriesCmd.java | 5 +- .../ws/telemetry/cmd/v2/UnsubscribeCmd.java | 6 +- .../sub/AlarmSubscriptionUpdate.java | 2 +- .../ws/telemetry/sub/SubscriptionState.java | 2 +- .../sub/TelemetrySubscriptionUpdate.java | 2 +- ...ngfoxHandlerProviderBeanPostProcessor.java | 2 +- .../thingsboard/server/utils/CsvUtils.java | 2 +- .../server/utils/LwM2mObjectModelUtils.java | 12 +- .../thingsboard/server/utils/MiscUtils.java | 2 +- .../server/utils/TbNodeUpgradeUtils.java | 57 +- application/src/main/resources/logback.xml | 2 +- .../templates/2fa.verification.code.ftl | 2 +- .../resources/templates/account.activated.ftl | 2 +- .../resources/templates/account.lockout.ftl | 2 +- .../main/resources/templates/activation.ftl | 2 +- .../templates/password.was.reset.ftl | 2 +- .../resources/templates/reset.password.ftl | 2 +- .../resources/templates/state.disabled.ftl | 2 +- .../resources/templates/state.enabled.ftl | 2 +- .../resources/templates/state.warning.ftl | 2 +- .../src/main/resources/templates/test.ftl | 2 +- .../src/main/resources/thingsboard.yml | 48 +- .../DeviceActorMessageProcessorTest.java | 2 +- .../server/actors/stats/StatsActorTest.java | 2 +- .../actors/stats/StatsPersistMsgTest.java | 2 +- ...CaffeineCacheDefaultConfigurationTest.java | 2 +- .../controller/AbstractControllerTest.java | 15 +- .../AbstractInMemoryStorageTest.java | 2 +- .../controller/AbstractNotifyEntityTest.java | 14 +- .../AbstractRuleEngineControllerTest.java | 2 +- .../server/controller/AbstractWebTest.java | 4 +- .../controller/AdminControllerTest.java | 2 +- .../AlarmCommentControllerTest.java | 2 +- .../controller/AlarmControllerTest.java | 8 +- .../controller/AssetControllerTest.java | 2 +- .../AssetProfileControllerTest.java | 61 +- .../controller/AuditLogControllerTest.java | 2 +- .../server/controller/AuthControllerTest.java | 85 +- .../controller/BaseQueueControllerTest.java | 2 +- .../ComponentDescriptorControllerTest.java | 2 +- .../controller/CustomerControllerTest.java | 2 +- .../controller/DashboardControllerTest.java | 23 +- .../DeviceConnectivityControllerTest.java | 452 +- .../controller/DeviceControllerTest.java | 33 +- .../DeviceProfileControllerTest.java | 61 +- .../server/controller/EdgeControllerTest.java | 221 +- .../controller/EdgeEventControllerTest.java | 2 +- .../controller/EntityQueryControllerTest.java | 2 +- .../EntityRelationControllerTest.java | 2 +- .../controller/EntityViewControllerTest.java | 2 +- .../server/controller/HomePageApiTest.java | 9 +- .../controller/ImageControllerTest.java | 337 + .../controller/OtaPackageControllerTest.java | 2 +- .../server/controller/RpcControllerTest.java | 2 +- .../controller/RuleChainControllerTest.java | 2 +- .../controller/TbResourceControllerTest.java | 120 +- .../controller/TbTestWebSocketClient.java | 45 +- .../controller/TelemetryControllerTest.java | 63 +- .../controller/TenantControllerTest.java | 2 +- .../TenantProfileControllerTest.java | 2 +- .../controller/TwoFactorAuthConfigTest.java | 2 +- .../server/controller/TwoFactorAuthTest.java | 2 +- .../server/controller/UserControllerTest.java | 2 +- .../server/controller/WebsocketApiTest.java | 9 +- .../controller/WidgetTypeControllerTest.java | 28 +- .../WidgetsBundleControllerTest.java | 2 +- .../plugin/TbWebSocketHandlerTest.java | 31 +- .../server/edge/AbstractEdgeTest.java | 74 +- .../server/edge/AlarmEdgeTest.java | 186 +- .../server/edge/AssetEdgeTest.java | 69 +- .../server/edge/AssetProfileEdgeTest.java | 61 +- .../server/edge/CustomerEdgeTest.java | 13 +- .../server/edge/DashboardEdgeTest.java | 65 +- .../server/edge/DeviceEdgeTest.java | 206 +- .../server/edge/DeviceProfileEdgeTest.java | 110 +- .../org/thingsboard/server/edge/EdgeTest.java | 8 +- .../server/edge/EntityViewEdgeTest.java | 80 +- .../server/edge/OtaPackageEdgeTest.java | 65 +- .../server/edge/QueueEdgeTest.java | 39 +- .../server/edge/RelationEdgeTest.java | 87 +- .../server/edge/ResourceEdgeTest.java | 66 +- .../server/edge/RuleChainEdgeTest.java | 34 +- .../server/edge/TelemetryEdgeTest.java | 2 +- .../server/edge/TenantEdgeTest.java | 33 +- .../server/edge/TenantProfileEdgeTest.java | 26 +- .../thingsboard/server/edge/UserEdgeTest.java | 65 +- .../server/edge/WidgetEdgeTest.java | 30 +- .../server/edge/imitator/EdgeImitator.java | 8 +- .../discovery/HashPartitionServiceTest.java | 2 +- ...AbstractRuleEngineFlowIntegrationTest.java | 2 +- .../sql/RuleEngineFlowSqlIntegrationTest.java | 2 +- ...actRuleEngineLifecycleIntegrationTest.java | 2 +- ...RuleEngineLifecycleSqlIntegrationTest.java | 2 +- .../DefaultTbApiUsageStateServiceTest.java | 2 +- .../provision/DeviceProvisionServiceTest.java | 2 +- .../RuleChainMsgConstructorTest.java | 17 +- .../rpc/processor/BaseEdgeProcessorTest.java | 294 +- .../asset/AbstractAssetProcessorTest.java | 2 +- .../asset/AssetEdgeProcessorTest.java | 10 +- .../asset/AssetProfileEdgeProcessorTest.java | 9 +- .../device/AbstractDeviceProcessorTest.java | 2 +- .../device/DeviceEdgeProcessorTest.java | 10 +- .../DeviceProfileEdgeProcessorTest.java | 11 +- .../telemetry/TelemetryEdgeProcessorTest.java | 2 +- .../alarm/DefaultTbAlarmServiceTest.java | 2 +- .../DefaultTbAlarmCommentServiceTest.java | 2 +- .../service/install/InstallScriptsTest.java | 5 +- .../SqlEntityDatabaseSchemaServiceTest.java | 2 +- .../update/DefaultDataUpdateServiceTest.java | 2 +- .../service/limits/RateLimitServiceTest.java | 2 +- .../server/service/mail/TbMailSenderTest.java | 2 +- .../AbstractNotificationApiTest.java | 5 +- .../notification/NotificationApiTest.java | 19 +- .../notification/NotificationApiWsClient.java | 28 +- .../notification/NotificationRuleApiTest.java | 2 +- .../NotificationTargetApiTest.java | 2 +- .../NotificationTemplateApiTest.java | 2 +- .../TestNotificationSettingsService.java | 2 +- .../queue/DefaultTbClusterServiceTest.java | 7 +- .../service/queue/TbMsgPackCallbackTest.java | 2 +- .../queue/TbMsgPackProcessingContextTest.java | 2 +- .../TbRuleEngineQueueConsumerManagerTest.java | 2 +- .../sql/BaseTbResourceServiceTest.java | 92 +- .../service/rpc/RpcSubmitStrategyTest.java | 2 +- .../service/script/MockJsInvokeService.java | 2 +- .../script/NashornJsInvokeServiceTest.java | 2 +- .../script/RemoteJsInvokeServiceTest.java | 2 +- .../service/script/TbelInvokeServiceTest.java | 2 +- .../security/auth/JwtTokenFactoryTest.java | 10 +- .../security/auth/TokenOutdatingTest.java | 6 +- .../security/auth/oauth2/CookieUtilsTest.java | 2 +- ...auth2AuthenticationSuccessHandlerTest.java | 2 +- .../service/sms/DefaultSmsServiceTest.java | 2 +- .../service/sms/smpp/SmppSmsSenderTest.java | 2 +- .../SequentialTimeseriesPersistenceTest.java | 2 +- .../state/DefaultDeviceStateServiceTest.java | 2 +- .../service/stats/DevicesStatisticsTest.java | 2 +- .../sync/ie/BaseExportImportServiceTest.java | 2 +- .../sync/ie/ExportImportServiceSqlTest.java | 2 +- .../DefaultTransportApiServiceTest.java | 6 +- .../service/ttl/AlarmsCleanUpServiceTest.java | 2 +- .../service/ttl/EventsCleanUpServiceTest.java | 2 +- .../server/system/BaseHttpDeviceApiTest.java | 2 +- .../server/system/BaseRestApiLimitsTest.java | 2 +- .../system/RestTemplateConvertersTest.java | 2 +- .../server/system/sql/DeviceApiSqlTest.java | 2 +- .../system/sql/RestApiLimitsSqlTest.java | 2 +- .../AbstractTransportIntegrationTest.java | 2 +- .../transport/TransportNoSqlTestSuite.java | 2 +- .../coap/AbstractCoapIntegrationTest.java | 2 +- .../transport/coap/CoapTestCallback.java | 8 +- .../server/transport/coap/CoapTestClient.java | 34 +- .../coap/CoapTestConfigProperties.java | 2 +- ...AbstractCoapAttributesIntegrationTest.java | 2 +- .../CoapAttributesRequestIntegrationTest.java | 2 +- ...pAttributesRequestJsonIntegrationTest.java | 2 +- ...AttributesRequestProtoIntegrationTest.java | 2 +- .../CoapAttributesUpdatesIntegrationTest.java | 2 +- ...pAttributesUpdatesJsonIntegrationTest.java | 2 +- ...AttributesUpdatesProtoIntegrationTest.java | 2 +- .../coap/claim/CoapClaimDeviceTest.java | 2 +- .../coap/claim/CoapClaimJsonDeviceTest.java | 2 +- .../coap/claim/CoapClaimProtoDeviceTest.java | 2 +- .../client/CoapClientIntegrationTest.java | 309 + .../CoapProvisionJsonDeviceTest.java | 2 +- .../CoapProvisionProtoDeviceTest.java | 2 +- ...tractCoapServerSideRpcIntegrationTest.java | 2 +- ...apServerSideRpcDefaultIntegrationTest.java | 2 +- .../CoapServerSideRpcJsonIntegrationTest.java | 2 +- ...CoapServerSideRpcProtoIntegrationTest.java | 2 +- .../CoapAttributesIntegrationTest.java | 2 +- .../CoapAttributesJsonIntegrationTest.java | 2 +- .../CoapAttributesProtoIntegrationTest.java | 2 +- ...AbstractCoapTimeseriesIntegrationTest.java | 2 +- ...ractCoapTimeseriesJsonIntegrationTest.java | 2 +- ...actCoapTimeseriesProtoIntegrationTest.java | 2 +- .../CoapTimeseriesNoSqlIntegrationTest.java | 2 +- ...oapTimeseriesNoSqlJsonIntegrationTest.java | 2 +- ...apTimeseriesNoSqlProtoIntegrationTest.java | 2 +- .../sql/CoapTimeseriesSqlIntegrationTest.java | 2 +- .../CoapTimeseriesSqlJsonIntegrationTest.java | 2 +- ...CoapTimeseriesSqlProtoIntegrationTest.java | 2 +- .../lwm2m/AbstractLwM2MIntegrationTest.java | 11 +- .../transport/lwm2m/Lwm2mTestHelper.java | 2 +- .../transport/lwm2m/client/FwLwM2MDevice.java | 2 +- .../lwm2m/client/LwM2MLocationParams.java | 2 +- .../lwm2m/client/LwM2MTestClient.java | 2 +- .../client/LwM2mBinaryAppDataContainer.java | 2 +- .../transport/lwm2m/client/LwM2mLocation.java | 2 +- .../lwm2m/client/LwM2mTemperatureSensor.java | 2 +- .../transport/lwm2m/client/Lwm2mServer.java | 2 +- .../lwm2m/client/SimpleLwM2MDevice.java | 2 +- .../transport/lwm2m/client/SwLwM2MDevice.java | 2 +- .../ota/AbstractOtaLwM2MIntegrationTest.java | 2 +- .../ota/sql/OtaLwM2MIntegrationTest.java | 2 +- .../rpc/AbstractRpcLwM2MIntegrationTest.java | 2 +- .../sql/RpcLwm2mIntegrationCreateTest.java | 2 +- .../sql/RpcLwm2mIntegrationDeleteTest.java | 2 +- .../sql/RpcLwm2mIntegrationDiscoverTest.java | 2 +- .../sql/RpcLwm2mIntegrationExecuteTest.java | 2 +- .../sql/RpcLwm2mIntegrationObserveTest.java | 2 +- .../rpc/sql/RpcLwm2mIntegrationReadTest.java | 2 +- ...pcLwm2mIntegrationWriteAttributesTest.java | 2 +- .../rpc/sql/RpcLwm2mIntegrationWriteTest.java | 2 +- .../AbstractSecurityLwM2MIntegrationTest.java | 2 +- .../sql/NoSecLwM2MIntegrationTest.java | 2 +- .../security/sql/PskLwm2mIntegrationTest.java | 2 +- .../security/sql/RpkLwM2MIntegrationTest.java | 2 +- .../sql/X509_NoTrustLwM2MIntegrationTest.java | 2 +- .../sql/X509_TrustLwM2MIntegrationTest.java | 2 +- .../LwM2mTransportServerHelperTest.java | 2 +- .../mqtt/AbstractMqttIntegrationTest.java | 2 +- .../mqtt/MqttTestConfigProperties.java | 2 +- .../mqtt/mqttv3/MqttTestCallback.java | 2 +- .../transport/mqtt/mqttv3/MqttTestClient.java | 2 +- .../MqttTestSubscribeOnTopicCallback.java | 2 +- ...AbstractMqttAttributesIntegrationTest.java | 2 +- ...tBackwardCompatibilityIntegrationTest.java | 2 +- .../MqttAttributesRequestIntegrationTest.java | 2 +- ...tAttributesRequestJsonIntegrationTest.java | 2 +- ...AttributesRequestProtoIntegrationTest.java | 2 +- ...sBackwardCompatibilityIntegrationTest.java | 2 +- .../MqttAttributesUpdatesIntegrationTest.java | 2 +- ...tAttributesUpdatesJsonIntegrationTest.java | 2 +- ...AttributesUpdatesProtoIntegrationTest.java | 2 +- ...tClaimBackwardCompatibilityDeviceTest.java | 2 +- .../mqttv3/claim/MqttClaimDeviceTest.java | 2 +- .../mqttv3/claim/MqttClaimJsonDeviceTest.java | 2 +- .../claim/MqttClaimProtoDeviceTest.java | 2 +- .../AbstractMqttClientConnectionTest.java | 2 +- .../client/MqttClientConnectionTest.java | 2 +- .../credentials/BasicMqttCredentialsTest.java | 2 +- .../MqttProvisionJsonDeviceTest.java | 2 +- .../MqttProvisionProtoDeviceTest.java | 2 +- ...tractMqttServerSideRpcIntegrationTest.java | 2 +- ...cBackwardCompatibilityIntegrationTest.java | 2 +- ...ttServerSideRpcDefaultIntegrationTest.java | 2 +- .../MqttServerSideRpcJsonIntegrationTest.java | 2 +- ...MqttServerSideRpcProtoIntegrationTest.java | 2 +- ...erSideRpcSequenceOnAckIntegrationTest.java | 2 +- ...eRpcSequenceOnResponseIntegrationTest.java | 2 +- .../MqttAttributesIntegrationTest.java | 2 +- .../MqttAttributesJsonIntegrationTest.java | 2 +- .../MqttAttributesProtoIntegrationTest.java | 2 +- ...AbstractMqttTimeseriesIntegrationTest.java | 2 +- ...ractMqttTimeseriesJsonIntegrationTest.java | 2 +- ...actMqttTimeseriesProtoIntegrationTest.java | 2 +- .../MqttTimeseriesNoSqlIntegrationTest.java | 2 +- ...qttTimeseriesNoSqlJsonIntegrationTest.java | 2 +- ...ttTimeseriesNoSqlProtoIntegrationTest.java | 2 +- .../sql/MqttTimeseriesSqlIntegrationTest.java | 2 +- .../MqttTimeseriesSqlJsonIntegrationTest.java | 2 +- ...MqttTimeseriesSqlProtoIntegrationTest.java | 2 +- .../mqtt/mqttv5/AbstractMqttV5Test.java | 2 +- .../mqtt/mqttv5/MqttV5TestCallback.java | 2 +- .../mqtt/mqttv5/MqttV5TestClient.java | 2 +- .../AbstractAttributesMqttV5Test.java | 2 +- .../updates/AttributesUpdatesTest.java | 2 +- .../upload/AttributesPublishTest.java | 2 +- .../mqttv5/claim/AbstractMqttV5ClaimTest.java | 2 +- .../mqtt/mqttv5/claim/MqttV5ClaimTest.java | 2 +- .../AbstractMqttV5ClientConnectionTest.java | 2 +- .../MqttV5ClientConnectionTest.java | 2 +- .../AbstractMqttV5ClientPublishTest.java | 2 +- .../publish/MqttV5ClientPublishTest.java | 2 +- .../AbstractMqttV5ClientSubscriptionTest.java | 2 +- .../MqttV5ClientSubscriptionTest.java | 2 +- .../AbstractMqttV5ClientUnsubscribeTest.java | 2 +- .../MqttV5ClientUnsubscribeTest.java | 2 +- .../provision/MqttV5ProvisionDeviceTest.java | 2 +- .../mqttv5/rpc/AbstractMqttV5RpcTest.java | 2 +- .../mqtt/mqttv5/rpc/MqttV5RpcTest.java | 2 +- .../AbstractMqttV5TimeseriesTest.java | 2 +- .../timeseries/MqttV5TimeseriesTest.java | 2 +- .../AbstractMqttV5ClientSparkplugTest.java | 2 +- ...ctMqttV5ClientSparkplugAttributesTest.java | 2 +- ...ientSparkplugBAttributesInProfileTest.java | 4 +- .../MqttV5ClientSparkplugBAttributesTest.java | 4 +- ...ctMqttV5ClientSparkplugConnectionTest.java | 2 +- .../MqttV5ClientSparkplugBConnectionTest.java | 2 +- .../rpc/AbstractMqttV5RpcSparkplugTest.java | 2 +- .../sparkplug/rpc/MqttV5RpcSparkplugTest.java | 2 +- ...actMqttV5ClientSparkplugTelemetryTest.java | 2 +- .../MqttV5ClientSparkplugBTelemetryTest.java | 2 +- .../server/utils/TbNodeUpgradeUtilsTest.java | 61 +- build_proto.sh | 2 +- common/actor/pom.xml | 4 +- .../server/actors/AbstractTbActor.java | 2 +- .../server/actors/DefaultTbActorSystem.java | 2 +- .../thingsboard/server/actors/Dispatcher.java | 2 +- .../server/actors/InitFailureStrategy.java | 2 +- .../server/actors/JsInvokeStats.java | 2 +- .../server/actors/ProcessFailureStrategy.java | 2 +- .../thingsboard/server/actors/TbActor.java | 2 +- .../server/actors/TbActorCreator.java | 2 +- .../thingsboard/server/actors/TbActorCtx.java | 2 +- .../server/actors/TbActorException.java | 2 +- .../thingsboard/server/actors/TbActorId.java | 2 +- .../server/actors/TbActorMailbox.java | 2 +- .../actors/TbActorNotRegisteredException.java | 2 +- .../thingsboard/server/actors/TbActorRef.java | 2 +- .../server/actors/TbActorSystem.java | 2 +- .../server/actors/TbActorSystemSettings.java | 2 +- .../server/actors/TbEntityActorId.java | 2 +- .../actors/TbRuleNodeUpdateException.java | 2 +- .../server/actors/TbStringActorId.java | 2 +- .../server/actors/ActorSystemTest.java | 2 +- .../server/actors/ActorTestCtx.java | 2 +- .../server/actors/FailedToInitActor.java | 2 +- .../server/actors/IntTbActorMsg.java | 2 +- .../server/actors/SlowCreateActor.java | 2 +- .../server/actors/SlowInitActor.java | 2 +- .../server/actors/TestRootActor.java | 2 +- common/cache/pom.xml | 4 +- .../thingsboard/server/cache/CacheSpecs.java | 2 +- .../server/cache/CacheSpecsMap.java | 2 +- .../cache/CaffeineTbCacheTransaction.java | 2 +- .../cache/CaffeineTbTransactionalCache.java | 2 +- .../server/cache/RedisTbCacheTransaction.java | 2 +- .../cache/RedisTbTransactionalCache.java | 18 +- .../cache/SimpleTbCacheValueWrapper.java | 2 +- .../cache/TBRedisCacheConfiguration.java | 2 +- .../cache/TBRedisClusterConfiguration.java | 2 +- .../cache/TBRedisSentinelConfiguration.java | 2 +- .../cache/TBRedisStandaloneConfiguration.java | 2 +- .../server/cache/TbCacheTransaction.java | 2 +- .../server/cache/TbCacheValueWrapper.java | 2 +- .../cache/TbCaffeineCacheConfiguration.java | 2 +- .../server/cache/TbFSTRedisSerializer.java | 2 +- .../server/cache/TbRedisSerializer.java | 2 +- .../server/cache/TbTransactionalCache.java | 27 +- .../cache/device/DeviceCacheEvictEvent.java | 2 +- .../server/cache/device/DeviceCacheKey.java | 2 +- .../cache/device/DeviceCaffeineCache.java | 2 +- .../server/cache/device/DeviceRedisCache.java | 2 +- .../cache/ota/CaffeineOtaPackageCache.java | 2 +- .../server/cache/ota/OtaPackageDataCache.java | 2 +- .../cache/ota/RedisOtaPackageDataCache.java | 2 +- .../resourceInfo/ResourceInfoCacheKey.java | 2 +- .../ResourceInfoCaffeineCache.java | 2 +- .../resourceInfo/ResourceInfoEvictEvent.java | 2 +- .../resourceInfo/ResourceInfoRedisCache.java | 2 +- ...UsersSessionInvalidationCaffeineCache.java | 2 +- .../UsersSessionInvalidationRedisCache.java | 2 +- .../server/cache/CacheSpecsMapTest.java | 2 +- common/cluster-api/pom.xml | 8 +- .../server/cluster/TbClusterService.java | 6 +- .../server/queue/TbQueueAdmin.java | 2 +- .../server/queue/TbQueueCallback.java | 2 +- .../server/queue/TbQueueClusterService.java | 2 +- .../server/queue/TbQueueConsumer.java | 2 +- .../server/queue/TbQueueHandler.java | 2 +- .../thingsboard/server/queue/TbQueueMsg.java | 2 +- .../server/queue/TbQueueMsgDecoder.java | 2 +- .../server/queue/TbQueueMsgHeaders.java | 2 +- .../server/queue/TbQueueMsgMetadata.java | 2 +- .../server/queue/TbQueueProducer.java | 2 +- .../server/queue/TbQueueRequestTemplate.java | 2 +- .../server/queue/TbQueueResponseTemplate.java | 2 +- common/coap-server/pom.xml | 4 +- .../server/coapserver/CoapServerContext.java | 2 +- .../server/coapserver/CoapServerService.java | 2 +- .../coapserver/DefaultCoapServerService.java | 2 +- .../TbCoapDtlsCertificateVerifier.java | 2 +- .../TbCoapDtlsSessionInMemoryStorage.java | 2 +- .../coapserver/TbCoapDtlsSessionInfo.java | 2 +- .../server/coapserver/TbCoapDtlsSettings.java | 2 +- .../coapserver/TbCoapServerComponent.java | 2 +- .../TbCoapServerMessageDeliverer.java | 2 +- common/dao-api/pom.xml | 4 +- .../server/dao/alarm/AlarmCommentService.java | 3 +- .../server/dao/alarm/AlarmService.java | 2 +- .../server/dao/asset/AssetProfileService.java | 11 +- .../server/dao/asset/AssetService.java | 3 +- .../dao/attributes/AttributesService.java | 2 +- .../server/dao/audit/AuditLogService.java | 2 +- .../cassandra/AbstractCassandraCluster.java | 2 +- .../dao/cassandra/CassandraCluster.java | 2 +- .../dao/cassandra/CassandraDriverOptions.java | 2 +- .../cassandra/CassandraInstallCluster.java | 2 +- .../cassandra/guava/DefaultGuavaSession.java | 2 +- .../cassandra/guava/GuavaDriverContext.java | 2 +- .../guava/GuavaMultiPageResultSet.java | 2 +- .../guava/GuavaRequestAsyncProcessor.java | 2 +- .../dao/cassandra/guava/GuavaSession.java | 2 +- .../cassandra/guava/GuavaSessionBuilder.java | 2 +- .../cassandra/guava/GuavaSessionUtils.java | 2 +- .../component/ComponentDescriptorService.java | 2 +- .../server/dao/customer/CustomerService.java | 2 +- .../dao/dashboard/DashboardService.java | 4 +- .../dao/device/ClaimDevicesService.java | 2 +- .../dao/device/DeviceConnectivityService.java | 6 +- .../dao/device/DeviceCredentialsService.java | 2 +- .../dao/device/DeviceProfileService.java | 11 +- .../dao/device/DeviceProvisionService.java | 2 +- .../server/dao/device/DeviceService.java | 3 +- .../server/dao/device/claim/ClaimData.java | 2 +- .../dao/device/claim/ClaimResponse.java | 2 +- .../server/dao/device/claim/ClaimResult.java | 2 +- .../dao/device/claim/ReclaimResult.java | 2 +- .../provision/ProvisionFailedException.java | 2 +- .../device/provision/ProvisionRequest.java | 2 +- .../device/provision/ProvisionResponse.java | 2 +- .../provision/ProvisionResponseStatus.java | 2 +- .../server/dao/edge/EdgeEventService.java | 2 +- .../server/dao/edge/EdgeService.java | 2 +- .../dao/edge/EdgeSynchronizationManager.java | 2 +- .../server/dao/entity/EntityCountService.java | 2 +- .../server/dao/entity/EntityDaoService.java | 2 +- .../server/dao/entity/EntityService.java | 2 +- .../dao/entity/EntityServiceRegistry.java | 2 +- .../dao/entityview/EntityViewService.java | 4 +- .../server/dao/event/EventService.java | 2 +- .../dao/housekeeper/HouseKeeperService.java | 2 +- .../dao/nosql/CassandraStatementTask.java | 2 +- .../server/dao/nosql/TbResultSet.java | 2 +- .../server/dao/nosql/TbResultSetFuture.java | 2 +- .../NotificationRequestService.java | 2 +- .../notification/NotificationRuleService.java | 2 +- .../dao/notification/NotificationService.java | 2 +- .../NotificationSettingsService.java | 2 +- .../NotificationTargetService.java | 2 +- .../NotificationTemplateService.java | 2 +- .../oauth2/OAuth2ConfigTemplateService.java | 2 +- .../server/dao/oauth2/OAuth2Service.java | 2 +- .../server/dao/oauth2/OAuth2User.java | 2 +- .../server/dao/ota/OtaPackageService.java | 2 +- .../server/dao/queue/QueueService.java | 2 +- .../server/dao/relation/RelationService.java | 2 +- .../server/dao/resource/ImageService.java | 68 + .../server/dao/resource/ResourceService.java | 9 +- .../server/dao/rpc/RpcService.java | 2 +- .../server/dao/rule/RuleChainService.java | 3 +- .../server/dao/rule/RuleNodeStateService.java | 2 +- .../dao/settings/AdminSettingsService.java | 2 +- .../dao/tenant/TbTenantProfileCache.java | 2 +- .../dao/tenant/TenantProfileService.java | 2 +- .../server/dao/tenant/TenantService.java | 2 +- .../dao/timeseries/TimeseriesService.java | 2 +- .../server/dao/usage/UsageInfoService.java | 2 +- .../dao/usagerecord/ApiLimitService.java | 2 +- .../dao/usagerecord/ApiUsageStateService.java | 2 +- .../server/dao/user/UserService.java | 2 +- .../server/dao/user/UserSettingsService.java | 2 +- .../server/dao/util/AsyncTask.java | 2 +- .../server/dao/util/DbTypeInfoComponent.java | 2 +- .../dao/util/DefaultDbTypeInfoComponent.java | 2 +- .../server/dao/util/NoSqlAnyDao.java | 2 +- .../server/dao/util/NoSqlAnyDaoNonCloud.java | 2 +- .../server/dao/util/NoSqlTsDao.java | 2 +- .../server/dao/util/NoSqlTsLatestDao.java | 2 +- .../thingsboard/server/dao/util/SqlDao.java | 2 +- .../thingsboard/server/dao/util/SqlTsDao.java | 2 +- .../server/dao/util/SqlTsLatestAnyDao.java | 2 +- .../server/dao/util/SqlTsLatestDao.java | 2 +- .../dao/util/SqlTsOrTsLatestAnyDao.java | 2 +- .../server/dao/util/TbAutoConfiguration.java | 2 +- .../server/dao/util/TimescaleDBTsDao.java | 2 +- .../dao/util/TimescaleDBTsLatestDao.java | 2 +- .../dao/util/TimescaleDBTsOrTsLatestDao.java | 2 +- .../server/dao/widget/WidgetTypeService.java | 2 +- .../dao/widget/WidgetsBundleService.java | 2 +- common/data/pom.xml | 4 +- .../server/common/data/AdminSettings.java | 2 +- .../server/common/data/ApiFeature.java | 2 +- .../server/common/data/ApiUsageRecordKey.java | 2 +- .../common/data/ApiUsageRecordState.java | 2 +- .../server/common/data/ApiUsageState.java | 2 +- .../common/data/ApiUsageStateValue.java | 2 +- .../server/common/data/BaseData.java | 2 +- .../data/BaseDataWithAdditionalInfo.java | 2 +- .../server/common/data/CacheConstants.java | 2 +- .../server/common/data/ClaimRequest.java | 2 +- .../server/common/data/CoapDeviceType.java | 2 +- .../server/common/data/ContactBased.java | 2 +- .../server/common/data/Customer.java | 2 +- .../server/common/data/Dashboard.java | 2 +- .../server/common/data/DashboardInfo.java | 7 +- .../server/common/data/DataConstants.java | 6 +- .../server/common/data/Device.java | 2 +- .../server/common/data/DeviceIdInfo.java | 2 +- .../server/common/data/DeviceInfo.java | 2 +- .../server/common/data/DeviceInfoFilter.java | 2 +- .../server/common/data/DeviceProfile.java | 5 +- .../server/common/data/DeviceProfileInfo.java | 2 +- .../data/DeviceProfileProvisionType.java | 2 +- .../server/common/data/DeviceProfileType.java | 2 +- .../common/data/DeviceTransportType.java | 2 +- .../server/common/data/DynamicProtoUtils.java | 2 +- .../server/common/data/EdgeUpgradeInfo.java | 26 + .../common/data/EdgeUpgradeMessage.java | 33 + .../server/common/data/EdgeUtils.java | 15 +- .../server/common/data/EntityFieldsData.java | 2 +- .../server/common/data/EntityInfo.java | 2 +- .../server/common/data/EntitySubtype.java | 2 +- .../server/common/data/EntityType.java | 2 +- .../server/common/data/EntityView.java | 2 +- .../server/common/data/EntityViewInfo.java | 2 +- .../server/common/data/EventInfo.java | 2 +- .../server/common/data/ExportableEntity.java | 2 +- .../server/common/data/FSTUtils.java | 2 +- .../server/common/data/FeaturesInfo.java | 2 +- .../server/common/data/FstStatsService.java | 28 + .../server/common/data/HasAdditionalInfo.java | 2 +- .../server/common/data/HasCustomerId.java | 2 +- .../server/common/data/HasEmail.java | 2 +- .../server/common/data/HasImage.java | 24 + .../server/common/data/HasLabel.java | 2 +- .../server/common/data/HasName.java | 2 +- .../server/common/data/HasOtaPackage.java | 2 +- .../common/data/HasRuleEngineProfile.java | 2 +- .../server/common/data/HasTenantId.java | 2 +- .../server/common/data/HasTitle.java | 2 +- .../server/common/data/HomeDashboard.java | 2 +- .../server/common/data/HomeDashboardInfo.java | 2 +- .../server/common/data/ImageDescriptor.java | 30 + .../server/common/data/ImageExportData.java | 41 + .../server/common/data/OtaPackage.java | 2 +- .../server/common/data/OtaPackageInfo.java | 2 +- .../server/common/data/ResourceType.java | 19 +- .../server/common/data/ResourceUtils.java | 2 +- .../SaveDeviceWithCredentialsRequest.java | 2 +- .../data/SaveOtaPackageInfoRequest.java | 2 +- .../server/common/data/ShortCustomerInfo.java | 2 +- .../server/common/data/StringUtils.java | 6 +- .../server/common/data/SystemInfo.java | 2 +- .../server/common/data/SystemInfoData.java | 2 +- .../server/common/data/SystemParams.java | 3 +- .../common/data/TbImageDeleteResult.java | 32 + .../server/common/data/TbProperty.java | 2 +- .../server/common/data/TbResource.java | 71 +- .../server/common/data/TbResourceInfo.java | 92 +- .../common/data/TbResourceInfoFilter.java | 6 +- .../common/data/TbTransportService.java | 2 +- .../server/common/data/Tenant.java | 2 +- .../server/common/data/TenantInfo.java | 2 +- .../server/common/data/TenantProfile.java | 2 +- .../server/common/data/TenantProfileType.java | 2 +- .../common/data/TransportPayloadType.java | 2 +- .../server/common/data/UUIDConverter.java | 2 +- .../server/common/data/UpdateMessage.java | 2 +- .../server/common/data/UsageInfo.java | 2 +- .../thingsboard/server/common/data/User.java | 2 +- .../server/common/data/UserEmailInfo.java | 2 +- .../server/common/data/alarm/Alarm.java | 2 +- .../common/data/alarm/AlarmApiCallResult.java | 2 +- .../common/data/alarm/AlarmAssignee.java | 2 +- .../data/alarm/AlarmAssigneeUpdate.java | 2 +- .../common/data/alarm/AlarmComment.java | 2 +- .../common/data/alarm/AlarmCommentInfo.java | 2 +- .../common/data/alarm/AlarmCommentType.java | 2 +- .../AlarmCreateOrUpdateActiveRequest.java | 2 +- .../server/common/data/alarm/AlarmInfo.java | 2 +- .../data/alarm/AlarmModificationRequest.java | 2 +- .../data/alarm/AlarmPropagationInfo.java | 2 +- .../server/common/data/alarm/AlarmQuery.java | 2 +- .../common/data/alarm/AlarmQueryV2.java | 2 +- .../common/data/alarm/AlarmSearchStatus.java | 2 +- .../common/data/alarm/AlarmSeverity.java | 2 +- .../server/common/data/alarm/AlarmStatus.java | 2 +- .../common/data/alarm/AlarmStatusFilter.java | 2 +- .../common/data/alarm/AlarmUpdateRequest.java | 2 +- .../server/common/data/alarm/EntityAlarm.java | 2 +- .../server/common/data/asset/Asset.java | 2 +- .../server/common/data/asset/AssetInfo.java | 2 +- .../common/data/asset/AssetProfile.java | 9 +- .../common/data/asset/AssetProfileInfo.java | 2 +- .../common/data/asset/AssetSearchQuery.java | 2 +- .../common/data/audit/ActionStatus.java | 2 +- .../server/common/data/audit/ActionType.java | 2 +- .../server/common/data/audit/AuditLog.java | 2 +- .../common/data/device/DeviceSearchQuery.java | 2 +- .../credentials/BasicMqttCredentials.java | 2 +- .../ProvisionDeviceCredentialsData.java | 2 +- ...wM2MBootstrapClientCredentialWithKeys.java | 2 +- .../lwm2m/AbstractLwM2MClientCredential.java | 2 +- ...AbstractLwM2MClientSecurityCredential.java | 2 +- .../lwm2m/LwM2MBootstrapClientCredential.java | 2 +- .../LwM2MBootstrapClientCredentials.java | 2 +- .../lwm2m/LwM2MClientCredential.java | 2 +- .../lwm2m/LwM2MDeviceCredentials.java | 2 +- .../credentials/lwm2m/LwM2MSecurityMode.java | 2 +- .../lwm2m/NoSecBootstrapClientCredential.java | 2 +- .../lwm2m/NoSecClientCredential.java | 2 +- .../lwm2m/PSKBootstrapClientCredential.java | 2 +- .../lwm2m/PSKClientCredential.java | 2 +- .../lwm2m/RPKBootstrapClientCredential.java | 2 +- .../lwm2m/RPKClientCredential.java | 2 +- .../lwm2m/X509BootstrapClientCredential.java | 2 +- .../lwm2m/X509ClientCredential.java | 2 +- .../CoapDeviceTransportConfiguration.java | 2 +- .../data/DefaultDeviceConfiguration.java | 2 +- .../DefaultDeviceTransportConfiguration.java | 2 +- .../data/device/data/DeviceConfiguration.java | 2 +- .../common/data/device/data/DeviceData.java | 2 +- .../data/DeviceTransportConfiguration.java | 2 +- .../Lwm2mDeviceTransportConfiguration.java | 2 +- .../MqttDeviceTransportConfiguration.java | 2 +- .../common/data/device/data/PowerMode.java | 2 +- .../device/data/PowerSavingConfiguration.java | 2 +- .../SnmpDeviceTransportConfiguration.java | 2 +- .../data/device/profile/AlarmCondition.java | 2 +- .../device/profile/AlarmConditionFilter.java | 2 +- .../profile/AlarmConditionFilterKey.java | 2 +- .../device/profile/AlarmConditionKeyType.java | 2 +- .../device/profile/AlarmConditionSpec.java | 2 +- .../profile/AlarmConditionSpecType.java | 2 +- .../common/data/device/profile/AlarmRule.java | 2 +- .../data/device/profile/AlarmSchedule.java | 2 +- .../device/profile/AlarmScheduleType.java | 2 +- ...esDeviceProfileProvisionConfiguration.java | 2 +- .../data/device/profile/AnyTimeSchedule.java | 2 +- ...esDeviceProfileProvisionConfiguration.java | 2 +- ...apDeviceProfileTransportConfiguration.java | 2 +- .../profile/CoapDeviceTypeConfiguration.java | 2 +- .../device/profile/CustomTimeSchedule.java | 2 +- .../profile/CustomTimeScheduleItem.java | 2 +- .../DefaultCoapDeviceTypeConfiguration.java | 2 +- .../DefaultDeviceProfileConfiguration.java | 2 +- ...ltDeviceProfileTransportConfiguration.java | 2 +- .../device/profile/DeviceProfileAlarm.java | 2 +- .../profile/DeviceProfileConfiguration.java | 2 +- .../device/profile/DeviceProfileData.java | 2 +- .../DeviceProfileProvisionConfiguration.java | 2 +- .../DeviceProfileTransportConfiguration.java | 2 +- ...edDeviceProfileProvisionConfiguration.java | 2 +- .../profile/DurationAlarmConditionSpec.java | 2 +- .../EfentoCoapDeviceTypeConfiguration.java | 2 +- .../JsonTransportPayloadConfiguration.java | 2 +- ...2mDeviceProfileTransportConfiguration.java | 2 +- ...ttDeviceProfileTransportConfiguration.java | 2 +- .../data/device/profile/MqttTopics.java | 2 +- .../ProtoTransportPayloadConfiguration.java | 2 +- .../ProvisionDeviceProfileCredentials.java | 2 +- .../profile/RepeatingAlarmConditionSpec.java | 2 +- .../profile/SimpleAlarmConditionSpec.java | 2 +- ...mpDeviceProfileTransportConfiguration.java | 2 +- .../device/profile/SpecificTimeSchedule.java | 2 +- .../TransportPayloadTypeConfiguration.java | 2 +- ...ertificateChainProvisionConfiguration.java | 3 +- .../profile/lwm2m/ObjectAttributes.java | 2 +- .../profile/lwm2m/OtherConfiguration.java | 2 +- .../lwm2m/TelemetryMappingConfiguration.java | 2 +- ...bstractLwM2MBootstrapServerCredential.java | 2 +- .../LwM2MBootstrapServerCredential.java | 2 +- .../bootstrap/LwM2MServerSecurityConfig.java | 2 +- .../LwM2MServerSecurityConfigDefault.java | 2 +- .../NoSecLwM2MBootstrapServerCredential.java | 2 +- .../PSKLwM2MBootstrapServerCredential.java | 2 +- .../RPKLwM2MBootstrapServerCredential.java | 2 +- .../X509LwM2MBootstrapServerCredential.java | 2 +- .../server/common/data/edge/Edge.java | 2 +- .../server/common/data/edge/EdgeEvent.java | 4 +- .../common/data/edge/EdgeEventActionType.java | 59 +- .../common/data/edge/EdgeEventType.java | 3 +- .../server/common/data/edge/EdgeInfo.java | 2 +- ...nstructions.java => EdgeInstructions.java} | 8 +- .../common/data/edge/EdgeSearchQuery.java | 2 +- .../entityview/EntityViewSearchQuery.java | 2 +- .../common/data/event/DebugEventFilter.java | 2 +- .../server/common/data/event/ErrorEvent.java | 2 +- .../common/data/event/ErrorEventFilter.java | 2 +- .../server/common/data/event/Event.java | 2 +- .../server/common/data/event/EventFilter.java | 2 +- .../server/common/data/event/EventType.java | 2 +- .../data/event/LifeCycleEventFilter.java | 2 +- .../common/data/event/LifecycleEvent.java | 2 +- .../data/event/RuleChainDebugEvent.java | 2 +- .../data/event/RuleChainDebugEventFilter.java | 2 +- .../common/data/event/RuleNodeDebugEvent.java | 2 +- .../data/event/RuleNodeDebugEventFilter.java | 2 +- .../common/data/event/StatisticsEvent.java | 2 +- .../data/event/StatisticsEventFilter.java | 2 +- .../exception/AbstractRateLimitException.java | 2 +- .../ApiUsageLimitsExceededException.java | 2 +- .../exception/TenantNotFoundException.java | 2 +- .../TenantProfileNotFoundException.java | 2 +- .../data/exception/ThingsboardErrorCode.java | 5 +- .../data/exception/ThingsboardException.java | 2 +- .../ThingsboardKafkaClientError.java | 2 +- .../common/data/id/AdminSettingsId.java | 2 +- .../server/common/data/id/AlarmCommentId.java | 2 +- .../server/common/data/id/AlarmId.java | 2 +- .../common/data/id/ApiUsageStateId.java | 2 +- .../server/common/data/id/AssetId.java | 2 +- .../server/common/data/id/AssetProfileId.java | 2 +- .../server/common/data/id/AuditLogId.java | 2 +- .../common/data/id/ComponentDescriptorId.java | 2 +- .../server/common/data/id/CustomerId.java | 2 +- .../server/common/data/id/DashboardId.java | 2 +- .../common/data/id/DeviceCredentialsId.java | 2 +- .../server/common/data/id/DeviceId.java | 2 +- .../common/data/id/DeviceProfileId.java | 2 +- .../server/common/data/id/EdgeEventId.java | 2 +- .../server/common/data/id/EdgeId.java | 2 +- .../server/common/data/id/EntityId.java | 2 +- .../common/data/id/EntityIdDeserializer.java | 2 +- .../common/data/id/EntityIdFactory.java | 2 +- .../common/data/id/EntityIdSerializer.java | 2 +- .../server/common/data/id/EntityViewId.java | 2 +- .../server/common/data/id/EventId.java | 2 +- .../server/common/data/id/HasId.java | 2 +- .../server/common/data/id/HasUUID.java | 2 +- .../server/common/data/id/IdBased.java | 2 +- .../data/id/NameLabelAndCustomerDetails.java | 2 +- .../server/common/data/id/NodeId.java | 2 +- .../server/common/data/id/NotificationId.java | 2 +- .../common/data/id/NotificationRequestId.java | 2 +- .../common/data/id/NotificationRuleId.java | 2 +- .../common/data/id/NotificationTargetId.java | 2 +- .../data/id/NotificationTemplateId.java | 2 +- .../OAuth2ClientRegistrationTemplateId.java | 2 +- .../server/common/data/id/OAuth2DomainId.java | 2 +- .../server/common/data/id/OAuth2MobileId.java | 2 +- .../server/common/data/id/OAuth2ParamsId.java | 2 +- .../common/data/id/OAuth2RegistrationId.java | 2 +- .../server/common/data/id/OtaPackageId.java | 2 +- .../server/common/data/id/QueueId.java | 2 +- .../server/common/data/id/RpcId.java | 2 +- .../server/common/data/id/RuleChainId.java | 2 +- .../server/common/data/id/RuleNodeId.java | 2 +- .../common/data/id/RuleNodeStateId.java | 2 +- .../server/common/data/id/TbResourceId.java | 2 +- .../server/common/data/id/TenantId.java | 2 +- .../common/data/id/TenantProfileId.java | 2 +- .../server/common/data/id/UUIDBased.java | 2 +- .../common/data/id/UserAuthSettingsId.java | 2 +- .../common/data/id/UserCredentialsId.java | 8 +- .../server/common/data/id/UserId.java | 2 +- .../server/common/data/id/WidgetTypeId.java | 2 +- .../common/data/id/WidgetsBundleId.java | 2 +- .../server/common/data/kv/AggTsKvEntry.java | 2 +- .../server/common/data/kv/Aggregation.java | 2 +- .../common/data/kv/AggregationParams.java | 92 + .../server/common/data/kv/AttributeKey.java | 2 +- .../common/data/kv/AttributeKvEntry.java | 2 +- .../common/data/kv/BaseAttributeKvEntry.java | 2 +- .../common/data/kv/BaseDeleteTsKvQuery.java | 2 +- .../common/data/kv/BaseReadTsKvQuery.java | 28 +- .../server/common/data/kv/BaseTsKvQuery.java | 2 +- .../server/common/data/kv/BasicKvEntry.java | 2 +- .../server/common/data/kv/BasicTsKvEntry.java | 2 +- .../common/data/kv/BooleanDataEntry.java | 2 +- .../server/common/data/kv/DataType.java | 2 +- .../common/data/kv/DeleteTsKvQuery.java | 2 +- .../common/data/kv/DoubleDataEntry.java | 2 +- .../server/common/data/kv/IntervalType.java | 22 + .../server/common/data/kv/JsonDataEntry.java | 2 +- .../server/common/data/kv/KvEntry.java | 2 +- .../server/common/data/kv/LongDataEntry.java | 2 +- .../server/common/data/kv/ReadTsKvQuery.java | 14 +- .../common/data/kv/ReadTsKvQueryResult.java | 2 +- .../common/data/kv/StringDataEntry.java | 2 +- .../server/common/data/kv/TsKvEntry.java | 2 +- .../common/data/kv/TsKvEntryAggWrapper.java | 2 +- .../data/kv/TsKvLatestRemovingResult.java | 2 +- .../server/common/data/kv/TsKvQuery.java | 2 +- .../server/common/data/limit/LimitedApi.java | 2 +- .../common/data/lwm2m/LwM2mConstants.java | 2 +- .../common/data/lwm2m/LwM2mInstance.java | 2 +- .../server/common/data/lwm2m/LwM2mObject.java | 2 +- .../data/lwm2m/LwM2mResourceObserve.java | 2 +- .../common/data/mail/MailOauth2Provider.java | 2 +- .../server/common/data/msg/TbMsgType.java | 2 +- .../common/data/msg/TbNodeConnectionType.java | 2 +- .../notification/AlreadySentException.java | 2 +- .../data/notification/Notification.java | 2 +- .../NotificationDeliveryMethod.java | 2 +- .../notification/NotificationRequest.java | 2 +- .../NotificationRequestConfig.java | 2 +- .../notification/NotificationRequestInfo.java | 2 +- .../NotificationRequestPreview.java | 2 +- .../NotificationRequestStats.java | 2 +- .../NotificationRequestStatus.java | 2 +- .../data/notification/NotificationStatus.java | 2 +- .../data/notification/NotificationType.java | 2 +- .../info/AlarmAssignmentNotificationInfo.java | 2 +- .../info/AlarmCommentNotificationInfo.java | 2 +- .../info/AlarmNotificationInfo.java | 2 +- .../info/ApiUsageLimitNotificationInfo.java | 2 +- .../info/DeviceActivityNotificationInfo.java | 2 +- .../info/EntitiesLimitNotificationInfo.java | 2 +- .../info/EntityActionNotificationInfo.java | 2 +- .../NewPlatformVersionNotificationInfo.java | 2 +- .../notification/info/NotificationInfo.java | 2 +- .../info/RateLimitsNotificationInfo.java | 2 +- ...mponentLifecycleEventNotificationInfo.java | 2 +- .../RuleEngineOriginatedNotificationInfo.java | 12 +- .../info/RuleOriginatedNotificationInfo.java | 2 +- ...faultNotificationRuleRecipientsConfig.java | 2 +- ...latedNotificationRuleRecipientsConfig.java | 2 +- .../notification/rule/NotificationRule.java | 2 +- .../rule/NotificationRuleConfig.java | 2 +- .../rule/NotificationRuleInfo.java | 2 +- .../NotificationRuleRecipientsConfig.java | 2 +- .../rule/trigger/AlarmAssignmentTrigger.java | 2 +- .../rule/trigger/AlarmCommentTrigger.java | 2 +- .../rule/trigger/AlarmTrigger.java | 2 +- .../rule/trigger/ApiUsageLimitTrigger.java | 2 +- .../rule/trigger/DeviceActivityTrigger.java | 2 +- .../rule/trigger/EntitiesLimitTrigger.java | 2 +- .../rule/trigger/EntityActionTrigger.java | 2 +- .../trigger/NewPlatformVersionTrigger.java | 2 +- .../rule/trigger/NotificationRuleTrigger.java | 2 +- .../rule/trigger/RateLimitsTrigger.java | 2 +- ...eEngineComponentLifecycleEventTrigger.java | 2 +- ...signmentNotificationRuleTriggerConfig.java | 2 +- ...mCommentNotificationRuleTriggerConfig.java | 2 +- .../AlarmNotificationRuleTriggerConfig.java | 2 +- ...ageLimitNotificationRuleTriggerConfig.java | 2 +- ...ActivityNotificationRuleTriggerConfig.java | 2 +- ...iesLimitNotificationRuleTriggerConfig.java | 2 +- ...tyActionNotificationRuleTriggerConfig.java | 2 +- ...mVersionNotificationRuleTriggerConfig.java | 2 +- .../config/NotificationRuleTriggerConfig.java | 2 +- .../config/NotificationRuleTriggerType.java | 2 +- ...teLimitsNotificationRuleTriggerConfig.java | 2 +- ...cleEventNotificationRuleTriggerConfig.java | 2 +- .../settings/AccountNotificationSettings.java | 2 +- .../NotificationDeliveryMethodConfig.java | 2 +- .../settings/NotificationSettings.java | 2 +- ...SlackNotificationDeliveryMethodConfig.java | 2 +- .../settings/UserNotificationSettings.java | 2 +- ...icrosoftTeamsNotificationTargetConfig.java | 2 +- .../targets/NotificationRecipient.java | 2 +- .../targets/NotificationTarget.java | 2 +- .../targets/NotificationTargetConfig.java | 2 +- .../targets/NotificationTargetType.java | 2 +- .../AffectedTenantAdministratorsFilter.java | 2 +- .../targets/platform/AffectedUserFilter.java | 2 +- .../targets/platform/AllUsersFilter.java | 2 +- .../targets/platform/CustomerUsersFilter.java | 2 +- .../OriginatorEntityOwnerUsersFilter.java | 2 +- ...PlatformUsersNotificationTargetConfig.java | 2 +- .../platform/SystemAdministratorsFilter.java | 2 +- .../platform/TenantAdministratorsFilter.java | 2 +- .../targets/platform/UserListFilter.java | 2 +- .../targets/platform/UsersFilter.java | 2 +- .../targets/platform/UsersFilterType.java | 2 +- .../targets/slack/SlackConversation.java | 2 +- .../targets/slack/SlackConversationType.java | 2 +- .../slack/SlackNotificationTargetConfig.java | 2 +- .../DeliveryMethodNotificationTemplate.java | 2 +- ...ailDeliveryMethodNotificationTemplate.java | 2 +- .../notification/template/HasSubject.java | 2 +- ...amsDeliveryMethodNotificationTemplate.java | 2 +- .../template/NotificationTemplate.java | 2 +- .../template/NotificationTemplateConfig.java | 2 +- ...ackDeliveryMethodNotificationTemplate.java | 2 +- ...SmsDeliveryMethodNotificationTemplate.java | 2 +- .../template/TemplatableValue.java | 2 +- ...WebDeliveryMethodNotificationTemplate.java | 2 +- .../server/common/data/oauth2/MapperType.java | 2 +- .../data/oauth2/OAuth2BasicMapperConfig.java | 2 +- .../common/data/oauth2/OAuth2ClientInfo.java | 2 +- .../OAuth2ClientRegistrationTemplate.java | 2 +- .../data/oauth2/OAuth2CustomMapperConfig.java | 2 +- .../common/data/oauth2/OAuth2Domain.java | 2 +- .../common/data/oauth2/OAuth2DomainInfo.java | 2 +- .../server/common/data/oauth2/OAuth2Info.java | 2 +- .../data/oauth2/OAuth2MapperConfig.java | 2 +- .../common/data/oauth2/OAuth2Mobile.java | 2 +- .../common/data/oauth2/OAuth2MobileInfo.java | 2 +- .../common/data/oauth2/OAuth2Params.java | 2 +- .../common/data/oauth2/OAuth2ParamsInfo.java | 2 +- .../data/oauth2/OAuth2Registration.java | 2 +- .../data/oauth2/OAuth2RegistrationInfo.java | 2 +- .../common/data/oauth2/PlatformType.java | 2 +- .../server/common/data/oauth2/SchemeType.java | 2 +- .../data/oauth2/TenantNameStrategyType.java | 2 +- .../data/objects/AttributesEntityView.java | 2 +- .../data/objects/TelemetryEntityView.java | 2 +- .../common/data/ota/ChecksumAlgorithm.java | 2 +- .../server/common/data/ota/OtaPackageKey.java | 2 +- .../common/data/ota/OtaPackageType.java | 2 +- .../data/ota/OtaPackageUpdateStatus.java | 2 +- .../common/data/ota/OtaPackageUtil.java | 2 +- .../data/page/BasePageDataIterable.java | 7 +- .../server/common/data/page/PageData.java | 2 +- .../common/data/page/PageDataIterable.java | 2 +- .../data/page/PageDataIterableByTenant.java | 2 +- .../PageDataIterableByTenantIdEntityId.java | 2 +- .../server/common/data/page/PageLink.java | 2 +- .../server/common/data/page/SortOrder.java | 2 +- .../server/common/data/page/TimePageLink.java | 2 +- .../data/plugin/ComponentClusteringMode.java | 2 +- .../data/plugin/ComponentDescriptor.java | 9 +- .../data/plugin/ComponentLifecycleEvent.java | 2 +- .../data/plugin/ComponentLifecycleState.java | 2 +- .../common/data/plugin/ComponentScope.java | 2 +- .../common/data/plugin/ComponentType.java | 2 +- .../common/data/query/AbstractDataQuery.java | 2 +- .../common/data/query/AlarmCountQuery.java | 2 +- .../server/common/data/query/AlarmData.java | 2 +- .../common/data/query/AlarmDataPageLink.java | 2 +- .../common/data/query/AlarmDataQuery.java | 2 +- .../data/query/ApiUsageStateFilter.java | 2 +- .../data/query/AssetSearchQueryFilter.java | 2 +- .../common/data/query/AssetTypeFilter.java | 2 +- .../data/query/BooleanFilterPredicate.java | 2 +- .../common/data/query/ComparisonTsValue.java | 2 +- .../data/query/ComplexFilterPredicate.java | 2 +- .../data/query/DeviceSearchQueryFilter.java | 2 +- .../common/data/query/DeviceTypeFilter.java | 2 +- .../common/data/query/DynamicValue.java | 2 +- .../data/query/DynamicValueSourceType.java | 2 +- .../data/query/EdgeSearchQueryFilter.java | 2 +- .../common/data/query/EdgeTypeFilter.java | 2 +- .../common/data/query/EntityCountQuery.java | 2 +- .../server/common/data/query/EntityData.java | 2 +- .../common/data/query/EntityDataPageLink.java | 2 +- .../common/data/query/EntityDataQuery.java | 2 +- .../data/query/EntityDataSortOrder.java | 2 +- .../common/data/query/EntityFilter.java | 2 +- .../common/data/query/EntityFilterType.java | 2 +- .../server/common/data/query/EntityKey.java | 2 +- .../common/data/query/EntityKeyType.java | 2 +- .../common/data/query/EntityKeyValueType.java | 2 +- .../common/data/query/EntityListFilter.java | 2 +- .../common/data/query/EntityNameFilter.java | 2 +- .../data/query/EntitySearchQueryFilter.java | 2 +- .../common/data/query/EntityTypeFilter.java | 2 +- .../query/EntityViewSearchQueryFilter.java | 2 +- .../data/query/EntityViewTypeFilter.java | 2 +- .../data/query/FilterPredicateType.java | 2 +- .../data/query/FilterPredicateValue.java | 2 +- .../server/common/data/query/KeyFilter.java | 2 +- .../common/data/query/KeyFilterPredicate.java | 2 +- .../data/query/NumericFilterPredicate.java | 2 +- .../data/query/RelationsQueryFilter.java | 2 +- .../data/query/SimpleKeyFilterPredicate.java | 2 +- .../common/data/query/SingleEntityFilter.java | 2 +- .../data/query/StringFilterPredicate.java | 2 +- .../server/common/data/query/TsValue.java | 2 +- .../common/data/queue/ProcessingStrategy.java | 2 +- .../data/queue/ProcessingStrategyType.java | 2 +- .../server/common/data/queue/Queue.java | 2 +- .../common/data/queue/SubmitStrategy.java | 2 +- .../common/data/queue/SubmitStrategyType.java | 2 +- .../common/data/relation/EntityRelation.java | 2 +- .../data/relation/EntityRelationInfo.java | 2 +- .../data/relation/EntityRelationsQuery.java | 2 +- .../data/relation/EntitySearchDirection.java | 2 +- .../relation/RelationEntityTypeFilter.java | 2 +- .../data/relation/RelationTypeGroup.java | 2 +- .../relation/RelationsSearchParameters.java | 2 +- .../server/common/data/rpc/Rpc.java | 2 +- .../server/common/data/rpc/RpcError.java | 2 +- .../server/common/data/rpc/RpcStatus.java | 2 +- .../data/rpc/ToDeviceRpcRequestBody.java | 2 +- .../rule/DefaultRuleChainCreateRequest.java | 2 +- .../common/data/rule/NodeConnectionInfo.java | 2 +- .../server/common/data/rule/RuleChain.java | 2 +- .../data/rule/RuleChainConnectionInfo.java | 2 +- .../common/data/rule/RuleChainData.java | 2 +- .../data/rule/RuleChainImportResult.java | 2 +- .../common/data/rule/RuleChainMetaData.java | 2 +- .../data/rule/RuleChainOutputLabelsUsage.java | 2 +- .../common/data/rule/RuleChainType.java | 2 +- .../data/rule/RuleChainUpdateResult.java | 2 +- .../server/common/data/rule/RuleNode.java | 8 +- .../common/data/rule/RuleNodeState.java | 2 +- .../data/rule/RuleNodeUpdateResult.java | 2 +- .../server/common/data/rule/RuleType.java | 2 +- .../server/common/data/rule/Scope.java | 2 +- .../common/data/script/ScriptLanguage.java | 2 +- .../common/data/security/Authority.java | 2 +- .../data/security/DeviceCredentials.java | 2 +- .../security/DeviceCredentialsFilter.java | 2 +- .../data/security/DeviceCredentialsType.java | 2 +- .../data/security/DeviceTokenCredentials.java | 2 +- .../data/security/DeviceX509Credentials.java | 2 +- .../data/security/UserAuthSettings.java | 2 +- .../common/data/security/UserCredentials.java | 2 +- .../event/UserAuthDataChangedEvent.java | 2 +- .../UserCredentialsInvalidationEvent.java | 2 +- .../event/UserSessionInvalidationEvent.java | 2 +- .../common/data/security/model/JwtPair.java | 2 +- .../data/security/model/JwtSettings.java | 2 +- .../common/data/security/model/JwtToken.java | 2 +- .../data/security/model/SecuritySettings.java | 2 +- .../security/model/UserPasswordPolicy.java | 6 +- .../model/mfa/PlatformTwoFaSettings.java | 2 +- .../mfa/account/AccountTwoFaSettings.java | 2 +- .../account/BackupCodeTwoFaAccountConfig.java | 2 +- .../mfa/account/EmailTwoFaAccountConfig.java | 2 +- .../account/OtpBasedTwoFaAccountConfig.java | 2 +- .../mfa/account/SmsTwoFaAccountConfig.java | 2 +- .../mfa/account/TotpTwoFaAccountConfig.java | 2 +- .../model/mfa/account/TwoFaAccountConfig.java | 2 +- .../BackupCodeTwoFaProviderConfig.java | 2 +- .../provider/EmailTwoFaProviderConfig.java | 2 +- .../provider/OtpBasedTwoFaProviderConfig.java | 2 +- .../mfa/provider/SmsTwoFaProviderConfig.java | 2 +- .../mfa/provider/TotpTwoFaProviderConfig.java | 2 +- .../mfa/provider/TwoFaProviderConfig.java | 2 +- .../model/mfa/provider/TwoFaProviderType.java | 2 +- .../settings/AbstractUserDashboardInfo.java | 2 +- .../settings/LastVisitedDashboardInfo.java | 2 +- .../data/settings/StarredDashboardInfo.java | 2 +- .../data/settings/UserDashboardAction.java | 2 +- .../data/settings/UserDashboardsInfo.java | 2 +- .../common/data/settings/UserSettings.java | 2 +- .../settings/UserSettingsCompositeKey.java | 2 +- .../data/settings/UserSettingsType.java | 2 +- .../AwsSnsSmsProviderConfiguration.java | 2 +- .../config/SmppSmsProviderConfiguration.java | 2 +- .../sms/config/SmsProviderConfiguration.java | 2 +- .../data/sms/config/SmsProviderType.java | 2 +- .../data/sms/config/TestSmsRequest.java | 2 +- .../TwilioSmsProviderConfiguration.java | 2 +- .../server/common/data/sync/JsonTbEntity.java | 6 +- .../data/sync/ie/AttributeExportData.java | 2 +- .../common/data/sync/ie/DeviceExportData.java | 2 +- .../common/data/sync/ie/EntityExportData.java | 2 +- .../data/sync/ie/EntityExportSettings.java | 2 +- .../data/sync/ie/EntityImportResult.java | 2 +- .../data/sync/ie/EntityImportSettings.java | 2 +- .../data/sync/ie/RuleChainExportData.java | 2 +- .../data/sync/ie/WidgetTypeExportData.java | 2 +- .../data/sync/ie/WidgetsBundleExportData.java | 2 +- .../importing/csv/BulkImportColumnType.java | 2 +- .../ie/importing/csv/BulkImportRequest.java | 2 +- .../ie/importing/csv/BulkImportResult.java | 2 +- .../data/sync/vc/AutoCommitSettings.java | 2 +- .../common/data/sync/vc/BranchInfo.java | 2 +- .../common/data/sync/vc/EntityDataDiff.java | 2 +- .../common/data/sync/vc/EntityDataInfo.java | 2 +- .../common/data/sync/vc/EntityLoadError.java | 2 +- .../data/sync/vc/EntityTypeLoadResult.java | 2 +- .../common/data/sync/vc/EntityVersion.java | 2 +- .../data/sync/vc/EntityVersionsDiff.java | 2 +- .../data/sync/vc/RepositoryAuthMethod.java | 2 +- .../data/sync/vc/RepositorySettings.java | 2 +- .../data/sync/vc/RepositorySettingsInfo.java | 2 +- .../server/common/data/sync/vc/VcUtils.java | 2 +- .../data/sync/vc/VersionCreationResult.java | 2 +- .../data/sync/vc/VersionLoadResult.java | 2 +- .../data/sync/vc/VersionedEntityInfo.java | 2 +- .../create/AutoVersionCreateConfig.java | 2 +- .../create/ComplexVersionCreateRequest.java | 2 +- .../create/EntityTypeVersionCreateConfig.java | 2 +- .../SingleEntityVersionCreateRequest.java | 2 +- .../sync/vc/request/create/SyncStrategy.java | 2 +- .../request/create/VersionCreateConfig.java | 2 +- .../request/create/VersionCreateRequest.java | 2 +- .../create/VersionCreateRequestType.java | 2 +- .../load/EntityTypeVersionLoadConfig.java | 2 +- .../load/EntityTypeVersionLoadRequest.java | 2 +- .../load/SingleEntityVersionLoadRequest.java | 2 +- .../vc/request/load/VersionLoadConfig.java | 2 +- .../vc/request/load/VersionLoadRequest.java | 2 +- .../request/load/VersionLoadRequestType.java | 2 +- .../DefaultTenantProfileConfiguration.java | 3 +- .../profile/TenantProfileConfiguration.java | 2 +- .../tenant/profile/TenantProfileData.java | 2 +- .../TenantProfileQueueConfiguration.java | 2 +- .../data/transport/resource/ResourceType.java | 2 +- .../snmp/AuthenticationProtocol.java | 2 +- .../data/transport/snmp/PrivacyProtocol.java | 2 +- .../transport/snmp/SnmpCommunicationSpec.java | 2 +- .../data/transport/snmp/SnmpMapping.java | 2 +- .../data/transport/snmp/SnmpMethod.java | 2 +- .../transport/snmp/SnmpProtocolVersion.java | 2 +- ...ltipleMappingsSnmpCommunicationConfig.java | 2 +- ...eatingQueryingSnmpCommunicationConfig.java | 2 +- .../snmp/config/SnmpCommunicationConfig.java | 2 +- ...rverRpcRequestSnmpCommunicationConfig.java | 2 +- ...ibutesQueryingSnmpCommunicationConfig.java | 2 +- ...ributesSettingSnmpCommunicationConfig.java | 2 +- ...emetryQueryingSnmpCommunicationConfig.java | 2 +- ...viceRpcRequestSnmpCommunicationConfig.java | 2 +- .../common/data/util/CollectionsUtil.java | 2 +- .../common/data/util/ReflectionUtils.java | 2 +- .../common/data/util/TbDDFFileParser.java | 2 +- .../server/common/data/util/TbPair.java | 2 +- .../common/data/util/TemplateUtils.java | 2 +- .../common/data/util/ThrowingBiFunction.java | 2 +- .../common/data/util/ThrowingRunnable.java | 2 +- .../common/data/util/ThrowingSupplier.java | 23 + .../server/common/data/util/TypeCastUtil.java | 2 +- .../server/common/data/validation/Length.java | 2 +- .../server/common/data/validation/NoXss.java | 2 +- .../common/data/widget/BaseWidgetType.java | 2 +- .../common/data/widget/DeprecatedFilter.java | 2 +- .../server/common/data/widget/WidgetType.java | 2 +- .../common/data/widget/WidgetTypeDetails.java | 8 +- .../common/data/widget/WidgetTypeInfo.java | 2 +- .../common/data/widget/WidgetsBundle.java | 9 +- .../data/widget/WidgetsBundleWidget.java | 2 +- .../common/data/DynamicProtoUtilsTest.java | 2 +- .../server/common/data/EntityTypeTest.java | 2 +- .../server/common/data/StringUtilsTest.java | 2 +- .../server/common/data/UUIDConverterTest.java | 2 +- .../common/data/audit/ActionTypeTest.java | 2 +- .../server/common/data/id/EntityIdTest.java | 2 +- .../server/common/data/msg/TbMsgTypeTest.java | 2 +- .../server/common/data/rpc/RpcStatusTest.java | 2 +- common/edge-api/pom.xml | 4 +- .../exception/EdgeConnectionException.java | 2 +- .../thingsboard/edge/rpc/EdgeGrpcClient.java | 4 +- .../thingsboard/edge/rpc/EdgeRpcClient.java | 2 +- common/edge-api/src/main/proto/edge.proto | 427 +- common/message/pom.xml | 4 +- .../server/common/msg/EncryptionUtil.java | 2 +- .../server/common/msg/MsgType.java | 4 +- .../server/common/msg/TbActorError.java | 2 +- .../server/common/msg/TbActorMsg.java | 2 +- .../server/common/msg/TbActorStopReason.java | 2 +- .../thingsboard/server/common/msg/TbMsg.java | 2 +- .../server/common/msg/TbMsgDataType.java | 2 +- .../server/common/msg/TbMsgMetaData.java | 2 +- .../server/common/msg/TbMsgProcessingCtx.java | 2 +- .../common/msg/TbMsgProcessingStackItem.java | 2 +- .../common/msg/TbRuleEngineActorMsg.java | 2 +- .../msg/ToDeviceActorNotificationMsg.java | 2 +- .../common/msg/aware/CustomerAwareMsg.java | 2 +- .../common/msg/aware/DeviceAwareMsg.java | 2 +- .../server/common/msg/aware/NodeAwareMsg.java | 2 +- .../common/msg/aware/RuleChainAwareMsg.java | 2 +- .../common/msg/aware/TenantAwareMsg.java | 2 +- .../common/msg/cluster/ToAllNodesMsg.java | 2 +- .../common/msg/edge/EdgeEventUpdateMsg.java | 2 +- .../common/msg/edge/EdgeSessionMsg.java | 2 +- .../common/msg/edge/FromEdgeSyncResponse.java | 2 +- .../common/msg/edge/ToEdgeSyncRequest.java | 2 +- .../NotificationRuleProcessor.java | 2 +- .../plugin/ComponentLifecycleListener.java | 2 +- .../msg/plugin/ComponentLifecycleMsg.java | 2 +- .../common/msg/plugin/RuleNodeUpdatedMsg.java | 2 +- .../common/msg/queue/PartitionChangeMsg.java | 2 +- .../msg/queue/QueueToRuleEngineMsg.java | 2 +- .../common/msg/queue/RuleEngineException.java | 2 +- .../common/msg/queue/RuleNodeException.java | 2 +- .../server/common/msg/queue/RuleNodeInfo.java | 2 +- .../server/common/msg/queue/ServiceType.java | 2 +- .../server/common/msg/queue/TbCallback.java | 2 +- .../common/msg/queue/TbMsgCallback.java | 2 +- .../common/msg/queue/TopicPartitionInfo.java | 2 +- .../common/msg/rpc/FromDeviceRpcResponse.java | 2 +- .../rpc/FromDeviceRpcResponseActorMsg.java | 2 +- .../common/msg/rpc/RemoveRpcActorMsg.java | 2 +- .../common/msg/rpc/ToDeviceRpcRequest.java | 2 +- .../msg/rpc/ToDeviceRpcRequestActorMsg.java | 2 +- .../msg/rule/engine/DeviceAttributes.java | 2 +- .../DeviceAttributesEventNotificationMsg.java | 2 +- ...eviceCredentialsUpdateNotificationMsg.java | 2 +- .../msg/rule/engine/DeviceDeleteMsg.java | 36 + .../msg/rule/engine/DeviceEdgeUpdateMsg.java | 2 +- .../msg/rule/engine/DeviceMetaData.java | 2 +- .../engine/DeviceNameOrTypeUpdateMsg.java | 2 +- .../common/msg/session/FeatureType.java | 2 +- .../common/msg/session/SessionMsgType.java | 2 +- .../ex/ProcessingTimeoutException.java | 2 +- .../msg/session/ex/SessionAuthException.java | 2 +- .../msg/session/ex/SessionException.java | 2 +- .../DeviceActorServerSideRpcTimeoutMsg.java | 2 +- .../server/common/msg/timeout/TimeoutMsg.java | 2 +- .../common/msg/tools/SchedulerUtils.java | 2 +- .../server/common/msg/tools/TbRateLimits.java | 2 +- .../msg/tools/TbRateLimitsException.java | 2 +- common/message/src/main/proto/tbmsg.proto | 2 +- .../server/common/msg/TbMsgMetaDataTest.java | 2 +- .../msg/TbMsgProcessingStackItemTest.java | 2 +- .../msg/queue/TopicPartitionInfoTest.java | 2 +- .../common/msg/tools/RateLimitsTest.java | 2 +- common/pom.xml | 5 +- common/proto/pom.xml | 94 + .../common}/adaptor/AdaptorException.java | 4 +- .../server/common}/adaptor/JsonConverter.java | 4 +- .../common}/adaptor/JsonConverterConfig.java | 4 +- .../common}/adaptor/ProtoConverter.java | 4 +- .../server/common/util}/ProtoUtils.java | 26 +- .../src/main/proto/jsinvoke.proto | 2 +- .../src/main/proto/queue.proto | 28 +- .../src/main/proto/transport.proto | 2 +- .../common/adaptor}/JsonConverterTest.java | 5 +- .../server/common/util}/ProtoUtilsTest.java | 4 +- common/queue/pom.xml | 4 +- .../queue/RuleEngineTbQueueAdminFactory.java | 2 +- .../azure/servicebus/TbServiceBusAdmin.java | 2 +- .../TbServiceBusConsumerTemplate.java | 2 +- .../TbServiceBusProducerTemplate.java | 2 +- .../servicebus/TbServiceBusQueueConfigs.java | 2 +- .../servicebus/TbServiceBusSettings.java | 2 +- ...stractParallelTbQueueConsumerTemplate.java | 2 +- .../AbstractTbQueueConsumerTemplate.java | 2 +- .../queue/common/AbstractTbQueueTemplate.java | 2 +- .../queue/common/AsyncCallbackTemplate.java | 2 +- .../queue/common/DefaultTbQueueMsg.java | 2 +- .../common/DefaultTbQueueMsgHeaders.java | 2 +- .../common/DefaultTbQueueRequestTemplate.java | 2 +- .../DefaultTbQueueResponseTemplate.java | 2 +- .../MultipleTbQueueCallbackWrapper.java | 2 +- .../MultipleTbQueueTbMsgCallbackWrapper.java | 2 +- .../queue/common/TbProtoJsQueueMsg.java | 2 +- .../server/queue/common/TbProtoQueueMsg.java | 2 +- .../common/TbQueueTbMsgCallbackWrapper.java | 2 +- .../queue/discovery/ConsistentHashCircle.java | 2 +- .../DefaultTbServiceInfoProvider.java | 2 +- .../queue/discovery/DiscoveryService.java | 2 +- .../discovery/DummyDiscoveryService.java | 2 +- .../queue/discovery/HashPartitionService.java | 2 +- .../queue/discovery/PartitionService.java | 2 +- .../server/queue/discovery/QueueKey.java | 2 +- .../queue/discovery/QueueRoutingInfo.java | 2 +- .../discovery/QueueRoutingInfoService.java | 2 +- .../discovery/TbApplicationEventListener.java | 2 +- .../discovery/TbServiceInfoProvider.java | 2 +- .../queue/discovery/TenantRoutingInfo.java | 2 +- .../discovery/TenantRoutingInfoService.java | 2 +- .../server/queue/discovery/TopicService.java | 2 +- .../queue/discovery/ZkDiscoveryService.java | 2 +- .../event/ClusterTopologyChangeEvent.java | 2 +- .../event/OtherServiceShutdownEvent.java | 2 +- .../discovery/event/PartitionChangeEvent.java | 2 +- .../event/ServiceListChangedEvent.java | 2 +- .../discovery/event/TbApplicationEvent.java | 2 +- .../environment/EnvironmentLogService.java | 2 +- .../server/queue/kafka/KafkaTbQueueMsg.java | 2 +- .../queue/kafka/KafkaTbQueueMsgMetadata.java | 2 +- .../server/queue/kafka/TbKafkaAdmin.java | 2 +- .../kafka/TbKafkaConsumerStatisticConfig.java | 2 +- .../kafka/TbKafkaConsumerStatsService.java | 2 +- .../queue/kafka/TbKafkaConsumerTemplate.java | 2 +- .../server/queue/kafka/TbKafkaDecoder.java | 2 +- .../server/queue/kafka/TbKafkaEncoder.java | 2 +- .../queue/kafka/TbKafkaProducerTemplate.java | 2 +- .../server/queue/kafka/TbKafkaSettings.java | 2 +- .../queue/kafka/TbKafkaTopicConfigs.java | 2 +- .../queue/memory/DefaultInMemoryStorage.java | 2 +- .../server/queue/memory/InMemoryStorage.java | 2 +- .../queue/memory/InMemoryTbQueueConsumer.java | 2 +- .../queue/memory/InMemoryTbQueueProducer.java | 2 +- ...faultNotificationDeduplicationService.java | 2 +- .../NotificationDeduplicationService.java | 2 +- .../RemoteNotificationRuleProcessor.java | 2 +- .../provider/AwsSqsMonolithQueueFactory.java | 2 +- .../provider/AwsSqsTbCoreQueueFactory.java | 2 +- .../AwsSqsTbRuleEngineQueueFactory.java | 2 +- .../AwsSqsTbVersionControlQueueFactory.java | 2 +- .../provider/AwsSqsTransportQueueFactory.java | 2 +- .../InMemoryMonolithQueueFactory.java | 2 +- .../InMemoryTbTransportQueueFactory.java | 2 +- .../provider/KafkaMonolithQueueFactory.java | 2 +- .../provider/KafkaTbCoreQueueFactory.java | 2 +- .../KafkaTbRuleEngineQueueFactory.java | 2 +- .../KafkaTbTransportQueueFactory.java | 2 +- .../KafkaTbVersionControlQueueFactory.java | 2 +- .../provider/PubSubMonolithQueueFactory.java | 2 +- .../provider/PubSubTbCoreQueueFactory.java | 2 +- .../PubSubTbRuleEngineQueueFactory.java | 2 +- .../PubSubTbVersionControlQueueFactory.java | 2 +- .../provider/PubSubTransportQueueFactory.java | 2 +- .../RabbitMqMonolithQueueFactory.java | 2 +- .../provider/RabbitMqTbCoreQueueFactory.java | 2 +- .../RabbitMqTbRuleEngineQueueFactory.java | 2 +- .../RabbitMqTbVersionControlQueueFactory.java | 2 +- .../RabbitMqTransportQueueFactory.java | 2 +- .../ServiceBusMonolithQueueFactory.java | 2 +- .../ServiceBusTbCoreQueueFactory.java | 2 +- .../ServiceBusTbRuleEngineQueueFactory.java | 2 +- ...erviceBusTbVersionControlQueueFactory.java | 2 +- .../ServiceBusTransportQueueFactory.java | 2 +- .../queue/provider/TbCoreQueueFactory.java | 2 +- .../provider/TbCoreQueueProducerProvider.java | 2 +- .../provider/TbQueueProducerProvider.java | 2 +- .../TbRuleEngineProducerProvider.java | 2 +- .../provider/TbRuleEngineQueueFactory.java | 2 +- .../provider/TbTransportQueueFactory.java | 2 +- .../TbTransportQueueProducerProvider.java | 2 +- .../TbUsageStatsClientQueueFactory.java | 2 +- .../TbVersionControlProducerProvider.java | 2 +- .../TbVersionControlQueueFactory.java | 2 +- .../server/queue/pubsub/TbPubSubAdmin.java | 2 +- .../pubsub/TbPubSubConsumerTemplate.java | 4 +- .../pubsub/TbPubSubProducerTemplate.java | 8 +- .../server/queue/pubsub/TbPubSubSettings.java | 27 +- .../pubsub/TbPubSubSubscriptionSettings.java | 2 +- .../queue/rabbitmq/TbRabbitMqAdmin.java | 2 +- .../rabbitmq/TbRabbitMqConsumerTemplate.java | 2 +- .../rabbitmq/TbRabbitMqProducerTemplate.java | 2 +- .../rabbitmq/TbRabbitMqQueueArguments.java | 2 +- .../queue/rabbitmq/TbRabbitMqSettings.java | 2 +- .../scheduler/DefaultSchedulerComponent.java | 2 +- .../queue/scheduler/SchedulerComponent.java | 2 +- .../queue/settings/TbQueueCoreSettings.java | 2 +- .../TbQueueRemoteJsInvokeSettings.java | 2 +- .../settings/TbQueueRuleEngineSettings.java | 2 +- .../settings/TbQueueTransportApiSettings.java | 2 +- .../TbQueueTransportNotificationSettings.java | 2 +- .../TbQueueVersionControlSettings.java | 2 +- ...leEngineQueueAckStrategyConfiguration.java | 2 +- .../TbRuleEngineQueueConfiguration.java | 2 +- ...ngineQueueSubmitStrategyConfiguration.java | 2 +- .../queue/sqs/AwsSqsTbQueueMsgMetadata.java | 2 +- .../server/queue/sqs/TbAwsSqsAdmin.java | 14 +- .../queue/sqs/TbAwsSqsConsumerTemplate.java | 2 +- .../queue/sqs/TbAwsSqsProducerTemplate.java | 44 +- .../queue/sqs/TbAwsSqsQueueAttributes.java | 2 +- .../server/queue/sqs/TbAwsSqsSettings.java | 5 +- .../DefaultTbApiUsageReportClient.java | 2 +- .../server/queue/util/AfterContextReady.java | 2 +- .../server/queue/util/AfterStartUp.java | 2 +- .../util/DataDecodingEncodingService.java | 2 +- .../server/queue/util/PropertyUtils.java | 2 +- .../queue/util/ProtoWithFSTService.java | 21 +- .../server/queue/util/TbCoreComponent.java | 2 +- .../TbLwM2mBootstrapTransportComponent.java | 2 +- .../queue/util/TbLwM2mTransportComponent.java | 2 +- .../queue/util/TbRuleEngineComponent.java | 2 +- .../queue/util/TbSnmpTransportComponent.java | 2 +- .../queue/util/TbTransportComponent.java | 2 +- .../queue/util/TbVersionControlComponent.java | 2 +- .../DefaultTbQueueRequestTemplateTest.java | 2 +- .../server/queue/discovery/QueueKeyTest.java | 2 +- .../discovery/ZkDiscoveryServiceTest.java | 2 +- .../kafka/TbKafkaProducerTemplateTest.java | 2 +- .../queue/kafka/TbKafkaSettingsTest.java | 2 +- .../memory/DefaultInMemoryStorageTest.java | 2 +- .../server/queue/util/PropertyUtilsTest.java | 2 +- common/script/pom.xml | 4 +- common/script/remote-js-client/pom.xml | 4 +- .../service/script/JsExecutorService.java | 2 +- .../service/script/RemoteJsInvokeService.java | 2 +- .../script/RemoteJsRequestEncoder.java | 2 +- .../script/RemoteJsResponseDecoder.java | 2 +- common/script/script-api/pom.xml | 4 +- .../api/AbstractScriptInvokeService.java | 2 +- .../script/api/BlockedScriptInfo.java | 2 +- .../script/api/RuleNodeScriptFactory.java | 2 +- .../script/api/ScriptInvokeService.java | 2 +- .../script/api/ScriptStatCallback.java | 2 +- .../thingsboard/script/api/ScriptType.java | 2 +- .../script/api/TbScriptException.java | 2 +- .../script/api/TbScriptExecutionTask.java | 2 +- .../api/js/AbstractJsInvokeService.java | 2 +- .../script/api/js/JsInvokeService.java | 2 +- .../script/api/js/JsScriptExecutionTask.java | 2 +- .../script/api/js/JsScriptInfo.java | 2 +- .../script/api/js/NashornJsInvokeService.java | 2 +- .../api/tbel/DateTimeFormatOptions.java | 2 +- .../api/tbel/DefaultTbelInvokeService.java | 2 +- .../thingsboard/script/api/tbel/TbDate.java | 100 +- .../thingsboard/script/api/tbel/TbJson.java | 2 +- .../thingsboard/script/api/tbel/TbUtils.java | 30 +- .../script/api/tbel/TbelInvokeService.java | 2 +- .../script/api/tbel/TbelScript.java | 2 +- .../api/tbel/TbelScriptExecutionTask.java | 2 +- .../api/tbel/TbDateConstructorTest.java | 102 + .../script/api/tbel/TbDateTest.java | 158 +- .../script/api/tbel/TbDateTestEntity.java | 2 +- .../script/api/tbel/TbUtilsTest.java | 92 +- common/stats/pom.xml | 4 +- .../server/common/stats/DefaultCounter.java | 2 +- .../common/stats/DefaultMessagesStats.java | 2 +- .../common/stats/DefaultStatsFactory.java | 2 +- .../common/stats/FstStatsServiceImpl.java | 58 + .../server/common/stats/MessagesStats.java | 2 +- .../server/common/stats/StatsCounter.java | 2 +- .../server/common/stats/StatsFactory.java | 2 +- .../server/common/stats/StatsType.java | 2 +- .../common/stats/TbApiUsageReportClient.java | 2 +- .../common/stats/TbApiUsageStateClient.java | 2 +- common/transport/coap/pom.xml | 4 +- .../coap/AbstractCoapTransportResource.java | 2 +- .../transport/coap/CoapSessionMsgType.java | 2 +- .../transport/coap/CoapTransportContext.java | 2 +- .../transport/coap/CoapTransportResource.java | 6 +- .../transport/coap/CoapTransportService.java | 2 +- .../coap/OtaPackageTransportResource.java | 2 +- .../transport/coap/TbCoapMessageObserver.java | 2 +- .../coap/TransportConfigurationContainer.java | 2 +- .../coap/adaptors/CoapAdaptorUtils.java | 4 +- .../coap/adaptors/CoapTransportAdaptor.java | 4 +- .../coap/adaptors/JsonCoapAdaptor.java | 6 +- .../coap/adaptors/ProtoCoapAdaptor.java | 8 +- .../callback/AbstractSyncSessionCallback.java | 3 +- .../coap/callback/CoapDeviceAuthCallback.java | 2 +- .../coap/callback/CoapEfentoCallback.java | 2 +- .../coap/callback/CoapNoOpCallback.java | 2 +- .../coap/callback/CoapOkCallback.java | 6 +- .../GetAttributesSyncSessionCallback.java | 4 +- .../ToServerRpcSyncSessionCallback.java | 4 +- .../coap/client/CoapClientContext.java | 4 +- .../coap/client/DefaultCoapClientContext.java | 6 +- .../transport/coap/client/NoSecClient.java | 2 +- .../coap/client/NoSecObserveClient.java | 2 +- .../coap/client/SecureClientNoAuth.java | 2 +- .../coap/client/SecureClientX509.java | 2 +- .../coap/client/TbCoapClientState.java | 2 +- .../coap/client/TbCoapContentFormatUtil.java | 2 +- .../coap/client/TbCoapObservationState.java | 2 +- .../efento/CoapEfentoTransportResource.java | 7 +- .../efento/adaptor/EfentoCoapAdaptor.java | 6 +- .../coap/efento/utils/CoapEfentoUtils.java | 2 +- .../src/main/proto/efento/proto_config.proto | 2 +- .../main/proto/efento/proto_device_info.proto | 2 +- .../efento/proto_measurement_types.proto | 2 +- .../proto/efento/proto_measurements.proto | 2 +- .../src/main/proto/efento/proto_rule.proto | 2 +- .../coap/CoapTransportResourceTest.java | 2 +- common/transport/http/pom.xml | 4 +- .../transport/http/DeviceApiController.java | 4 +- .../transport/http/HttpTransportContext.java | 2 +- common/transport/lwm2m/pom.xml | 4 +- .../LwM2MTransportBootstrapService.java | 2 +- .../secure/LwM2MBootstrapConfig.java | 2 +- .../secure/LwM2MBootstrapServers.java | 2 +- .../secure/LwM2MServerBootstrap.java | 2 +- .../LwM2mDefaultBootstrapSessionManager.java | 2 +- ...LwM2MDtlsBootstrapCertificateVerifier.java | 2 +- .../LwM2MBootstrapClientInstanceIds.java | 2 +- ...LwM2MBootstrapConfigStoreTaskProvider.java | 2 +- .../store/LwM2MBootstrapSecurityStore.java | 2 +- .../store/LwM2MBootstrapTaskProvider.java | 2 +- .../store/LwM2MConfigurationChecker.java | 2 +- .../LwM2MInMemoryBootstrapConfigStore.java | 2 +- .../lwm2m/config/LwM2MSecureServerConfig.java | 2 +- .../config/LwM2MTransportBootstrapConfig.java | 2 +- .../config/LwM2MTransportServerConfig.java | 2 +- .../lwm2m/config/TbLwM2mVersion.java | 2 +- ...LwM2mCredentialsSecurityInfoValidator.java | 2 +- .../lwm2m/secure/LwM2mRPkCredentials.java | 2 +- .../lwm2m/secure/TbLwM2MAuthorizer.java | 2 +- .../TbLwM2MDtlsCertificateVerifier.java | 2 +- .../lwm2m/secure/TbLwM2MSecurityInfo.java | 2 +- .../lwm2m/secure/TbX509DtlsSessionInfo.java | 2 +- .../credentials/LwM2MClientCredentials.java | 2 +- .../AbstractLwM2mTransportResource.java | 2 +- .../server/DefaultLwM2mTransportService.java | 2 +- .../lwm2m/server/LwM2MNetworkConfig.java | 2 +- .../lwm2m/server/LwM2MOperationType.java | 2 +- .../lwm2m/server/LwM2MTransportService.java | 2 +- .../lwm2m/server/LwM2mOtaConvert.java | 2 +- .../lwm2m/server/LwM2mQueuedRequest.java | 2 +- .../lwm2m/server/LwM2mServerListener.java | 2 +- .../lwm2m/server/LwM2mSessionMsgListener.java | 2 +- .../server/LwM2mTransportCoapResource.java | 2 +- .../lwm2m/server/LwM2mTransportContext.java | 2 +- .../server/LwM2mTransportServerHelper.java | 2 +- .../server/LwM2mVersionedModelProvider.java | 5 +- .../server/adaptors/LwM2MJsonAdaptor.java | 6 +- .../adaptors/LwM2MTransportAdaptor.java | 4 +- .../DefaultLwM2MAttributesService.java | 2 +- .../attributes/LwM2MAttributesService.java | 2 +- .../server/client/LwM2MAuthException.java | 2 +- .../lwm2m/server/client/LwM2MClientState.java | 2 +- .../client/LwM2MClientStateException.java | 2 +- .../lwm2m/server/client/LwM2mClient.java | 2 +- .../server/client/LwM2mClientContext.java | 2 +- .../server/client/LwM2mClientContextImpl.java | 2 +- .../lwm2m/server/client/ModelObject.java | 2 +- .../client/ParametersAnalyzeResult.java | 2 +- .../lwm2m/server/client/ResourceValue.java | 2 +- .../client/ResultsAddKeyValueProto.java | 2 +- .../common/LwM2MExecutorAwareService.java | 2 +- .../AbstractTbLwM2MRequestCallback.java | 2 +- ...bstractTbLwM2MTargetedDownlinkRequest.java | 2 +- .../DefaultLwM2mDownlinkMsgHandler.java | 2 +- .../downlink/DownlinkRequestCallback.java | 2 +- .../server/downlink/HasContentFormat.java | 2 +- .../lwm2m/server/downlink/HasVersionedId.java | 2 +- .../server/downlink/HasVersionedIds.java | 2 +- .../downlink/LwM2mDownlinkMsgHandler.java | 2 +- .../TbLwM2MCancelAllObserveCallback.java | 2 +- .../downlink/TbLwM2MCancelAllRequest.java | 2 +- .../TbLwM2MCancelObserveCallback.java | 2 +- .../downlink/TbLwM2MCancelObserveRequest.java | 2 +- .../server/downlink/TbLwM2MCreateRequest.java | 2 +- .../TbLwM2MCreateResponseCallback.java | 2 +- .../downlink/TbLwM2MDeleteCallback.java | 2 +- .../server/downlink/TbLwM2MDeleteRequest.java | 2 +- .../downlink/TbLwM2MDiscoverAllRequest.java | 2 +- .../downlink/TbLwM2MDiscoverCallback.java | 2 +- .../downlink/TbLwM2MDiscoverRequest.java | 2 +- .../downlink/TbLwM2MDownlinkRequest.java | 2 +- .../downlink/TbLwM2MExecuteCallback.java | 2 +- .../downlink/TbLwM2MExecuteRequest.java | 2 +- .../server/downlink/TbLwM2MLatchCallback.java | 2 +- .../downlink/TbLwM2MObserveAllRequest.java | 2 +- .../downlink/TbLwM2MObserveCallback.java | 2 +- .../downlink/TbLwM2MObserveRequest.java | 2 +- .../server/downlink/TbLwM2MReadCallback.java | 2 +- .../server/downlink/TbLwM2MReadRequest.java | 2 +- .../downlink/TbLwM2MTargetedCallback.java | 2 +- .../TbLwM2MUplinkTargetedCallback.java | 2 +- .../TbLwM2MWriteAttributesCallback.java | 2 +- .../TbLwM2MWriteAttributesRequest.java | 2 +- .../downlink/TbLwM2MWriteReplaceRequest.java | 2 +- .../TbLwM2MWriteResponseCallback.java | 2 +- .../downlink/TbLwM2MWriteUpdateRequest.java | 2 +- ...LwM2MTargetedDownlinkCompositeRequest.java | 2 +- .../TbLwM2MReadCompositeCallback.java | 2 +- .../TbLwM2MReadCompositeRequest.java | 2 +- .../TbLwM2MWriteCompositeRequest.java | 2 +- ...TbLwM2MWriteResponseCompositeCallback.java | 2 +- .../log/DefaultLwM2MTelemetryLogService.java | 2 +- .../server/log/LwM2MTelemetryLogService.java | 2 +- .../lwm2m/server/model/LwM2MModelConfig.java | 2 +- .../server/model/LwM2MModelConfigService.java | 2 +- .../model/LwM2MModelConfigServiceImpl.java | 2 +- .../ota/DefaultLwM2MOtaUpdateService.java | 2 +- .../lwm2m/server/ota/LwM2MClientOtaInfo.java | 2 +- .../lwm2m/server/ota/LwM2MClientOtaState.java | 2 +- .../server/ota/LwM2MOtaUpdateService.java | 2 +- .../ota/firmware/FirmwareDeliveryMethod.java | 2 +- .../ota/firmware/FirmwareUpdateResult.java | 2 +- .../ota/firmware/FirmwareUpdateState.java | 2 +- .../ota/firmware/LwM2MClientFwOtaInfo.java | 2 +- .../firmware/LwM2MFirmwareUpdateStrategy.java | 2 +- .../ota/software/LwM2MClientSwOtaInfo.java | 2 +- .../software/LwM2MSoftwareUpdateStrategy.java | 2 +- .../ota/software/SoftwareUpdateResult.java | 2 +- .../ota/software/SoftwareUpdateState.java | 2 +- .../rpc/DefaultLwM2MRpcRequestHandler.java | 2 +- .../server/rpc/LwM2MRpcRequestHandler.java | 2 +- .../server/rpc/LwM2MRpcRequestHeader.java | 2 +- .../server/rpc/LwM2MRpcResponseBody.java | 2 +- .../rpc/RpcCancelAllObserveCallback.java | 2 +- .../server/rpc/RpcCancelObserveCallback.java | 2 +- .../lwm2m/server/rpc/RpcCreateRequest.java | 2 +- .../server/rpc/RpcCreateResponseCallback.java | 2 +- .../lwm2m/server/rpc/RpcDiscoverCallback.java | 2 +- .../rpc/RpcDownlinkRequestCallbackProxy.java | 2 +- .../server/rpc/RpcEmptyResponseCallback.java | 2 +- .../lwm2m/server/rpc/RpcLinkSetCallback.java | 2 +- .../server/rpc/RpcLwM2MDownlinkCallback.java | 2 +- .../server/rpc/RpcReadResponseCallback.java | 2 +- .../server/rpc/RpcWriteAttributesRequest.java | 2 +- .../server/rpc/RpcWriteReplaceRequest.java | 2 +- .../server/rpc/RpcWriteUpdateRequest.java | 2 +- .../composite/RpcReadCompositeRequest.java | 2 +- .../RpcReadResponseCompositeCallback.java | 2 +- .../composite/RpcWriteCompositeRequest.java | 2 +- .../session/DefaultLwM2MSessionManager.java | 2 +- .../server/session/LwM2MSessionManager.java | 2 +- .../store/TbDummyLwM2MClientOtaInfoStore.java | 2 +- .../server/store/TbDummyLwM2MClientStore.java | 2 +- .../store/TbDummyLwM2MModelConfigStore.java | 2 +- .../server/store/TbEditableSecurityStore.java | 2 +- .../server/store/TbInMemorySecurityStore.java | 2 +- .../TbL2M2MDtlsSessionInMemoryStore.java | 2 +- .../store/TbLwM2MClientOtaInfoStore.java | 2 +- .../server/store/TbLwM2MClientStore.java | 2 +- .../store/TbLwM2MDtlsSessionRedisStore.java | 2 +- .../server/store/TbLwM2MDtlsSessionStore.java | 2 +- .../server/store/TbLwM2MModelConfigStore.java | 2 +- .../store/TbLwM2mRedisClientOtaInfoStore.java | 2 +- .../store/TbLwM2mRedisRegistrationStore.java | 2 +- .../store/TbLwM2mRedisSecurityStore.java | 2 +- .../server/store/TbLwM2mSecurityStore.java | 2 +- .../server/store/TbLwM2mStoreFactory.java | 2 +- .../server/store/TbMainSecurityStore.java | 2 +- .../server/store/TbRedisLwM2MClientStore.java | 2 +- .../store/TbRedisLwM2MModelConfigStore.java | 2 +- .../lwm2m/server/store/TbSecurityStore.java | 2 +- .../server/store/util/LwM2MClientSerDes.java | 2 +- .../uplink/DefaultLwM2mUplinkMsgHandler.java | 2 +- .../lwm2m/server/uplink/LwM2mTypeServer.java | 2 +- .../server/uplink/LwM2mUplinkMsgHandler.java | 2 +- .../lwm2m/utils/LwM2MTransportUtil.java | 2 +- .../lwm2m/utils/LwM2mValueConverterImpl.java | 2 +- .../LwM2MModelConfigServiceImplTest.java | 2 +- .../lwm2m/server/client/LwM2mClientTest.java | 2 +- .../store/util/LwM2MClientSerDesTest.java | 2 +- common/transport/mqtt/pom.xml | 4 +- .../mqtt/MqttSslHandlerProvider.java | 2 +- .../transport/mqtt/MqttTransportContext.java | 2 +- .../transport/mqtt/MqttTransportHandler.java | 14 +- .../mqtt/MqttTransportServerInitializer.java | 2 +- .../transport/mqtt/MqttTransportService.java | 2 +- .../server/transport/mqtt/TopicType.java | 2 +- .../BackwardCompatibilityAdaptor.java | 4 +- .../mqtt/adaptors/JsonMqttAdaptor.java | 6 +- .../mqtt/adaptors/MqttTransportAdaptor.java | 4 +- .../mqtt/adaptors/ProtoMqttAdaptor.java | 8 +- .../transport/mqtt/limits/IpFilter.java | 2 +- .../transport/mqtt/limits/ProxyIpFilter.java | 2 +- .../AbstractGatewayDeviceSessionContext.java | 2 +- .../AbstractGatewaySessionHandler.java | 30 +- .../mqtt/session/DeviceSessionCtx.java | 2 +- .../session/GatewayDeviceSessionContext.java | 2 +- .../mqtt/session/GatewaySessionHandler.java | 4 +- .../MqttDeviceAwareSessionContext.java | 2 +- .../mqtt/session/MqttTopicMatcher.java | 2 +- .../SparkplugDeviceSessionContext.java | 2 +- .../session/SparkplugNodeSessionHandler.java | 8 +- .../mqtt/util/AlwaysTrueTopicFilter.java | 2 +- .../mqtt/util/EqualsTopicFilter.java | 2 +- .../transport/mqtt/util/MqttTopicFilter.java | 2 +- .../mqtt/util/MqttTopicFilterFactory.java | 2 +- .../transport/mqtt/util/RegexTopicFilter.java | 2 +- .../transport/mqtt/util/ReturnCode.java | 2 +- .../mqtt/util/ReturnCodeResolver.java | 2 +- .../mqtt/util/sparkplug/MetricDataType.java | 4 +- .../sparkplug/SparkplugConnectionState.java | 2 +- .../util/sparkplug/SparkplugMessageType.java | 2 +- .../util/sparkplug/SparkplugMetricUtil.java | 2 +- .../sparkplug/SparkplugRpcRequestHeader.java | 2 +- .../sparkplug/SparkplugRpcResponseBody.java | 2 +- .../mqtt/util/sparkplug/SparkplugTopic.java | 2 +- .../util/sparkplug/SparkplugTopicUtil.java | 2 +- .../mqtt/src/main/proto/sparkplug.proto | 2 +- .../mqtt/MqttTransportHandlerTest.java | 2 +- .../session/GatewaySessionHandlerTest.java | 2 +- .../mqtt/util/MqttTopicFilterFactoryTest.java | 2 +- common/transport/pom.xml | 4 +- common/transport/snmp/pom.xml | 4 +- .../transport/snmp/SnmpTransportContext.java | 2 +- .../ServiceListChangedEventListener.java | 2 +- .../event/SnmpTransportListChangedEvent.java | 2 +- ...SnmpTransportListChangedEventListener.java | 2 +- .../transport/snmp/service/PduService.java | 2 +- .../service/ProtoTransportEntityService.java | 2 +- .../snmp/service/SnmpAuthService.java | 2 +- .../SnmpTransportBalancingService.java | 2 +- .../snmp/service/SnmpTransportService.java | 6 +- .../snmp/session/DeviceSessionContext.java | 2 +- .../transport/snmp/SnmpDeviceSimulatorV2.java | 2 +- .../transport/snmp/SnmpDeviceSimulatorV3.java | 2 +- .../server/transport/snmp/SnmpTestV2.java | 2 +- .../server/transport/snmp/SnmpTestV3.java | 2 +- common/transport/transport-api/pom.xml | 4 +- .../common/transport/DeviceDeletedEvent.java | 2 +- .../transport/DeviceProfileUpdatedEvent.java | 2 +- .../common/transport/DeviceUpdatedEvent.java | 2 +- .../common/transport/SessionMsgListener.java | 2 +- .../common/transport/TransportAdaptor.java | 2 +- .../common/transport/TransportContext.java | 2 +- .../TransportDeviceProfileCache.java | 2 +- .../transport/TransportResourceCache.java | 2 +- .../common/transport/TransportService.java | 6 +- .../transport/TransportServiceCallback.java | 2 +- .../TransportTenantProfileCache.java | 2 +- .../activity/AbstractActivityManager.java | 187 + .../transport/activity/ActivityManager.java | 26 + .../activity/ActivityReportCallback.java | 24 + .../transport/activity/ActivityState.java | 26 + .../activity/strategy/ActivityStrategy.java | 24 + .../strategy/ActivityStrategyType.java | 47 + .../strategy/AllEventsActivityStrategy.java | 39 + .../FirstAndLastEventActivityStrategy.java | 40 + .../strategy/FirstEventActivityStrategy.java | 40 + .../strategy/LastEventActivityStrategy.java | 39 + .../transport/auth/DeviceAuthResult.java | 2 +- .../transport/auth/DeviceAuthService.java | 2 +- .../transport/auth/DeviceProfileAware.java | 2 +- .../GetOrCreateDeviceFromGatewayResponse.java | 2 +- .../transport/auth/SessionInfoCreator.java | 2 +- .../transport/auth/TransportDeviceInfo.java | 2 +- .../ValidateDeviceCredentialsResponse.java | 2 +- .../config/ssl/AbstractSslCredentials.java | 2 +- .../config/ssl/KeystoreSslCredentials.java | 2 +- .../config/ssl/PemSslCredentials.java | 2 +- .../transport/config/ssl/SslCredentials.java | 2 +- .../config/ssl/SslCredentialsConfig.java | 2 +- .../config/ssl/SslCredentialsType.java | 2 +- .../SslCredentialsWebServerCustomizer.java | 2 +- .../limits/DefaultEntityLimitsCache.java | 74 + .../DefaultTransportRateLimitService.java | 2 +- .../limits/DummyTransportRateLimit.java | 2 +- .../transport/limits/EntityLimitKey.java | 27 + .../transport/limits/EntityLimitsCache.java | 24 + .../limits/EntityTransportRateLimits.java | 2 +- .../limits/InetAddressRateLimitStats.java | 2 +- .../limits/SimpleTransportRateLimit.java | 2 +- .../transport/limits/TransportRateLimit.java | 2 +- .../limits/TransportRateLimitService.java | 2 +- .../profile/TenantProfileUpdateResult.java | 2 +- .../DefaultTransportDeviceProfileCache.java | 2 +- .../DefaultTransportResourceCache.java | 2 +- .../service/DefaultTransportService.java | 172 +- .../DefaultTransportTenantProfileCache.java | 2 +- .../transport/service/RpcRequestMetadata.java | 2 +- .../service/SessionActivityData.java | 39 - .../transport/service/SessionMetaData.java | 2 +- .../service/ToRuleEngineMsgEncoder.java | 2 +- .../ToTransportMsgResponseDecoder.java | 2 +- .../service/TransportActivityManager.java | 149 + .../service/TransportApiRequestEncoder.java | 2 +- .../service/TransportApiResponseDecoder.java | 2 +- .../TransportQueueRoutingInfoService.java | 2 +- .../TransportTenantRoutingInfoService.java | 2 +- .../session/DeviceAwareSessionContext.java | 2 +- .../transport/session/SessionContext.java | 2 +- .../common/transport/util/JsonUtils.java | 2 +- .../server/common/transport/util/SslUtil.java | 2 +- .../strategy/ActivityStrategyTypeTest.java | 44 + .../AllEventsActivityStrategyTest.java | 42 + ...FirstAndLastEventActivityStrategyTest.java | 53 + .../FirstEventActivityStrategyTest.java | 52 + .../LastEventActivityStrategyTest.java | 43 + .../service/TransportActivityManagerTest.java | 508 ++ common/util/pom.xml | 4 +- .../util/AbstractListeningExecutor.java | 2 +- .../common/util/AzureIotHubUtil.java | 2 +- .../thingsboard/common/util/DonAsynchron.java | 2 +- .../common/util/ExceptionUtil.java | 2 +- .../common/util/ExecutorProvider.java | 23 + .../thingsboard/common/util/JacksonUtil.java | 14 +- .../org/thingsboard/common/util/KvUtil.java | 2 +- .../util/LinkedHashMapRemoveEldest.java | 2 +- .../common/util/ListeningExecutor.java | 2 +- .../thingsboard/common/util/RegexUtils.java | 13 +- .../org/thingsboard/common/util/SslUtil.java | 2 +- .../thingsboard/common/util/SystemUtil.java | 2 +- .../thingsboard/common/util/TbStopWatch.java | 2 +- .../common/util/ThingsBoardExecutors.java | 2 +- ...hingsBoardForkJoinWorkerThreadFactory.java | 2 +- .../common/util/ThingsBoardThreadFactory.java | 2 +- .../common/util/ExceptionUtilTest.java | 2 +- .../common/util/JacksonUtilTest.java | 29 +- .../util/LinkedHashMapRemoveEldestTest.java | 2 +- common/version-control/pom.xml | 4 +- .../sync/vc/ClusterVersionControlService.java | 2 +- .../DefaultClusterVersionControlService.java | 17 +- .../sync/vc/DefaultGitRepositoryService.java | 2 +- .../server/service/sync/vc/GitRepository.java | 11 +- .../service/sync/vc/GitRepositoryService.java | 2 +- .../server/service/sync/vc/PendingCommit.java | 2 +- .../sync/vc/VersionControlRequestCtx.java | 2 +- dao/pom.xml | 16 +- .../java/org/thingsboard/server/dao/Dao.java | 2 +- .../org/thingsboard/server/dao/DaoUtil.java | 25 +- .../server/dao/ExportableEntityDao.java | 8 +- .../dao/ExportableEntityRepository.java | 2 +- .../server/dao/ImageContainerDao.java | 29 + .../thingsboard/server/dao/JpaDaoConfig.java | 2 +- .../server/dao/SqlTimeseriesDaoConfig.java | 2 +- .../server/dao/SqlTsDaoConfig.java | 2 +- .../server/dao/SqlTsLatestDaoConfig.java | 2 +- .../server/dao/TenantEntityDao.java | 2 +- .../server/dao/TenantEntityWithDataDao.java | 2 +- .../dao/ThingsboardPostgreSQLDialect.java | 2 +- .../server/dao/TimescaleDaoConfig.java | 2 +- .../dao/TimescaleTsLatestDaoConfig.java | 2 +- .../server/dao/alarm/AlarmCommentDao.java | 2 +- .../server/dao/alarm/AlarmDao.java | 2 +- .../dao/alarm/AlarmTypesCacheEvictEvent.java | 2 +- .../dao/alarm/AlarmTypesCaffeineCache.java | 2 +- .../dao/alarm/AlarmTypesRedisCache.java | 2 +- .../dao/alarm/BaseAlarmCommentService.java | 23 +- .../server/dao/alarm/BaseAlarmService.java | 4 +- .../server/dao/aspect/DbCallStats.java | 2 +- .../dao/aspect/DbCallStatsSnapshot.java | 2 +- .../server/dao/aspect/MethodCallStats.java | 2 +- .../dao/aspect/MethodCallStatsSnapshot.java | 2 +- .../server/dao/aspect/SqlDaoCallsAspect.java | 2 +- .../dao/asset/AssetCacheEvictEvent.java | 2 +- .../server/dao/asset/AssetCacheKey.java | 2 +- .../server/dao/asset/AssetCaffeineCache.java | 2 +- .../server/dao/asset/AssetDao.java | 3 +- .../dao/asset/AssetProfileCacheKey.java | 2 +- .../dao/asset/AssetProfileCaffeineCache.java | 2 +- .../server/dao/asset/AssetProfileDao.java | 12 +- .../dao/asset/AssetProfileEvictEvent.java | 2 +- .../dao/asset/AssetProfileRedisCache.java | 2 +- .../dao/asset/AssetProfileServiceImpl.java | 47 +- .../server/dao/asset/AssetRedisCache.java | 2 +- .../server/dao/asset/AssetTypeFilter.java | 2 +- .../server/dao/asset/BaseAssetService.java | 19 +- .../dao/attributes/AttributeCacheKey.java | 2 +- .../attributes/AttributeCaffeineCache.java | 2 +- .../dao/attributes/AttributeRedisCache.java | 2 +- .../server/dao/attributes/AttributeUtils.java | 2 +- .../server/dao/attributes/AttributesDao.java | 2 +- .../dao/attributes/BaseAttributesService.java | 2 +- .../attributes/CachedAttributesService.java | 2 +- .../server/dao/audit/AuditLogDao.java | 2 +- .../server/dao/audit/AuditLogLevelFilter.java | 2 +- .../server/dao/audit/AuditLogLevelMask.java | 2 +- .../dao/audit/AuditLogLevelProperties.java | 2 +- .../server/dao/audit/AuditLogServiceImpl.java | 2 +- .../dao/audit/DummyAuditLogServiceImpl.java | 2 +- .../server/dao/audit/sink/AuditLogSink.java | 2 +- .../dao/audit/sink/DummyAuditLogSink.java | 2 +- .../audit/sink/ElasticsearchAuditLogSink.java | 2 +- .../dao/cache/CacheExecutorService.java | 2 +- .../BaseComponentDescriptorService.java | 2 +- .../dao/component/ComponentDescriptorDao.java | 2 +- .../server/dao/customer/CustomerDao.java | 2 +- .../dao/customer/CustomerServiceImpl.java | 4 +- .../server/dao/dashboard/DashboardDao.java | 4 +- .../dao/dashboard/DashboardInfoDao.java | 9 +- .../dao/dashboard/DashboardServiceImpl.java | 11 +- .../dashboard/DashboardTitleEvictEvent.java | 2 +- .../DashboardTitlesCaffeineCache.java | 2 +- .../dashboard/DashboardTitlesRedisCache.java | 2 +- .../server/dao/device/ClaimDataInfo.java | 2 +- .../DeviceConnectivityConfiguration.java | 5 +- .../dao/device/DeviceConnectivityInfo.java | 2 +- .../device/DeviceConnectivityServiceImpl.java | 75 +- .../DeviceCredentialsCaffeineCache.java | 2 +- .../dao/device/DeviceCredentialsDao.java | 2 +- .../device/DeviceCredentialsEvictEvent.java | 2 +- .../device/DeviceCredentialsRedisCache.java | 2 +- .../device/DeviceCredentialsServiceImpl.java | 2 +- .../server/dao/device/DeviceDao.java | 3 +- .../dao/device/DeviceProfileCacheKey.java | 2 +- .../device/DeviceProfileCaffeineCache.java | 2 +- .../server/dao/device/DeviceProfileDao.java | 12 +- .../dao/device/DeviceProfileEvictEvent.java | 2 +- .../dao/device/DeviceProfileRedisCache.java | 2 +- .../dao/device/DeviceProfileServiceImpl.java | 50 +- .../server/dao/device/DeviceServiceImpl.java | 14 +- .../server/dao/edge/BaseEdgeEventService.java | 2 +- .../DefaultEdgeSynchronizationManager.java | 2 +- .../server/dao/edge/EdgeCacheEvictEvent.java | 2 +- .../server/dao/edge/EdgeCacheKey.java | 2 +- .../server/dao/edge/EdgeCaffeineCache.java | 2 +- .../thingsboard/server/dao/edge/EdgeDao.java | 2 +- .../server/dao/edge/EdgeEventDao.java | 2 +- .../server/dao/edge/EdgeRedisCache.java | 2 +- .../server/dao/edge/EdgeServiceImpl.java | 2 +- .../entity/AbstractCachedEntityService.java | 2 +- .../dao/entity/AbstractCachedService.java | 2 +- .../dao/entity/AbstractEntityService.java | 2 +- .../dao/entity/BaseEntityCountService.java | 2 +- .../server/dao/entity/BaseEntityService.java | 2 +- .../entity/DefaultEntityServiceRegistry.java | 2 +- .../entity/EntityCountCacheEvictEvent.java | 2 +- .../dao/entity/EntityCountCacheKey.java | 2 +- .../server/dao/entity/EntityQueryDao.java | 2 +- .../count/EntityCountCaffeineCache.java | 2 +- .../entity/count/EntityCountRedisCache.java | 2 +- .../dao/entityview/EntityViewCacheKey.java | 2 +- .../dao/entityview/EntityViewCacheValue.java | 2 +- .../entityview/EntityViewCaffeineCache.java | 2 +- .../server/dao/entityview/EntityViewDao.java | 2 +- .../dao/entityview/EntityViewEvictEvent.java | 2 +- .../dao/entityview/EntityViewRedisCache.java | 2 +- .../dao/entityview/EntityViewServiceImpl.java | 13 +- .../server/dao/event/BaseEventService.java | 2 +- .../server/dao/event/EventDao.java | 2 +- .../dao/eventsourcing/ActionEntityEvent.java | 2 +- .../dao/eventsourcing/DeleteEntityEvent.java | 2 +- .../eventsourcing/RelationActionEvent.java | 2 +- .../dao/eventsourcing/SaveEntityEvent.java | 4 +- .../dao/exception/BufferLimitException.java | 2 +- .../exception/DataValidationException.java | 2 +- .../dao/exception/DatabaseException.java | 2 +- .../DeviceCredentialsValidationException.java | 2 +- .../dao/exception/EntitiesLimitException.java | 35 + .../IncorrectParameterException.java | 2 +- .../server/dao/model/BaseEntity.java | 2 +- .../server/dao/model/BaseSqlEntity.java | 2 +- .../server/dao/model/ModelConstants.java | 8 +- .../thingsboard/server/dao/model/ToData.java | 2 +- .../model/sql/AbstractAlarmCommentEntity.java | 2 +- .../dao/model/sql/AbstractAlarmEntity.java | 2 +- .../dao/model/sql/AbstractAssetEntity.java | 2 +- .../dao/model/sql/AbstractDeviceEntity.java | 2 +- .../dao/model/sql/AbstractEdgeEntity.java | 2 +- .../model/sql/AbstractEntityViewEntity.java | 2 +- .../dao/model/sql/AbstractTenantEntity.java | 2 +- .../dao/model/sql/AbstractTsKvEntity.java | 2 +- .../model/sql/AbstractWidgetTypeEntity.java | 2 +- .../dao/model/sql/AdminSettingsEntity.java | 2 +- .../dao/model/sql/AlarmCommentEntity.java | 2 +- .../dao/model/sql/AlarmCommentInfoEntity.java | 2 +- .../server/dao/model/sql/AlarmEntity.java | 2 +- .../server/dao/model/sql/AlarmInfoEntity.java | 2 +- .../dao/model/sql/ApiUsageStateEntity.java | 2 +- .../server/dao/model/sql/AssetEntity.java | 2 +- .../server/dao/model/sql/AssetInfoEntity.java | 2 +- .../dao/model/sql/AssetProfileEntity.java | 2 +- .../model/sql/AttributeKvCompositeKey.java | 2 +- .../dao/model/sql/AttributeKvEntity.java | 2 +- .../server/dao/model/sql/AuditLogEntity.java | 2 +- .../model/sql/ComponentDescriptorEntity.java | 7 +- .../server/dao/model/sql/CustomerEntity.java | 2 +- .../server/dao/model/sql/DashboardEntity.java | 2 +- .../dao/model/sql/DashboardInfoEntity.java | 2 +- .../model/sql/DeviceCredentialsEntity.java | 2 +- .../server/dao/model/sql/DeviceEntity.java | 2 +- .../dao/model/sql/DeviceInfoEntity.java | 2 +- .../dao/model/sql/DeviceProfileEntity.java | 2 +- .../server/dao/model/sql/EdgeEntity.java | 2 +- .../server/dao/model/sql/EdgeEventEntity.java | 2 +- .../server/dao/model/sql/EdgeInfoEntity.java | 2 +- .../model/sql/EntityAlarmCompositeKey.java | 2 +- .../dao/model/sql/EntityAlarmEntity.java | 2 +- .../dao/model/sql/EntityViewEntity.java | 2 +- .../dao/model/sql/EntityViewInfoEntity.java | 2 +- .../dao/model/sql/ErrorEventEntity.java | 2 +- .../server/dao/model/sql/EventEntity.java | 2 +- .../dao/model/sql/LifecycleEventEntity.java | 2 +- .../dao/model/sql/NotificationEntity.java | 2 +- .../model/sql/NotificationRequestEntity.java | 2 +- .../sql/NotificationRequestInfoEntity.java | 2 +- .../dao/model/sql/NotificationRuleEntity.java | 2 +- .../model/sql/NotificationRuleInfoEntity.java | 2 +- .../model/sql/NotificationTargetEntity.java | 2 +- .../model/sql/NotificationTemplateEntity.java | 2 +- ...Auth2ClientRegistrationTemplateEntity.java | 2 +- .../dao/model/sql/OAuth2DomainEntity.java | 2 +- .../dao/model/sql/OAuth2MobileEntity.java | 2 +- .../dao/model/sql/OAuth2ParamsEntity.java | 2 +- .../model/sql/OAuth2RegistrationEntity.java | 2 +- .../dao/model/sql/OtaPackageEntity.java | 2 +- .../dao/model/sql/OtaPackageInfoEntity.java | 2 +- .../server/dao/model/sql/QueueEntity.java | 2 +- .../dao/model/sql/RelationCompositeKey.java | 2 +- .../server/dao/model/sql/RelationEntity.java | 2 +- .../server/dao/model/sql/RpcEntity.java | 2 +- .../model/sql/RuleChainDebugEventEntity.java | 2 +- .../server/dao/model/sql/RuleChainEntity.java | 2 +- .../model/sql/RuleNodeDebugEventEntity.java | 2 +- .../server/dao/model/sql/RuleNodeEntity.java | 7 +- .../dao/model/sql/RuleNodeStateEntity.java | 2 +- .../dao/model/sql/StatisticsEventEntity.java | 2 +- .../dao/model/sql/TbResourceEntity.java | 45 +- .../dao/model/sql/TbResourceInfoEntity.java | 44 +- .../server/dao/model/sql/TenantEntity.java | 2 +- .../dao/model/sql/TenantInfoEntity.java | 2 +- .../dao/model/sql/TenantProfileEntity.java | 2 +- .../dao/model/sql/UserAuthSettingsEntity.java | 2 +- .../dao/model/sql/UserCredentialsEntity.java | 2 +- .../server/dao/model/sql/UserEntity.java | 2 +- .../dao/model/sql/UserSettingsEntity.java | 2 +- .../model/sql/WidgetTypeDetailsEntity.java | 2 +- .../dao/model/sql/WidgetTypeEntity.java | 2 +- .../dao/model/sql/WidgetTypeIdFqnEntity.java | 2 +- .../dao/model/sql/WidgetTypeInfoEntity.java | 2 +- .../dao/model/sql/WidgetsBundleEntity.java | 2 +- .../sql/WidgetsBundleWidgetCompositeKey.java | 2 +- .../model/sql/WidgetsBundleWidgetEntity.java | 2 +- .../sqlts/dictionary/TsKvDictionary.java | 2 +- .../TsKvDictionaryCompositeKey.java | 2 +- .../sqlts/latest/TsKvLatestCompositeKey.java | 2 +- .../model/sqlts/latest/TsKvLatestEntity.java | 2 +- .../ts/TimescaleTsKvCompositeKey.java | 2 +- .../timescale/ts/TimescaleTsKvEntity.java | 2 +- .../dao/model/sqlts/ts/TsKvCompositeKey.java | 2 +- .../server/dao/model/sqlts/ts/TsKvEntity.java | 2 +- .../dao/nosql/CassandraAbstractAsyncDao.java | 2 +- .../dao/nosql/CassandraAbstractDao.java | 2 +- .../CassandraBufferedRateReadExecutor.java | 2 +- .../CassandraBufferedRateWriteExecutor.java | 2 +- .../DefaultNotificationRequestService.java | 2 +- .../DefaultNotificationRuleService.java | 2 +- .../DefaultNotificationService.java | 2 +- .../DefaultNotificationSettingsService.java | 2 +- .../DefaultNotificationTargetService.java | 7 +- .../DefaultNotificationTemplateService.java | 2 +- .../notification/DefaultNotifications.java | 2 +- .../dao/notification/NotificationDao.java | 2 +- .../notification/NotificationRequestDao.java | 2 +- .../dao/notification/NotificationRuleDao.java | 2 +- .../notification/NotificationTargetDao.java | 2 +- .../notification/NotificationTemplateDao.java | 2 +- .../HybridClientRegistrationRepository.java | 2 +- .../OAuth2ClientRegistrationTemplateDao.java | 2 +- .../OAuth2ConfigTemplateServiceImpl.java | 2 +- .../dao/oauth2/OAuth2Configuration.java | 2 +- .../server/dao/oauth2/OAuth2DomainDao.java | 2 +- .../server/dao/oauth2/OAuth2MobileDao.java | 2 +- .../server/dao/oauth2/OAuth2ParamsDao.java | 2 +- .../dao/oauth2/OAuth2RegistrationDao.java | 2 +- .../server/dao/oauth2/OAuth2ServiceImpl.java | 2 +- .../server/dao/oauth2/OAuth2Utils.java | 2 +- .../server/dao/ota/BaseOtaPackageService.java | 6 +- .../dao/ota/OtaPackageCacheEvictEvent.java | 2 +- .../server/dao/ota/OtaPackageCacheKey.java | 2 +- .../dao/ota/OtaPackageCaffeineCache.java | 2 +- .../server/dao/ota/OtaPackageDao.java | 2 +- .../server/dao/ota/OtaPackageInfoDao.java | 2 +- .../server/dao/ota/OtaPackageRedisCache.java | 2 +- .../server/dao/queue/BaseQueueService.java | 4 +- .../server/dao/queue/QueueDao.java | 2 +- .../dao/relation/BaseRelationService.java | 2 +- .../dao/relation/EntityRelationEvent.java | 2 +- .../server/dao/relation/RelationCacheKey.java | 2 +- .../dao/relation/RelationCacheValue.java | 2 +- .../dao/relation/RelationCaffeineCache.java | 2 +- .../server/dao/relation/RelationDao.java | 2 +- .../dao/relation/RelationRedisCache.java | 2 +- .../server/dao/resource/BaseImageService.java | 672 ++ .../dao/resource/BaseResourceService.java | 86 +- .../server/dao/resource/ImageCacheKey.java | 62 + .../server/dao/resource/TbResourceDao.java | 15 +- .../dao/resource/TbResourceInfoDao.java | 21 +- .../server/dao/rpc/BaseRpcService.java | 2 +- .../thingsboard/server/dao/rpc/RpcDao.java | 2 +- .../server/dao/rule/BaseRuleChainService.java | 7 +- .../dao/rule/BaseRuleNodeStateService.java | 2 +- .../server/dao/rule/RuleChainDao.java | 2 +- .../server/dao/rule/RuleNodeDao.java | 2 +- .../server/dao/rule/RuleNodeStateDao.java | 2 +- .../dao/service/ConstraintValidator.java | 2 +- .../server/dao/service/DataValidator.java | 11 +- .../server/dao/service/NoXssValidator.java | 2 +- .../server/dao/service/PaginatedRemover.java | 2 +- .../dao/service/StringLengthValidator.java | 2 +- .../dao/service/TimePaginatedRemover.java | 2 +- .../server/dao/service/Validator.java | 4 +- .../AbstractHasOtaPackageValidator.java | 2 +- .../validator/AdminSettingsDataValidator.java | 2 +- .../validator/AlarmCommentDataValidator.java | 2 +- .../service/validator/AlarmDataValidator.java | 2 +- .../validator/ApiUsageDataValidator.java | 2 +- .../service/validator/AssetDataValidator.java | 2 +- .../validator/AssetProfileDataValidator.java | 2 +- .../validator/AuditLogDataValidator.java | 2 +- .../BaseOtaPackageDataValidator.java | 2 +- ...ientRegistrationTemplateDataValidator.java | 2 +- .../ComponentDescriptorDataValidator.java | 2 +- .../validator/CustomerDataValidator.java | 2 +- .../validator/DashboardDataValidator.java | 2 +- .../DeviceCredentialsDataValidator.java | 2 +- .../validator/DeviceDataValidator.java | 2 +- .../validator/DeviceProfileDataValidator.java | 2 +- .../service/validator/EdgeDataValidator.java | 2 +- .../validator/EdgeEventDataValidator.java | 2 +- .../validator/EntityViewDataValidator.java | 2 +- .../service/validator/EventDataValidator.java | 2 +- .../validator/OtaPackageDataValidator.java | 2 +- .../OtaPackageInfoDataValidator.java | 2 +- .../dao/service/validator/QueueValidator.java | 2 +- .../validator/ResourceDataValidator.java | 57 +- .../validator/RuleChainDataValidator.java | 11 +- .../validator/TenantDataValidator.java | 2 +- .../validator/TenantProfileDataValidator.java | 2 +- .../UserCredentialsDataValidator.java | 2 +- .../service/validator/UserDataValidator.java | 2 +- .../validator/WidgetTypeDataValidator.java | 2 +- .../validator/WidgetsBundleDataValidator.java | 2 +- .../server/dao/settings/AdminSettingsDao.java | 2 +- .../settings/AdminSettingsServiceImpl.java | 2 +- .../server/dao/sql/JpaAbstractDao.java | 2 +- ...paAbstractDaoListeningExecutorService.java | 2 +- .../server/dao/sql/JpaExecutorService.java | 2 +- .../sql/ScheduledLogExecutorComponent.java | 2 +- .../server/dao/sql/TbSqlBlockingQueue.java | 19 +- .../dao/sql/TbSqlBlockingQueueParams.java | 2 +- .../dao/sql/TbSqlBlockingQueueWrapper.java | 2 +- .../server/dao/sql/TbSqlQueue.java | 2 +- .../server/dao/sql/TbSqlQueueElement.java | 2 +- .../dao/sql/alarm/AlarmCommentRepository.java | 2 +- .../server/dao/sql/alarm/AlarmRepository.java | 2 +- .../dao/sql/alarm/EntityAlarmRepository.java | 2 +- .../dao/sql/alarm/JpaAlarmCommentDao.java | 2 +- .../server/dao/sql/alarm/JpaAlarmDao.java | 2 +- .../dao/sql/asset/AssetProfileRepository.java | 23 +- .../server/dao/sql/asset/AssetRepository.java | 5 +- .../server/dao/sql/asset/JpaAssetDao.java | 10 +- .../dao/sql/asset/JpaAssetProfileDao.java | 28 +- .../AttributeKvInsertRepository.java | 2 +- .../sql/attributes/AttributeKvRepository.java | 2 +- .../dao/sql/attributes/JpaAttributeDao.java | 2 +- .../SqlAttributesInsertRepository.java | 2 +- .../dao/sql/audit/AuditLogRepository.java | 2 +- .../server/dao/sql/audit/JpaAuditLogDao.java | 2 +- ...ctComponentDescriptorInsertRepository.java | 5 +- .../ComponentDescriptorInsertRepository.java | 2 +- .../ComponentDescriptorRepository.java | 2 +- .../JpaBaseComponentDescriptorDao.java | 2 +- ...qlComponentDescriptorInsertRepository.java | 6 +- .../dao/sql/customer/CustomerRepository.java | 2 +- .../dao/sql/customer/JpaCustomerDao.java | 2 +- .../dashboard/DashboardInfoRepository.java | 15 +- .../sql/dashboard/DashboardRepository.java | 5 +- .../dao/sql/dashboard/JpaDashboardDao.java | 7 +- .../sql/dashboard/JpaDashboardInfoDao.java | 14 +- .../device/DefaultNativeDeviceRepository.java | 2 +- .../device/DeviceCredentialsRepository.java | 2 +- .../sql/device/DeviceProfileRepository.java | 23 +- .../dao/sql/device/DeviceRepository.java | 5 +- .../sql/device/JpaDeviceCredentialsDao.java | 2 +- .../server/dao/sql/device/JpaDeviceDao.java | 10 +- .../dao/sql/device/JpaDeviceProfileDao.java | 28 +- .../sql/device/NativeDeviceRepository.java | 2 +- .../sql/edge/EdgeEventInsertRepository.java | 2 +- .../dao/sql/edge/EdgeEventRepository.java | 2 +- .../server/dao/sql/edge/EdgeRepository.java | 2 +- .../dao/sql/edge/JpaBaseEdgeEventDao.java | 2 +- .../server/dao/sql/edge/JpaEdgeDao.java | 2 +- .../sql/entityview/EntityViewRepository.java | 2 +- .../dao/sql/entityview/JpaEntityViewDao.java | 2 +- .../dao/sql/event/ErrorEventRepository.java | 2 +- .../dao/sql/event/EventCleanupRepository.java | 2 +- .../dao/sql/event/EventInsertRepository.java | 2 +- .../event/EventPartitionConfiguration.java | 2 +- .../server/dao/sql/event/EventRepository.java | 2 +- .../server/dao/sql/event/JpaBaseEventDao.java | 2 +- .../sql/event/LifecycleEventRepository.java | 2 +- .../event/RuleChainDebugEventRepository.java | 2 +- .../event/RuleNodeDebugEventRepository.java | 2 +- .../sql/event/SqlEventCleanupRepository.java | 2 +- .../sql/event/StatisticsEventRepository.java | 2 +- .../sql/notification/JpaNotificationDao.java | 2 +- .../JpaNotificationRequestDao.java | 2 +- .../notification/JpaNotificationRuleDao.java | 2 +- .../JpaNotificationTargetDao.java | 2 +- .../JpaNotificationTemplateDao.java | 2 +- .../notification/NotificationRepository.java | 2 +- .../NotificationRequestRepository.java | 2 +- .../NotificationRuleRepository.java | 2 +- .../NotificationTargetRepository.java | 2 +- .../NotificationTemplateRepository.java | 2 +- ...paOAuth2ClientRegistrationTemplateDao.java | 2 +- .../dao/sql/oauth2/JpaOAuth2DomainDao.java | 2 +- .../dao/sql/oauth2/JpaOAuth2MobileDao.java | 2 +- .../dao/sql/oauth2/JpaOAuth2ParamsDao.java | 2 +- .../sql/oauth2/JpaOAuth2RegistrationDao.java | 2 +- ...2ClientRegistrationTemplateRepository.java | 2 +- .../sql/oauth2/OAuth2DomainRepository.java | 2 +- .../sql/oauth2/OAuth2MobileRepository.java | 2 +- .../sql/oauth2/OAuth2ParamsRepository.java | 2 +- .../oauth2/OAuth2RegistrationRepository.java | 2 +- .../server/dao/sql/ota/JpaOtaPackageDao.java | 2 +- .../dao/sql/ota/JpaOtaPackageInfoDao.java | 2 +- .../dao/sql/ota/OtaPackageInfoRepository.java | 2 +- .../dao/sql/ota/OtaPackageRepository.java | 2 +- .../dao/sql/query/AlarmDataAdapter.java | 2 +- .../dao/sql/query/AlarmQueryRepository.java | 2 +- .../query/DefaultAlarmQueryRepository.java | 2 +- .../query/DefaultEntityQueryRepository.java | 2 +- .../sql/query/DefaultQueryLogComponent.java | 2 +- .../dao/sql/query/EntityDataAdapter.java | 2 +- .../dao/sql/query/EntityKeyMapping.java | 2 +- .../dao/sql/query/EntityQueryRepository.java | 2 +- .../dao/sql/query/JpaEntityQueryDao.java | 2 +- .../server/dao/sql/query/QueryContext.java | 2 +- .../dao/sql/query/QueryLogComponent.java | 2 +- .../dao/sql/query/QuerySecurityContext.java | 2 +- .../server/dao/sql/queue/JpaQueueDao.java | 2 +- .../server/dao/sql/queue/QueueRepository.java | 2 +- .../dao/sql/relation/JpaRelationDao.java | 2 +- .../JpaRelationQueryExecutorService.java | 2 +- .../relation/RelationInsertRepository.java | 2 +- .../dao/sql/relation/RelationRepository.java | 2 +- .../relation/SqlRelationInsertRepository.java | 2 +- .../dao/sql/resource/JpaTbResourceDao.java | 43 +- .../sql/resource/JpaTbResourceInfoDao.java | 58 +- .../resource/TbResourceInfoRepository.java | 38 +- .../sql/resource/TbResourceRepository.java | 21 +- .../server/dao/sql/rpc/JpaRpcDao.java | 2 +- .../server/dao/sql/rpc/RpcRepository.java | 2 +- .../server/dao/sql/rule/JpaRuleChainDao.java | 2 +- .../server/dao/sql/rule/JpaRuleNodeDao.java | 2 +- .../dao/sql/rule/JpaRuleNodeStateDao.java | 2 +- .../dao/sql/rule/RuleChainRepository.java | 2 +- .../dao/sql/rule/RuleNodeRepository.java | 4 +- .../dao/sql/rule/RuleNodeStateRepository.java | 2 +- .../sql/settings/AdminSettingsRepository.java | 2 +- .../dao/sql/settings/JpaAdminSettingsDao.java | 2 +- .../server/dao/sql/tenant/JpaTenantDao.java | 2 +- .../dao/sql/tenant/JpaTenantProfileDao.java | 2 +- .../sql/tenant/TenantProfileRepository.java | 2 +- .../dao/sql/tenant/TenantRepository.java | 2 +- .../usagerecord/ApiUsageStateRepository.java | 2 +- .../sql/usagerecord/JpaApiUsageStateDao.java | 2 +- .../dao/sql/user/JpaUserAuthSettingsDao.java | 2 +- .../dao/sql/user/JpaUserCredentialsDao.java | 2 +- .../server/dao/sql/user/JpaUserDao.java | 2 +- .../dao/sql/user/JpaUserSettingsDao.java | 2 +- .../sql/user/UserAuthSettingsRepository.java | 2 +- .../sql/user/UserCredentialsRepository.java | 2 +- .../server/dao/sql/user/UserRepository.java | 2 +- .../dao/sql/user/UserSettingsRepository.java | 2 +- .../dao/sql/widget/JpaWidgetTypeDao.java | 25 +- .../dao/sql/widget/JpaWidgetsBundleDao.java | 18 +- .../sql/widget/WidgetTypeInfoRepository.java | 15 +- .../dao/sql/widget/WidgetTypeRepository.java | 12 +- .../sql/widget/WidgetsBundleRepository.java | 8 +- .../widget/WidgetsBundleWidgetRepository.java | 2 +- ...stractChunkedAggregationTimeseriesDao.java | 25 +- .../dao/sqlts/AbstractSqlTimeseriesDao.java | 2 +- .../dao/sqlts/AggregationTimeseriesDao.java | 2 +- .../sqlts/BaseAbstractSqlTimeseriesDao.java | 10 +- .../server/dao/sqlts/EntityContainer.java | 2 +- .../dao/sqlts/SqlTimeseriesLatestDao.java | 2 +- .../thingsboard/server/dao/sqlts/TsKey.java | 2 +- .../dictionary/TsKvDictionaryRepository.java | 2 +- .../insert/AbstractInsertRepository.java | 2 +- .../dao/sqlts/insert/InsertTsRepository.java | 2 +- .../latest/InsertLatestTsRepository.java | 2 +- .../sql/SqlLatestInsertTsRepository.java | 2 +- .../insert/sql/SqlInsertTsRepository.java | 2 +- .../insert/sql/SqlPartitioningRepository.java | 2 +- .../TimescaleInsertTsRepository.java | 2 +- .../latest/SearchTsKvLatestRepository.java | 2 +- .../sqlts/latest/TsKvLatestRepository.java | 2 +- .../dao/sqlts/sql/JpaSqlTimeseriesDao.java | 2 +- .../timescale/AggregationRepository.java | 2 +- .../timescale/TimescaleTimeseriesDao.java | 26 +- .../timescale/TsKvTimescaleRepository.java | 2 +- .../server/dao/sqlts/ts/TsKvRepository.java | 2 +- .../tenant/DefaultTbTenantProfileCache.java | 2 +- .../dao/tenant/TenantCaffeineCache.java | 2 +- .../server/dao/tenant/TenantDao.java | 2 +- .../server/dao/tenant/TenantEvictEvent.java | 2 +- .../dao/tenant/TenantExistsCaffeineCache.java | 2 +- .../dao/tenant/TenantExistsRedisCache.java | 2 +- .../dao/tenant/TenantProfileCacheKey.java | 2 +- .../tenant/TenantProfileCaffeineCache.java | 2 +- .../server/dao/tenant/TenantProfileDao.java | 2 +- .../dao/tenant/TenantProfileEvictEvent.java | 2 +- .../dao/tenant/TenantProfileRedisCache.java | 2 +- .../dao/tenant/TenantProfileServiceImpl.java | 4 +- .../server/dao/tenant/TenantRedisCache.java | 2 +- .../server/dao/tenant/TenantServiceImpl.java | 4 +- .../AbstractCassandraBaseTimeseriesDao.java | 2 +- .../AggregatePartitionsFunction.java | 2 +- .../dao/timeseries/BaseTimeseriesService.java | 2 +- .../CassandraBaseTimeseriesDao.java | 20 +- .../CassandraBaseTimeseriesLatestDao.java | 2 +- .../CassandraPartitionCacheKey.java | 2 +- .../CassandraTsPartitionsCache.java | 2 +- .../dao/timeseries/NoSqlTsPartitionDate.java | 2 +- .../server/dao/timeseries/QueryCursor.java | 2 +- .../timeseries/SimpleListenableFuture.java | 2 +- .../server/dao/timeseries/SqlPartition.java | 2 +- .../dao/timeseries/SqlTsPartitionDate.java | 2 +- .../server/dao/timeseries/TimeseriesDao.java | 2 +- .../dao/timeseries/TimeseriesLatestDao.java | 2 +- .../dao/timeseries/TsInsertExecutorType.java | 2 +- .../dao/timeseries/TsKvQueryCursor.java | 4 +- .../dao/usage/BasicUsageInfoService.java | 2 +- .../dao/usagerecord/ApiUsageStateDao.java | 2 +- .../usagerecord/ApiUsageStateServiceImpl.java | 2 +- .../usagerecord/DefaultApiLimitService.java | 2 +- .../server/dao/user/UserAuthSettingsDao.java | 2 +- .../server/dao/user/UserCredentialsDao.java | 2 +- .../thingsboard/server/dao/user/UserDao.java | 2 +- .../server/dao/user/UserServiceImpl.java | 4 +- .../dao/user/UserSettingsCaffeineCache.java | 2 +- .../server/dao/user/UserSettingsDao.java | 2 +- .../dao/user/UserSettingsEvictEvent.java | 2 +- .../dao/user/UserSettingsRedisCache.java | 2 +- .../dao/user/UserSettingsServiceImpl.java | 2 +- .../util/AbstractBufferedRateExecutor.java | 2 +- .../server/dao/util/AsyncRateLimiter.java | 2 +- .../server/dao/util/AsyncTaskContext.java | 2 +- .../server/dao/util/BufferedRateExecutor.java | 2 +- .../dao/util/BufferedRateExecutorStats.java | 2 +- .../dao/util/DeviceConnectivityUtil.java | 162 +- .../server/dao/util/ImageUtils.java | 267 + .../dao/util/JsonNodeProcessingTask.java | 30 + .../dao/util/JsonPathProcessingTask.java | 70 + .../thingsboard/server/dao/util/KvUtils.java | 2 +- .../dao/util/TenantRateLimitException.java | 2 +- .../server/dao/util/TimeUtils.java | 45 + .../util/limits/DefaultRateLimitService.java | 2 +- .../dao/util/limits/RateLimitService.java | 2 +- .../AbstractJsonSqlTypeDescriptor.java | 2 +- .../mapping/JsonBinarySqlTypeDescriptor.java | 2 +- .../dao/util/mapping/JsonBinaryType.java | 2 +- .../mapping/JsonStringSqlTypeDescriptor.java | 2 +- .../dao/util/mapping/JsonStringType.java | 2 +- .../dao/util/mapping/JsonTypeDescriptor.java | 2 +- .../server/dao/widget/WidgetTypeDao.java | 7 +- .../dao/widget/WidgetTypeServiceImpl.java | 11 +- .../server/dao/widget/WidgetsBundleDao.java | 8 +- .../dao/widget/WidgetsBundleServiceImpl.java | 9 +- .../resources/cassandra/schema-keyspace.cql | 2 +- .../resources/cassandra/schema-ts-latest.cql | 2 +- .../main/resources/cassandra/schema-ts.cql | 2 +- .../sql/schema-entities-idx-psql-addon.sql | 2 +- .../resources/sql/schema-entities-idx.sql | 16 +- .../main/resources/sql/schema-entities.sql | 13 +- .../main/resources/sql/schema-timescale.sql | 2 +- dao/src/main/resources/sql/schema-ts-psql.sql | 2 +- .../sql/schema-views-and-functions.sql | 2 +- dao/src/main/resources/xss-policy.xml | 2 +- .../server/dao/AbstractDaoServiceTest.java | 2 +- .../server/dao/AbstractJpaDaoTest.java | 2 +- .../server/dao/AbstractNoSqlContainer.java | 3 +- .../server/dao/AbstractRedisContainer.java | 2 +- .../server/dao/NoSqlDaoServiceTestSuite.java | 2 +- .../server/dao/PostgreSqlInitializer.java | 2 +- .../server/dao/RedisSqlTestSuite.java | 2 +- .../dao/TimescaleDaoServiceTestSuite.java | 2 +- .../server/dao/TimescaleSqlInitializer.java | 2 +- .../eventsourcing/DeleteEntityEventTest.java | 2 +- .../nosql/CassandraPartitionsCacheTest.java | 2 +- .../dao/service/AbstractServiceTest.java | 2 +- .../dao/service/AdminSettingsServiceTest.java | 2 +- .../dao/service/AlarmCommentServiceTest.java | 2 +- .../server/dao/service/AlarmServiceTest.java | 2 +- .../dao/service/ApiUsageStateServiceTest.java | 2 +- .../dao/service/AssetProfileServiceTest.java | 99 +- .../server/dao/service/AssetServiceTest.java | 41 +- .../dao/service/ConstraintValidatorTest.java | 2 +- .../dao/service/CustomerServiceTest.java | 2 +- .../server/dao/service/DaoNoSqlTest.java | 2 +- .../server/dao/service/DaoSqlTest.java | 2 +- .../server/dao/service/DaoTimescaleTest.java | 2 +- .../dao/service/DashboardServiceTest.java | 2 +- .../server/dao/service/DataValidatorTest.java | 2 +- .../service/DeviceCredentialsCacheTest.java | 2 +- .../service/DeviceCredentialsServiceTest.java | 2 +- .../dao/service/DeviceProfileServiceTest.java | 96 +- .../server/dao/service/DeviceServiceTest.java | 31 +- .../dao/service/EdgeEventServiceTest.java | 2 +- .../server/dao/service/EdgeServiceTest.java | 2 +- .../service/EntityServiceRegistryTest.java | 2 +- .../server/dao/service/EntityServiceTest.java | 2 +- .../dao/service/NoXssValidatorTest.java | 2 +- .../OAuth2ConfigTemplateServiceTest.java | 2 +- .../server/dao/service/OAuth2ServiceTest.java | 2 +- .../dao/service/OtaPackageServiceTest.java | 4 +- .../server/dao/service/QueueServiceTest.java | 2 +- .../server/dao/service/RelationCacheTest.java | 2 +- .../dao/service/RelationServiceTest.java | 2 +- .../dao/service/RuleChainServiceTest.java | 2 +- .../dao/service/TbCacheSerializationTest.java | 2 +- .../dao/service/TenantProfileServiceTest.java | 2 +- .../server/dao/service/TenantServiceTest.java | 5 +- .../server/dao/service/UserServiceTest.java | 2 +- .../dao/service/WidgetTypeServiceTest.java | 2 +- .../dao/service/WidgetsBundleServiceTest.java | 2 +- .../attributes/BaseAttributesServiceTest.java | 2 +- .../sql/AttributesServiceSqlTest.java | 2 +- .../service/event/BaseEventServiceTest.java | 2 +- .../event/sql/EventServiceSqlTest.java | 2 +- .../install/sql/EntitiesSchemaSqlTest.java | 2 +- .../timeseries/BaseTimeseriesServiceTest.java | 2 +- .../nosql/TimeseriesServiceNoSqlTest.java | 2 +- .../nosql/TimeseriesServiceTimescaleTest.java | 2 +- .../sql/TimeseriesServiceSqlTest.java | 2 +- .../AdminSettingsDataValidatorTest.java | 2 +- .../validator/AlarmDataValidatorTest.java | 2 +- .../validator/AssetDataValidatorTest.java | 2 +- .../AssetProfileDataValidatorTest.java | 2 +- .../BaseOtaPackageDataValidatorTest.java | 2 +- .../ComponentDescriptorDataValidatorTest.java | 2 +- .../validator/CustomerDataValidatorTest.java | 2 +- .../validator/DashboardDataValidatorTest.java | 2 +- .../validator/DeviceDataValidatorTest.java | 2 +- .../DeviceProfileDataValidatorTest.java | 2 +- .../validator/EdgeDataValidatorTest.java | 2 +- .../EntityViewDataValidatorTest.java | 2 +- .../validator/ResourceDataValidatorTest.java | 2 +- .../validator/RuleChainDataValidatorTest.java | 2 +- .../validator/TenantDataValidatorTest.java | 2 +- .../TenantProfileDataValidatorTest.java | 2 +- .../WidgetTypeDataValidatorTest.java | 2 +- .../WidgetsBundleDataValidatorTest.java | 2 +- .../dao/sql/alarm/JpaAlarmCommentDaoTest.java | 2 +- .../server/dao/sql/alarm/JpaAlarmDaoTest.java | 2 +- .../server/dao/sql/asset/JpaAssetDaoTest.java | 2 +- .../dao/sql/audit/JpaAuditLogDaoTest.java | 2 +- .../JpaBaseComponentDescriptorDaoTest.java | 2 +- .../dao/sql/customer/JpaCustomerDaoTest.java | 2 +- .../dashboard/JpaDashboardInfoDaoTest.java | 2 +- .../device/JpaDeviceCredentialsDaoTest.java | 2 +- .../dao/sql/device/JpaDeviceDaoTest.java | 2 +- .../dao/sql/event/JpaBaseEventDaoTest.java | 2 +- .../DefaultEntityQueryRepositoryTest.java | 2 +- .../query/DefaultQueryLogComponentTest.java | 2 +- .../dao/sql/query/EntityDataAdapterTest.java | 2 +- .../dao/sql/query/EntityKeyMappingTest.java | 2 +- .../dao/sql/rule/JpaRuleNodeDaoTest.java | 2 +- .../dao/sql/tenant/JpaTenantDaoTest.java | 2 +- .../sql/user/JpaUserCredentialsDaoTest.java | 2 +- .../server/dao/sql/user/JpaUserDaoTest.java | 2 +- .../dao/sql/user/JpaUserSettingsDaoTest.java | 2 +- .../dao/sql/widget/JpaWidgetTypeDaoTest.java | 25 +- .../sql/widget/JpaWidgetsBundleDaoTest.java | 2 +- ...ctChunkedAggregationTimeseriesDaoTest.java | 2 +- ...esDaoPartitioningDaysAlwaysExistsTest.java | 2 +- ...sDaoPartitioningHoursAlwaysExistsTest.java | 2 +- ...artitioningIndefiniteAlwaysExistsTest.java | 2 +- ...aoPartitioningMinutesAlwaysExistsTest.java | 2 +- ...DaoPartitioningMonthsAlwaysExistsTest.java | 2 +- ...sDaoPartitioningYearsAlwaysExistsTest.java | 2 +- .../dao/util/DeviceConnectivityUtilTest.java | 32 + .../server/dao/util/TimeUtilsTest.java | 60 + docker/compose-utils.sh | 2 +- docker/docker-check-log-folders.sh | 2 +- docker/docker-compose.aws-sqs.yml | 2 +- docker/docker-compose.cassandra.volumes.yml | 2 +- docker/docker-compose.confluent.yml | 2 +- docker/docker-compose.hybrid.yml | 4 +- docker/docker-compose.kafka.yml | 2 +- docker/docker-compose.postgres.volumes.yml | 2 +- docker/docker-compose.postgres.yml | 4 +- docker/docker-compose.prometheus-grafana.yml | 2 +- docker/docker-compose.pubsub.yml | 2 +- docker/docker-compose.rabbitmq.yml | 2 +- .../docker-compose.redis-cluster.volumes.yml | 2 +- docker/docker-compose.redis-cluster.yml | 2 +- .../docker-compose.redis-sentinel.volumes.yml | 2 +- docker/docker-compose.redis-sentinel.yml | 2 +- docker/docker-compose.redis.volumes.yml | 2 +- docker/docker-compose.redis.yml | 2 +- docker/docker-compose.service-bus.yml | 2 +- docker/docker-compose.volumes.yml | 2 +- docker/docker-compose.yml | 2 +- docker/docker-create-log-folders.sh | 2 +- docker/docker-install-tb.sh | 2 +- docker/docker-remove-services.sh | 2 +- docker/docker-start-services.sh | 2 +- docker/docker-stop-services.sh | 2 +- docker/docker-update-service.sh | 2 +- docker/docker-upgrade-tb.sh | 2 +- .../provisioning/dashboards/dashboard.yml | 2 +- .../provisioning/datasources/datasource.yml | 2 +- docker/monitoring/prometheus/prometheus.yml | 2 +- docker/tb-transports/coap/conf/logback.xml | 2 +- .../coap/conf/tb-coap-transport.conf | 2 +- docker/tb-transports/http/conf/logback.xml | 2 +- .../http/conf/tb-http-transport.conf | 2 +- docker/tb-transports/lwm2m/conf/logback.xml | 2 +- .../lwm2m/conf/tb-lwm2m-transport.conf | 2 +- docker/tb-transports/mqtt/conf/logback.xml | 2 +- .../mqtt/conf/tb-mqtt-transport.conf | 2 +- docker/tb-transports/snmp/conf/logback.xml | 2 +- .../snmp/conf/tb-snmp-transport.conf | 2 +- docker/tb-vc-executor/conf/logback.xml | 2 +- .../tb-vc-executor/conf/tb-vc-executor.conf | 2 +- license-header-template.txt | 2 +- monitoring/pom.xml | 4 +- monitoring/src/main/conf/logback.xml | 2 +- monitoring/src/main/conf/tb-monitoring.conf | 2 +- .../ThingsboardMonitoringApplication.java | 2 +- .../monitoring/client/Lwm2mClient.java | 2 +- .../monitoring/client/TbClient.java | 2 +- .../monitoring/client/WsClient.java | 2 +- .../monitoring/client/WsClientFactory.java | 2 +- .../monitoring/config/MonitoringConfig.java | 2 +- .../monitoring/config/MonitoringTarget.java | 10 +- .../CoapTransportMonitoringConfig.java | 2 +- .../config/transport/DeviceConfig.java | 2 +- .../HttpTransportMonitoringConfig.java | 2 +- .../Lwm2mTransportMonitoringConfig.java | 2 +- .../MqttTransportMonitoringConfig.java | 2 +- .../config/transport/TransportInfo.java | 9 +- .../transport/TransportMonitoringConfig.java | 5 +- .../transport/TransportMonitoringTarget.java | 9 +- .../config/transport/TransportType.java | 11 +- .../monitoring/data/Latencies.java | 6 +- .../thingsboard/monitoring/data/Latency.java | 50 +- .../monitoring/data/MonitoredServiceKey.java | 2 +- .../data/ServiceFailureException.java | 2 +- .../monitoring/data/cmd/CmdsWrapper.java | 2 +- .../monitoring/data/cmd/EntityDataCmd.java | 2 +- .../monitoring/data/cmd/EntityDataUpdate.java | 2 +- .../monitoring/data/cmd/LatestValueCmd.java | 2 +- .../notification/HighLatencyNotification.java | 12 +- .../data/notification/Notification.java | 2 +- .../ServiceFailureNotification.java | 4 +- .../ServiceRecoveryNotification.java | 4 +- .../notification/NotificationService.java | 20 +- .../channels/NotificationChannel.java | 6 +- .../impl/SlackNotificationChannel.java | 13 +- .../monitoring/service/BaseHealthChecker.java | 17 +- .../service/BaseMonitoringService.java | 91 +- .../service/MonitoringReporter.java | 28 +- .../transport/TransportHealthChecker.java | 98 +- .../TransportsMonitoringService.java | 9 +- .../impl/CoapTransportHealthChecker.java | 2 +- .../impl/HttpTransportHealthChecker.java | 2 +- .../impl/Lwm2mTransportHealthChecker.java | 2 +- .../impl/MqttTransportHealthChecker.java | 2 +- .../monitoring/util/ResourceUtils.java | 2 +- .../monitoring/util/TbStopWatch.java | 2 +- monitoring/src/main/resources/logback.xml | 2 +- .../src/main/resources/lwm2m/models/0.xml | 2 +- .../src/main/resources/lwm2m/models/1.xml | 2 +- .../src/main/resources/lwm2m/models/2.xml | 2 +- .../resources/lwm2m/models/test-model.xml | 2 +- .../src/main/resources/root_rule_chain.json | 436 ++ .../src/main/resources/tb-monitoring.yml | 31 +- msa/black-box-tests/pom.xml | 4 +- .../server/msa/AbstractContainerTest.java | 2 +- .../server/msa/ContainerTestSuite.java | 4 +- .../server/msa/DisableUIListeners.java | 2 +- .../server/msa/DockerComposeExecutor.java | 2 +- .../msa/SeleniumRemoteWebDriverTest.java | 2 +- .../server/msa/TestCoapClient.java | 2 +- .../server/msa/TestCoapClientCallback.java | 2 +- .../thingsboard/server/msa/TestListener.java | 2 +- .../server/msa/TestProperties.java | 11 +- .../server/msa/TestRestClient.java | 43 +- .../server/msa/ThingsBoardDbInstaller.java | 8 +- .../org/thingsboard/server/msa/WsClient.java | 2 +- .../msa/connectivity/CoapClientTest.java | 2 +- .../msa/connectivity/HttpClientTest.java | 2 +- .../msa/connectivity/MqttClientTest.java | 11 +- .../connectivity/MqttGatewayClientTest.java | 2 +- .../server/msa/mapper/AttributesResponse.java | 2 +- .../msa/mapper/WsTelemetryResponse.java | 2 +- .../msa/prototypes/DevicePrototypes.java | 2 +- .../server/msa/rule/node/MqttNodeTest.java | 204 + .../server/msa/ui/base/AbstractBasePage.java | 2 +- .../msa/ui/base/AbstractDriverBaseTest.java | 2 +- .../msa/ui/listeners/RetryAnalyzer.java | 2 +- .../msa/ui/listeners/RetryTestListener.java | 2 +- .../pages/AlarmDetailsEntityTabElements.java | 2 +- .../ui/pages/AlarmDetailsEntityTabHelper.java | 2 +- .../ui/pages/AlarmDetailsViewElements.java | 2 +- .../msa/ui/pages/AlarmDetailsViewHelper.java | 2 +- .../msa/ui/pages/AlarmWidgetElements.java | 2 +- .../msa/ui/pages/AssetPageElements.java | 2 +- .../server/msa/ui/pages/AssetPageHelper.java | 2 +- .../ui/pages/CreateWidgetPopupElements.java | 2 +- .../msa/ui/pages/CreateWidgetPopupHelper.java | 2 +- .../msa/ui/pages/CustomerPageElements.java | 2 +- .../msa/ui/pages/CustomerPageHelper.java | 2 +- .../msa/ui/pages/DashboardPageElements.java | 2 +- .../msa/ui/pages/DashboardPageHelper.java | 2 +- .../msa/ui/pages/DevicePageElements.java | 2 +- .../server/msa/ui/pages/DevicePageHelper.java | 2 +- .../msa/ui/pages/EntityViewPageElements.java | 2 +- .../msa/ui/pages/EntityViewPageHelper.java | 2 +- .../msa/ui/pages/LoginPageElements.java | 2 +- .../server/msa/ui/pages/LoginPageHelper.java | 2 +- .../ui/pages/OpenRuleChainPageElements.java | 2 +- .../msa/ui/pages/OpenRuleChainPageHelper.java | 2 +- .../msa/ui/pages/OtherPageElements.java | 2 +- .../msa/ui/pages/OtherPageElementsHelper.java | 2 +- .../msa/ui/pages/ProfilesPageElements.java | 2 +- .../msa/ui/pages/ProfilesPageHelper.java | 2 +- .../msa/ui/pages/RuleChainsPageElements.java | 2 +- .../msa/ui/pages/RuleChainsPageHelper.java | 2 +- .../msa/ui/pages/SideBarMenuViewElements.java | 2 +- .../msa/ui/pages/SideBarMenuViewHelper.java | 2 +- .../msa/ui/tabs/AssignDeviceTabElements.java | 2 +- .../msa/ui/tabs/AssignDeviceTabHelper.java | 2 +- .../msa/ui/tabs/CreateDeviceTabElements.java | 2 +- .../msa/ui/tabs/CreateDeviceTabHelper.java | 2 +- .../alarmassignee/AbstractAssignTest.java | 2 +- .../AssignDetailsTabAssignTest.java | 2 +- ...ssignDetailsTabFromCustomerAssignTest.java | 2 +- .../AssignFromAlarmWidgetTest.java | 2 +- .../AssetProfileEditMenuTest.java | 2 +- .../CreateAssetProfileImportTest.java | 2 +- .../CreateAssetProfileTest.java | 2 +- .../DeleteAssetProfileTest.java | 2 +- .../DeleteSeveralAssetProfilesTest.java | 2 +- .../MakeAssetProfileDefaultTest.java | 2 +- .../SearchAssetProfileTest.java | 2 +- .../assetProfileSmoke/SortByNameTest.java | 2 +- .../customerSmoke/CreateCustomerTest.java | 2 +- .../customerSmoke/CustomerEditMenuTest.java | 2 +- .../customerSmoke/DeleteCustomerTest.java | 2 +- .../DeleteSeveralCustomerTest.java | 2 +- .../ManageCustomersAssetsTest.java | 2 +- .../ManageCustomersDashboardsTest.java | 2 +- .../ManageCustomersDevicesTest.java | 2 +- .../ManageCustomersEdgesTest.java | 2 +- .../ManageCustomersUsersTest.java | 2 +- .../customerSmoke/SearchCustomerTest.java | 2 +- .../tests/customerSmoke/SortByNameTest.java | 2 +- .../CreateDeviceProfileImportTest.java | 2 +- .../CreateDeviceProfileTest.java | 2 +- .../DeleteDeviceProfileTest.java | 2 +- .../DeleteSeveralDeviceProfilesTest.java | 2 +- .../DeviceProfileEditMenuTest.java | 2 +- .../MakeDeviceProfileDefaultTest.java | 2 +- .../SearchDeviceProfileTest.java | 2 +- .../deviceProfileSmoke/SortByNameTest.java | 2 +- .../devicessmoke/AbstractDeviceTest.java | 2 +- .../devicessmoke/AssignToCustomerTest.java | 2 +- .../tests/devicessmoke/CreateDeviceTest.java | 2 +- .../tests/devicessmoke/DeleteDeviceTest.java | 2 +- .../DeleteSeveralDevicesTest.java | 2 +- .../tests/devicessmoke/DeviceFilterTest.java | 2 +- .../ui/tests/devicessmoke/EditDeviceTest.java | 2 +- .../devicessmoke/MakeDevicePrivateTest.java | 2 +- .../devicessmoke/MakeDevicePublicTest.java | 2 +- .../AbstractRuleChainTest.java | 2 +- .../CreateRuleChainImportTest.java | 2 +- .../rulechainssmoke/CreateRuleChainTest.java | 2 +- .../rulechainssmoke/DeleteRuleChainTest.java | 2 +- .../DeleteSeveralRuleChainsTest.java | 2 +- .../MakeRuleChainRootTest.java | 2 +- .../rulechainssmoke/OpenRuleChainTest.java | 2 +- .../RuleChainEditMenuTest.java | 2 +- .../rulechainssmoke/SearchRuleChainTest.java | 2 +- .../tests/rulechainssmoke/SortByNameTest.java | 2 +- .../tests/rulechainssmoke/SortByTimeTest.java | 2 +- .../server/msa/ui/utils/Const.java | 2 +- .../msa/ui/utils/DataProviderCredential.java | 2 +- .../server/msa/ui/utils/EntityPrototypes.java | 2 +- .../resources/MqttRuleNodeTestMetadata.json | 79 + .../src/test/resources/alarmAssignee.xml | 2 +- .../src/test/resources/all.xml | 2 +- .../src/test/resources/connectivity.xml | 2 +- .../docker-compose.hybrid-test-extras.yml | 2 +- .../resources/docker-compose.mosquitto.yml | 25 + .../docker-compose.postgres-test-extras.yml | 2 +- .../docker-compose.rabbitmq-server.yml | 2 +- .../src/test/resources/docker-selenium.yml | 2 +- .../src/test/resources/forImport.txt | 2 +- .../src/test/resources/logback.xml | 2 +- .../test/resources/mosquitto/mosquitto.conf | 18 + .../src/test/resources/smokeDevices.xml | 2 +- .../src/test/resources/smokesCustomer.xml | 2 +- .../src/test/resources/smokesProfiles.xml | 2 +- .../src/test/resources/smokesRuleChain.xml | 2 +- .../test/resources/tb-node/conf/logback.xml | 2 +- .../tb-transports/coap/conf/logback.xml | 2 +- .../tb-transports/http/conf/logback.xml | 2 +- .../tb-transports/mqtt/conf/logback.xml | 2 +- .../src/test/resources/uiTests.xml | 2 +- msa/js-executor/api/httpServer.ts | 2 +- msa/js-executor/api/jsExecutor.models.ts | 2 +- msa/js-executor/api/jsExecutor.ts | 2 +- .../api/jsInvokeMessageProcessor.ts | 2 +- msa/js-executor/api/utils.ts | 2 +- .../config/custom-environment-variables.yml | 2 +- msa/js-executor/config/default.yml | 2 +- msa/js-executor/config/logger.ts | 2 +- msa/js-executor/config/tb-js-executor.conf | 2 +- msa/js-executor/docker/Dockerfile | 2 +- msa/js-executor/docker/start-js-executor.sh | 2 +- msa/js-executor/install.js | 2 +- msa/js-executor/package.json | 2 +- msa/js-executor/pom.xml | 4 +- msa/js-executor/queue/awsSqsTemplate.ts | 2 +- msa/js-executor/queue/kafkaTemplate.ts | 2 +- msa/js-executor/queue/pubSubTemplate.ts | 2 +- msa/js-executor/queue/queue.models.ts | 2 +- msa/js-executor/queue/rabbitmqTemplate.ts | 2 +- msa/js-executor/queue/serviceBusTemplate.ts | 2 +- msa/js-executor/server.ts | 2 +- msa/monitoring/docker/Dockerfile | 2 +- msa/monitoring/docker/start-tb-monitoring.sh | 2 +- msa/monitoring/pom.xml | 4 +- msa/pom.xml | 4 +- msa/tb-node/docker/Dockerfile | 2 +- msa/tb-node/docker/start-tb-node.sh | 2 +- msa/tb-node/pom.xml | 4 +- msa/tb/docker-cassandra/Dockerfile | 4 +- msa/tb/docker-cassandra/start-db.sh | 2 +- msa/tb/docker-cassandra/stop-db.sh | 2 +- msa/tb/docker-postgres/Dockerfile | 2 +- msa/tb/docker-postgres/start-db.sh | 2 +- msa/tb/docker-postgres/stop-db.sh | 2 +- msa/tb/docker/install-tb.sh | 2 +- msa/tb/docker/logback.xml | 2 +- msa/tb/docker/start-tb.sh | 2 +- msa/tb/docker/thingsboard.conf | 2 +- msa/tb/docker/upgrade-tb.sh | 2 +- msa/tb/pom.xml | 6 +- msa/transport/coap/docker/Dockerfile | 2 +- .../coap/docker/start-tb-coap-transport.sh | 2 +- msa/transport/coap/pom.xml | 4 +- msa/transport/http/docker/Dockerfile | 2 +- .../http/docker/start-tb-http-transport.sh | 2 +- msa/transport/http/pom.xml | 4 +- msa/transport/lwm2m/docker/Dockerfile | 2 +- .../lwm2m/docker/start-tb-lwm2m-transport.sh | 2 +- msa/transport/lwm2m/pom.xml | 4 +- msa/transport/mqtt/docker/Dockerfile | 2 +- .../mqtt/docker/start-tb-mqtt-transport.sh | 2 +- msa/transport/mqtt/pom.xml | 4 +- msa/transport/pom.xml | 4 +- msa/transport/snmp/docker/Dockerfile | 2 +- .../snmp/docker/start-tb-snmp-transport.sh | 2 +- msa/transport/snmp/pom.xml | 4 +- msa/vc-executor-docker/docker/Dockerfile | 2 +- .../docker/start-tb-vc-executor.sh | 2 +- msa/vc-executor-docker/pom.xml | 4 +- msa/vc-executor/pom.xml | 4 +- msa/vc-executor/src/main/conf/logback.xml | 2 +- .../src/main/conf/tb-vc-executor.conf | 2 +- ...oardVersionControlExecutorApplication.java | 2 +- ...VersionControlQueueRoutingInfoService.java | 2 +- ...ersionControlTenantRoutingInfoService.java | 2 +- .../src/main/resources/logback.xml | 2 +- .../src/main/resources/tb-vc-executor.yml | 12 +- .../config/custom-environment-variables.yml | 2 +- msa/web-ui/config/default.yml | 2 +- msa/web-ui/config/logger.ts | 2 +- msa/web-ui/config/tb-web-ui.conf | 2 +- msa/web-ui/docker/Dockerfile | 2 +- msa/web-ui/docker/start-web-ui.sh | 2 +- msa/web-ui/install.js | 2 +- msa/web-ui/package.json | 2 +- msa/web-ui/pom.xml | 4 +- msa/web-ui/server.ts | 2 +- netty-mqtt/pom.xml | 6 +- .../mqtt/ChannelClosedException.java | 2 +- .../thingsboard/mqtt/MqttChannelHandler.java | 2 +- .../java/org/thingsboard/mqtt/MqttClient.java | 2 +- .../thingsboard/mqtt/MqttClientCallback.java | 2 +- .../thingsboard/mqtt/MqttClientConfig.java | 2 +- .../org/thingsboard/mqtt/MqttClientImpl.java | 2 +- .../thingsboard/mqtt/MqttConnectResult.java | 2 +- .../org/thingsboard/mqtt/MqttHandler.java | 2 +- .../mqtt/MqttIncomingQos2Publish.java | 2 +- .../org/thingsboard/mqtt/MqttLastWill.java | 2 +- .../thingsboard/mqtt/MqttPendingPublish.java | 2 +- .../mqtt/MqttPendingSubscription.java | 2 +- .../mqtt/MqttPendingUnsubscription.java | 2 +- .../org/thingsboard/mqtt/MqttPingHandler.java | 2 +- .../thingsboard/mqtt/MqttSubscription.java | 2 +- .../thingsboard/mqtt/PendingOperation.java | 2 +- .../mqtt/RetransmissionHandler.java | 2 +- .../thingsboard/mqtt/MqttPingHandlerTest.java | 2 +- .../integration/IntegrationTestSuite.java | 2 +- .../mqtt/integration/MqttIntegrationTest.java | 2 +- .../mqtt/integration/server/MqttServer.java | 2 +- .../server/MqttTransportHandler.java | 2 +- packaging/java/assembly/windows.xml | 2 +- packaging/java/build.gradle | 2 +- packaging/java/scripts/install/install.sh | 2 +- .../java/scripts/install/install_dev_db.sh | 2 +- packaging/java/scripts/install/logback.xml | 2 +- packaging/java/scripts/install/upgrade.sh | 2 +- .../java/scripts/install/upgrade_dev_db.sh | 2 +- packaging/js/assembly/windows.xml | 2 +- packaging/js/build.gradle | 2 +- pom.xml | 30 +- rest-client/pom.xml | 4 +- .../thingsboard/rest/client/RestClient.java | 217 +- .../rest/client/utils/RestJsonConverter.java | 2 +- rest-client/src/main/resources/logback.xml | 2 +- rule-engine/pom.xml | 4 +- rule-engine/rule-engine-api/pom.xml | 4 +- .../engine/api/EmptyNodeConfiguration.java | 2 +- .../rule/engine/api/MailService.java | 2 +- .../rule/engine/api/NodeConfiguration.java | 2 +- .../rule/engine/api/NodeDefinition.java | 2 +- .../rule/engine/api/NotificationCenter.java | 6 +- .../engine/api/RuleEngineAlarmService.java | 2 +- .../api/RuleEngineApiUsageStateService.java | 2 +- .../api/RuleEngineAssetProfileCache.java | 2 +- .../api/RuleEngineDeviceProfileCache.java | 2 +- .../api/RuleEngineDeviceRpcRequest.java | 2 +- .../api/RuleEngineDeviceRpcResponse.java | 2 +- .../rule/engine/api/RuleEngineRpcService.java | 2 +- .../api/RuleEngineTelemetryService.java | 2 +- .../thingsboard/rule/engine/api/RuleNode.java | 4 +- .../rule/engine/api/ScriptEngine.java | 2 +- .../rule/engine/api/SmsService.java | 2 +- .../rule/engine/api/TbContext.java | 16 +- .../thingsboard/rule/engine/api/TbEmail.java | 2 +- .../thingsboard/rule/engine/api/TbNode.java | 2 +- .../rule/engine/api/TbNodeConfiguration.java | 2 +- .../rule/engine/api/TbNodeException.java | 2 +- .../rule/engine/api/TbNodeState.java | 2 +- .../rule/engine/api/slack/SlackService.java | 2 +- .../rule/engine/api/sms/SmsSender.java | 2 +- .../rule/engine/api/sms/SmsSenderFactory.java | 2 +- .../api/sms/exception/SmsException.java | 2 +- .../api/sms/exception/SmsParseException.java | 2 +- .../api/sms/exception/SmsSendException.java | 2 +- .../rule/engine/api/util/TbNodeUtils.java | 3 +- .../rule/engine/api/util/TbNodeUtilsTest.java | 2 +- rule-engine/rule-engine-components/pom.xml | 4 +- .../engine/action/TbAbstractAlarmNode.java | 2 +- .../TbAbstractAlarmNodeConfiguration.java | 2 +- .../action/TbAbstractCustomerActionNode.java | 2 +- ...stractCustomerActionNodeConfiguration.java | 2 +- .../action/TbAbstractRelationActionNode.java | 2 +- ...stractRelationActionNodeConfiguration.java | 2 +- .../rule/engine/action/TbAlarmResult.java | 2 +- .../engine/action/TbAssignToCustomerNode.java | 2 +- .../TbAssignToCustomerNodeConfiguration.java | 2 +- .../rule/engine/action/TbClearAlarmNode.java | 2 +- .../action/TbClearAlarmNodeConfiguration.java | 2 +- .../TbCopyAttributesToEntityViewNode.java | 4 +- .../rule/engine/action/TbCreateAlarmNode.java | 2 +- .../TbCreateAlarmNodeConfiguration.java | 2 +- .../engine/action/TbCreateRelationNode.java | 2 +- .../TbCreateRelationNodeConfiguration.java | 2 +- .../engine/action/TbDeleteRelationNode.java | 2 +- .../TbDeleteRelationNodeConfiguration.java | 2 +- .../rule/engine/action/TbLogNode.java | 2 +- .../engine/action/TbLogNodeConfiguration.java | 2 +- .../rule/engine/action/TbMsgCountNode.java | 2 +- .../action/TbMsgCountNodeConfiguration.java | 2 +- .../TbSaveToCustomCassandraTableNode.java | 2 +- ...CustomCassandraTableNodeConfiguration.java | 2 +- .../action/TbUnassignFromCustomerNode.java | 2 +- ...UnassignFromCustomerNodeConfiguration.java | 2 +- .../rule/engine/aws/sns/TbSnsNode.java | 2 +- .../aws/sns/TbSnsNodeConfiguration.java | 2 +- .../rule/engine/aws/sqs/TbSqsNode.java | 2 +- .../aws/sqs/TbSqsNodeConfiguration.java | 2 +- .../credentials/AnonymousCredentials.java | 2 +- .../engine/credentials/BasicCredentials.java | 2 +- .../credentials/CertPemCredentials.java | 2 +- .../engine/credentials/ClientCredentials.java | 2 +- .../engine/credentials/CredentialsType.java | 2 +- .../engine/data/DeviceRelationsQuery.java | 2 +- .../rule/engine/data/RelationsQuery.java | 2 +- .../rule/engine/debug/TbMsgGeneratorNode.java | 32 +- .../TbMsgGeneratorNodeConfiguration.java | 3 +- .../deduplication/DeduplicationData.java | 2 +- .../engine/deduplication/DeduplicationId.java | 2 +- .../deduplication/DeduplicationStrategy.java | 2 +- .../deduplication/TbMsgDeduplicationNode.java | 38 +- .../TbMsgDeduplicationNodeConfiguration.java | 3 +- .../rule/engine/delay/TbMsgDelayNode.java | 2 +- .../delay/TbMsgDelayNodeConfiguration.java | 2 +- .../engine/edge/AbstractTbMsgPushNode.java | 43 +- .../edge/BaseTbMsgPushNodeConfiguration.java | 2 +- .../engine/edge/TbMsgPushToCloudNode.java | 12 +- .../TbMsgPushToCloudNodeConfiguration.java | 2 +- .../rule/engine/edge/TbMsgPushToEdgeNode.java | 38 +- .../TbMsgPushToEdgeNodeConfiguration.java | 2 +- .../external/TbAbstractExternalNode.java | 2 +- .../filter/TbAbstractTypeSwitchNode.java | 2 +- .../engine/filter/TbAssetTypeSwitchNode.java | 2 +- .../engine/filter/TbCheckAlarmStatusNode.java | 2 +- .../filter/TbCheckAlarmStatusNodeConfig.java | 2 +- .../engine/filter/TbCheckMessageNode.java | 2 +- .../TbCheckMessageNodeConfiguration.java | 2 +- .../engine/filter/TbCheckRelationNode.java | 2 +- .../TbCheckRelationNodeConfiguration.java | 2 +- .../engine/filter/TbDeviceTypeSwitchNode.java | 2 +- .../rule/engine/filter/TbJsFilterNode.java | 2 +- .../filter/TbJsFilterNodeConfiguration.java | 2 +- .../rule/engine/filter/TbJsSwitchNode.java | 2 +- .../filter/TbJsSwitchNodeConfiguration.java | 2 +- .../engine/filter/TbMsgTypeFilterNode.java | 2 +- .../TbMsgTypeFilterNodeConfiguration.java | 2 +- .../engine/filter/TbMsgTypeSwitchNode.java | 2 +- .../filter/TbOriginatorTypeFilterNode.java | 2 +- ...OriginatorTypeFilterNodeConfiguration.java | 2 +- .../filter/TbOriginatorTypeSwitchNode.java | 2 +- .../rule/engine/flow/TbAckNode.java | 2 +- .../rule/engine/flow/TbCheckpointNode.java | 33 +- .../engine/flow/TbRuleChainInputNode.java | 2 +- .../TbRuleChainInputNodeConfiguration.java | 2 +- .../engine/flow/TbRuleChainOutputNode.java | 2 +- .../rule/engine/gcp/pubsub/TbPubSubNode.java | 8 +- .../gcp/pubsub/TbPubSubNodeConfiguration.java | 2 +- .../engine/geo/AbstractGeofencingNode.java | 2 +- .../rule/engine/geo/Coordinates.java | 2 +- .../engine/geo/EntityGeofencingState.java | 2 +- .../thingsboard/rule/engine/geo/GeoUtil.java | 2 +- .../rule/engine/geo/Perimeter.java | 2 +- .../rule/engine/geo/PerimeterType.java | 2 +- .../rule/engine/geo/RangeUnit.java | 2 +- .../engine/geo/TbGpsGeofencingActionNode.java | 2 +- ...bGpsGeofencingActionNodeConfiguration.java | 2 +- .../engine/geo/TbGpsGeofencingFilterNode.java | 2 +- ...bGpsGeofencingFilterNodeConfiguration.java | 2 +- .../rule/engine/kafka/TbKafkaNode.java | 12 +- .../kafka/TbKafkaNodeConfiguration.java | 2 +- .../rule/engine/mail/TbMsgToEmailNode.java | 42 +- .../mail/TbMsgToEmailNodeConfiguration.java | 18 +- .../rule/engine/mail/TbSendEmailNode.java | 2 +- .../mail/TbSendEmailNodeConfiguration.java | 2 +- .../rule/engine/math/TbMathArgument.java | 2 +- .../rule/engine/math/TbMathArgumentType.java | 2 +- .../rule/engine/math/TbMathArgumentValue.java | 2 +- .../rule/engine/math/TbMathNode.java | 2 +- .../engine/math/TbMathNodeConfiguration.java | 2 +- .../rule/engine/math/TbMathResult.java | 2 +- .../math/TbRuleNodeMathFunctionType.java | 2 +- .../engine/metadata/CalculateDeltaNode.java | 2 +- .../CalculateDeltaNodeConfiguration.java | 2 +- .../rule/engine/metadata/DataToFetch.java | 2 +- .../TbAbstractFetchToNodeConfiguration.java | 2 +- .../metadata/TbAbstractGetAttributesNode.java | 2 +- .../metadata/TbAbstractGetEntityDataNode.java | 2 +- .../TbAbstractGetEntityDetailsNode.java | 2 +- ...ractGetEntityDetailsNodeConfiguration.java | 2 +- .../metadata/TbAbstractGetMappedDataNode.java | 2 +- .../metadata/TbAbstractNodeWithFetchTo.java | 8 +- .../TbFetchDeviceCredentialsNode.java | 2 +- ...tchDeviceCredentialsNodeConfiguration.java | 2 +- .../engine/metadata/TbGetAttributesNode.java | 2 +- .../TbGetAttributesNodeConfiguration.java | 2 +- .../metadata/TbGetCustomerAttributeNode.java | 2 +- .../metadata/TbGetCustomerDetailsNode.java | 2 +- ...TbGetCustomerDetailsNodeConfiguration.java | 2 +- .../engine/metadata/TbGetDeviceAttrNode.java | 2 +- .../TbGetDeviceAttrNodeConfiguration.java | 2 +- .../TbGetEntityDataNodeConfiguration.java | 2 +- .../TbGetMappedDataNodeConfiguration.java | 2 +- .../TbGetOriginatorFieldsConfiguration.java | 3 +- .../metadata/TbGetOriginatorFieldsNode.java | 2 +- .../metadata/TbGetRelatedAttributeNode.java | 2 +- .../TbGetRelatedDataNodeConfiguration.java | 2 +- .../engine/metadata/TbGetTelemetryNode.java | 2 +- .../TbGetTelemetryNodeConfiguration.java | 2 +- .../metadata/TbGetTenantAttributeNode.java | 2 +- .../metadata/TbGetTenantDetailsNode.java | 2 +- .../TbGetTenantDetailsNodeConfiguration.java | 2 +- .../rule/engine/mqtt/TbMqttNode.java | 2 +- .../engine/mqtt/TbMqttNodeConfiguration.java | 2 +- .../mqtt/azure/AzureIotHubSasCredentials.java | 2 +- .../engine/mqtt/azure/TbAzureIotHubNode.java | 2 +- .../azure/TbAzureIotHubNodeConfiguration.java | 2 +- .../notification/TbNotificationNode.java | 33 +- .../TbNotificationNodeConfiguration.java | 2 +- .../rule/engine/notification/TbSlackNode.java | 2 +- .../TbSlackNodeConfiguration.java | 2 +- .../rule/engine/profile/AlarmEvalResult.java | 2 +- .../rule/engine/profile/AlarmRuleState.java | 4 +- .../rule/engine/profile/AlarmState.java | 2 +- .../profile/AlarmStateUpdateResult.java | 2 +- .../rule/engine/profile/DataSnapshot.java | 2 +- .../rule/engine/profile/DeviceState.java | 4 +- .../profile/DynamicPredicateValueCtx.java | 2 +- .../profile/DynamicPredicateValueCtxImpl.java | 2 +- .../rule/engine/profile/EntityKeyValue.java | 2 +- .../engine/profile/NumericParseException.java | 2 +- .../rule/engine/profile/ProfileState.java | 2 +- .../rule/engine/profile/SnapshotUpdate.java | 2 +- .../engine/profile/TbDeviceProfileNode.java | 2 +- .../TbDeviceProfileNodeConfiguration.java | 2 +- .../state/PersistedAlarmRuleState.java | 2 +- .../profile/state/PersistedAlarmState.java | 2 +- .../profile/state/PersistedDeviceState.java | 2 +- .../rule/engine/rabbitmq/TbRabbitMqNode.java | 2 +- .../rabbitmq/TbRabbitMqNodeConfiguration.java | 2 +- .../rule/engine/rest/TbHttpClient.java | 2 +- .../rule/engine/rest/TbRestApiCallNode.java | 2 +- .../rest/TbRestApiCallNodeConfiguration.java | 2 +- .../rule/engine/rpc/TbSendRPCReplyNode.java | 2 +- .../rule/engine/rpc/TbSendRPCRequestNode.java | 2 +- .../rpc/TbSendRpcReplyNodeConfiguration.java | 2 +- .../TbSendRpcRequestNodeConfiguration.java | 2 +- .../rule/engine/sms/TbSendSmsNode.java | 2 +- .../sms/TbSendSmsNodeConfiguration.java | 2 +- .../AttributesDeleteNodeCallback.java | 2 +- .../AttributesUpdateNodeCallback.java | 2 +- .../engine/telemetry/TbMsgAttributesNode.java | 46 +- .../TbMsgAttributesNodeConfiguration.java | 6 +- .../telemetry/TbMsgDeleteAttributesNode.java | 2 +- ...bMsgDeleteAttributesNodeConfiguration.java | 2 +- .../engine/telemetry/TbMsgTimeseriesNode.java | 4 +- .../TbMsgTimeseriesNodeConfiguration.java | 2 +- .../telemetry/TelemetryNodeCallback.java | 2 +- .../TbSynchronizationBeginNode.java | 2 +- .../transaction/TbSynchronizationEndNode.java | 2 +- .../MultipleTbMsgsCallbackWrapper.java | 2 +- .../transform/TbAbstractTransformNode.java | 2 +- ...bAbstractTransformNodeWithTbMsgSource.java | 91 + .../transform/TbChangeOriginatorNode.java | 16 +- .../TbChangeOriginatorNodeConfiguration.java | 2 +- .../rule/engine/transform/TbCopyKeysNode.java | 104 +- .../TbCopyKeysNodeConfiguration.java | 7 +- .../engine/transform/TbDeleteKeysNode.java | 108 +- .../TbDeleteKeysNodeConfiguration.java | 7 +- .../rule/engine/transform/TbJsonPathNode.java | 8 +- .../TbJsonPathNodeConfiguration.java | 2 +- .../transform/TbMsgCallbackWrapper.java | 2 +- .../engine/transform/TbRenameKeysNode.java | 95 +- .../TbRenameKeysNodeConfiguration.java | 9 +- .../engine/transform/TbSplitArrayMsgNode.java | 12 +- .../engine/transform/TbTransformMsgNode.java | 11 +- .../TbTransformMsgNodeConfiguration.java | 2 +- .../util/ContactBasedEntityDetails.java | 2 +- .../EntitiesAlarmOriginatorIdAsyncLoader.java | 2 +- .../util/EntitiesByNameAndTypeLoader.java | 2 +- .../util/EntitiesCustomerIdAsyncLoader.java | 5 +- .../util/EntitiesFieldsAsyncLoader.java | 2 +- .../EntitiesRelatedDeviceIdAsyncLoader.java | 2 +- .../EntitiesRelatedEntityIdAsyncLoader.java | 2 +- .../rule/engine/util/EntityContainer.java | 2 +- .../rule/engine/util/TbMsgSource.java | 2 +- .../rule/engine/util/TenantIdLoader.java | 2 +- .../static/rulenode/rulenode-core-config.js | 26 +- .../engine/AbstractRuleNodeUpgradeTest.java | 52 + .../rule/engine/TestDbCallbackExecutor.java | 2 +- .../rule/engine/action/TbAlarmNodeTest.java | 2 +- .../action/TbCreateRelationNodeTest.java | 2 +- .../rule/engine/action/TbLogNodeTest.java | 2 +- .../credentials/CertPemCredentialsTest.java | 2 +- .../engine/debug/TbMsgGeneratorNodeTest.java | 53 + .../engine/edge/TbMsgPushToEdgeNodeTest.java | 2 +- .../filter/TbAssetTypeSwitchNodeTest.java | 2 +- .../filter/TbCheckAlarmStatusNodeTest.java | 2 +- .../engine/filter/TbCheckMessageNodeTest.java | 2 +- .../filter/TbCheckRelationNodeTest.java | 2 +- .../filter/TbDeviceTypeSwitchNodeTest.java | 2 +- .../engine/filter/TbJsFilterNodeTest.java | 2 +- .../engine/filter/TbJsSwitchNodeTest.java | 2 +- .../filter/TbMsgTypeFilterNodeTest.java | 2 +- .../filter/TbMsgTypeSwitchNodeTest.java | 2 +- .../TbOriginatorTypeFilterNodeTest.java | 2 +- .../TbOriginatorTypeSwitchNodeTest.java | 2 +- .../engine/flow/TbCheckpointNodeTest.java | 55 + .../rule/engine/geo/GeoUtilTest.java | 2 +- .../geo/TbGpsGeofencingFilterNodeTest.java | 2 +- .../engine/mail/TbMsgToEmailNodeTest.java | 190 +- .../engine/math/TbMathArgumentValueTest.java | 2 +- .../rule/engine/math/TbMathNodeTest.java | 2 +- .../metadata/CalculateDeltaNodeTest.java | 2 +- .../TbFetchDeviceCredentialsNodeTest.java | 2 +- .../metadata/TbGetAttributesNodeTest.java | 2 +- .../TbGetCustomerAttributeNodeTest.java | 5 +- .../TbGetCustomerDetailsNodeTest.java | 5 +- .../metadata/TbGetDeviceAttrNodeTest.java | 2 +- .../TbGetOriginatorFieldsNodeTest.java | 5 +- .../TbGetRelatedAttributeNodeTest.java | 4 +- .../metadata/TbGetTelemetryNodeTest.java | 2 +- .../TbGetTenantAttributeNodeTest.java | 5 +- .../metadata/TbGetTenantDetailsNodeTest.java | 5 +- .../rule/engine/profile/AlarmStateTest.java | 2 +- .../rule/engine/profile/DeviceStateTest.java | 2 +- .../profile/TbDeviceProfileNodeTest.java | 2 +- .../rule/engine/rest/TbHttpClientTest.java | 27 +- .../engine/rest/TbRestApiCallNodeTest.java | 2 +- .../engine/rpc/TbSendRPCReplyNodeTest.java | 2 +- .../TbMsgAttributesNodeConfigurationTest.java | 4 +- .../telemetry/TbMsgAttributesNodeTest.java | 163 +- .../TbMsgDeleteAttributesNodeTest.java | 2 +- .../transform/TbChangeOriginatorNodeTest.java | 2 +- .../engine/transform/TbCopyKeysNodeTest.java | 64 +- .../transform/TbDeleteKeysNodeTest.java | 53 +- .../engine/transform/TbJsonPathNodeTest.java | 2 +- .../transform/TbMsgDeduplicationNodeTest.java | 69 +- .../transform/TbRenameKeysNodeTest.java | 42 +- .../transform/TbSplitArrayMsgNodeTest.java | 2 +- .../transform/TbTransformMsgNodeTest.java | 2 +- .../EntitiesCustomerIdAsyncLoaderTest.java | 2 +- .../util/EntitiesFieldsAsyncLoaderTest.java | 2 +- ...ntitiesRelatedDeviceIdAsyncLoaderTest.java | 2 +- ...ntitiesRelatedEntityIdAsyncLoaderTest.java | 2 +- .../rule/engine/util/TenantIdLoaderTest.java | 2 +- tools/pom.xml | 4 +- .../client/tools/MqttSslClient.java | 2 +- .../tools/migrator/DictionaryParser.java | 2 +- .../client/tools/migrator/MigratorTool.java | 2 +- .../client/tools/migrator/PgCaMigrator.java | 2 +- .../tools/migrator/RelatedEntitiesParser.java | 2 +- .../client/tools/migrator/WriterBuilder.java | 2 +- tools/src/main/python/check_yml_file.py | 2 +- tools/src/main/python/mqtt-send-telemetry.py | 2 +- .../main/python/one-way-ssl-mqtt-client.py | 2 +- tools/src/main/python/simple-mqtt-client.py | 2 +- .../main/python/two-way-ssl-mqtt-client.py | 2 +- tools/src/main/shell/client.keygen.sh | 2 +- .../lwM2M_cfssl_chain_clients_for_test.sh | 2 +- .../lwm2m/lwm2m_cfssl_chain_all_for_test.sh | 2 +- .../lwm2m_cfssl_chain_server_for_test.sh | 2 +- tools/src/main/shell/server.keygen.sh | 2 +- transport/coap/pom.xml | 4 +- transport/coap/src/main/conf/logback.xml | 2 +- .../coap/src/main/conf/tb-coap-transport.conf | 2 +- .../ThingsboardCoapTransportApplication.java | 2 +- transport/coap/src/main/resources/logback.xml | 2 +- .../src/main/resources/tb-coap-transport.yml | 12 +- transport/http/pom.xml | 4 +- transport/http/src/main/conf/logback.xml | 2 +- .../http/src/main/conf/tb-http-transport.conf | 2 +- .../ThingsboardHttpTransportApplication.java | 2 +- transport/http/src/main/resources/logback.xml | 2 +- .../src/main/resources/tb-http-transport.yml | 14 +- transport/lwm2m/pom.xml | 4 +- transport/lwm2m/src/main/conf/logback.xml | 2 +- .../src/main/conf/tb-lwm2m-transport.conf | 2 +- .../ThingsboardLwm2mTransportApplication.java | 2 +- .../lwm2m/src/main/resources/logback.xml | 2 +- .../src/main/resources/tb-lwm2m-transport.yml | 12 +- transport/mqtt/pom.xml | 4 +- transport/mqtt/src/main/conf/logback.xml | 2 +- .../mqtt/src/main/conf/tb-mqtt-transport.conf | 2 +- .../ThingsboardMqttTransportApplication.java | 2 +- transport/mqtt/src/main/resources/logback.xml | 2 +- .../src/main/resources/tb-mqtt-transport.yml | 12 +- transport/pom.xml | 4 +- transport/snmp/pom.xml | 4 +- transport/snmp/src/main/conf/logback.xml | 2 +- .../snmp/src/main/conf/tb-snmp-transport.conf | 2 +- .../ThingsboardSnmpTransportApplication.java | 2 +- transport/snmp/src/main/resources/logback.xml | 2 +- .../src/main/resources/tb-snmp-transport.yml | 12 +- ui-ngx/.editorconfig | 2 +- ui-ngx/e2e/protractor.conf.js | 2 +- ui-ngx/e2e/src/app.e2e-spec.ts | 2 +- ui-ngx/e2e/src/app.po.ts | 2 +- ui-ngx/extra-webpack.config.js | 2 +- ui-ngx/generate-types.js | 2 +- ui-ngx/package.json | 3 +- ui-ngx/pom.xml | 4 +- ui-ngx/proxy.conf.js | 2 +- ui-ngx/src/app/app-routing.module.ts | 2 +- ui-ngx/src/app/app.component.html | 2 +- ui-ngx/src/app/app.component.scss | 2 +- ui-ngx/src/app/app.component.ts | 2 +- ui-ngx/src/app/app.module.ts | 2 +- .../app/core/api/alarm-data-subscription.ts | 2 +- ui-ngx/src/app/core/api/alarm-data.service.ts | 6 +- ui-ngx/src/app/core/api/alias-controller.ts | 2 +- ui-ngx/src/app/core/api/data-aggregator.ts | 169 +- .../app/core/api/entity-data-subscription.ts | 98 +- .../src/app/core/api/entity-data.service.ts | 2 +- ui-ngx/src/app/core/api/public-api.ts | 2 +- ui-ngx/src/app/core/api/widget-api.models.ts | 2 +- .../src/app/core/api/widget-subscription.ts | 11 +- ui-ngx/src/app/core/auth/auth.actions.ts | 2 +- ui-ngx/src/app/core/auth/auth.effects.ts | 2 +- ui-ngx/src/app/core/auth/auth.models.ts | 3 +- ui-ngx/src/app/core/auth/auth.reducer.ts | 3 +- ui-ngx/src/app/core/auth/auth.selectors.ts | 2 +- ui-ngx/src/app/core/auth/auth.service.spec.ts | 2 +- ui-ngx/src/app/core/auth/auth.service.ts | 2 +- ui-ngx/src/app/core/auth/public-api.ts | 2 +- ui-ngx/src/app/core/core.module.ts | 2 +- ui-ngx/src/app/core/core.state.ts | 2 +- ui-ngx/src/app/core/css/css.js | 2 +- ui-ngx/src/app/core/guards/auth.guard.ts | 2 +- .../app/core/guards/confirm-on-exit.guard.ts | 2 +- ui-ngx/src/app/core/http/admin.service.ts | 2 +- .../app/core/http/alarm-comment.service.ts | 2 +- ui-ngx/src/app/core/http/alarm.service.ts | 2 +- .../app/core/http/asset-profile.service.ts | 6 +- ui-ngx/src/app/core/http/asset.service.ts | 8 +- ui-ngx/src/app/core/http/attribute.service.ts | 2 +- ui-ngx/src/app/core/http/audit-log.service.ts | 2 +- .../core/http/component-descriptor.service.ts | 2 +- ui-ngx/src/app/core/http/customer.service.ts | 2 +- ui-ngx/src/app/core/http/dashboard.service.ts | 6 +- .../app/core/http/device-profile.service.ts | 6 +- ui-ngx/src/app/core/http/device.service.ts | 18 +- ui-ngx/src/app/core/http/edge.service.ts | 18 +- .../http/entities-version-control.service.ts | 2 +- .../app/core/http/entity-relation.service.ts | 2 +- .../src/app/core/http/entity-view.service.ts | 2 +- ui-ngx/src/app/core/http/entity.service.ts | 10 +- ui-ngx/src/app/core/http/event.service.ts | 2 +- ui-ngx/src/app/core/http/http-utils.ts | 2 +- ui-ngx/src/app/core/http/image.service.ts | 135 + .../src/app/core/http/notification.service.ts | 2 +- ui-ngx/src/app/core/http/oauth2.service.ts | 2 +- .../src/app/core/http/ota-package.service.ts | 34 +- ui-ngx/src/app/core/http/public-api.ts | 2 +- ui-ngx/src/app/core/http/queue.service.ts | 2 +- ui-ngx/src/app/core/http/resource.service.ts | 41 +- .../src/app/core/http/rule-chain.service.ts | 2 +- .../app/core/http/tenant-profile.service.ts | 2 +- ui-ngx/src/app/core/http/tenant.service.ts | 2 +- .../http/two-factor-authentication.service.ts | 2 +- .../src/app/core/http/ui-settings.service.ts | 2 +- .../src/app/core/http/usage-info.service.ts | 2 +- .../app/core/http/user-settings.service.ts | 2 +- ui-ngx/src/app/core/http/user.service.ts | 2 +- ui-ngx/src/app/core/http/widget.service.ts | 17 +- .../interceptors/global-http-interceptor.ts | 2 +- .../core/interceptors/interceptor-config.ts | 2 +- .../interceptors/interceptor-http-params.ts | 2 +- .../src/app/core/interceptors/load.actions.ts | 2 +- .../src/app/core/interceptors/load.models.ts | 2 +- .../src/app/core/interceptors/load.reducer.ts | 2 +- .../app/core/interceptors/load.selectors.ts | 2 +- .../local-storage/local-storage.service.ts | 2 +- .../app/core/meta-reducers/debug.reducer.ts | 2 +- .../init-state-from-local-storage.reducer.ts | 2 +- .../core/notification/notification.actions.ts | 2 +- .../core/notification/notification.effects.ts | 2 +- .../core/notification/notification.models.ts | 2 +- .../core/notification/notification.reducer.ts | 2 +- ui-ngx/src/app/core/operator/enterZone.ts | 2 +- ui-ngx/src/app/core/public-api.ts | 2 +- .../core/services/active-component.service.ts | 2 +- .../src/app/core/services/broadcast.models.ts | 2 +- .../app/core/services/broadcast.service.ts | 2 +- .../core/services/dashboard-utils.service.ts | 2 +- .../src/app/core/services/dialog.service.ts | 2 +- .../dynamic-component-factory.service.ts | 2 +- ui-ngx/src/app/core/services/help.service.ts | 2 +- .../app/core/services/item-buffer.service.ts | 2 +- ui-ngx/src/app/core/services/menu.models.ts | 2 +- ui-ngx/src/app/core/services/menu.service.ts | 16 +- .../src/app/core/services/mobile.service.ts | 2 +- ui-ngx/src/app/core/services/public-api.ts | 2 +- ui-ngx/src/app/core/services/raf.service.ts | 2 +- .../app/core/services/resources.service.ts | 35 +- .../script/node-script-test.service.ts | 2 +- ui-ngx/src/app/core/services/time.service.ts | 71 +- ui-ngx/src/app/core/services/title.service.ts | 2 +- .../services/toast-notification.service.ts | 2 +- ui-ngx/src/app/core/services/utils.service.ts | 2 +- .../src/app/core/services/window.service.ts | 2 +- .../src/app/core/settings/settings.actions.ts | 2 +- .../src/app/core/settings/settings.effects.ts | 2 +- .../src/app/core/settings/settings.models.ts | 2 +- .../src/app/core/settings/settings.reducer.ts | 2 +- .../app/core/settings/settings.selectors.ts | 2 +- .../src/app/core/settings/settings.utils.ts | 2 +- .../translate/missing-translate-handler.ts | 2 +- .../translate/translate-default-compiler.ts | 2 +- .../translate/translate-default-parser.ts | 2 +- ui-ngx/src/app/core/utils.ts | 11 +- .../core/ws/notification-websocket.service.ts | 110 +- ui-ngx/src/app/core/ws/public-api.ts | 2 +- .../core/ws/telemetry-websocket.service.ts | 107 +- ui-ngx/src/app/core/ws/websocket.service.ts | 47 +- .../app/modules/common/modules-map.models.ts | 2 +- ui-ngx/src/app/modules/common/modules-map.ts | 23 +- .../dashboard/dashboard-pages.module.ts | 2 +- .../dashboard-pages.routing.module.ts | 2 +- .../dashboard/dashboard-routing.module.ts | 2 +- .../alarm/alarm-assignee-panel.component.html | 2 +- .../alarm/alarm-assignee-panel.component.scss | 3 +- .../alarm/alarm-assignee-panel.component.ts | 2 +- .../alarm-assignee-select-panel.component.ts | 2 +- .../alarm-assignee-select.component.html | 2 +- .../alarm/alarm-assignee-select.component.ts | 2 +- .../alarm/alarm-assignee.component.html | 3 +- .../alarm/alarm-assignee.component.scss | 3 +- .../alarm/alarm-assignee.component.ts | 2 +- .../alarm/alarm-comment-dialog.component.html | 2 +- .../alarm/alarm-comment-dialog.component.ts | 2 +- .../alarm/alarm-comment.component.html | 5 +- .../alarm/alarm-comment.component.scss | 2 +- .../alarm/alarm-comment.component.ts | 4 +- .../alarm/alarm-details-dialog.component.html | 2 +- .../alarm/alarm-details-dialog.component.scss | 3 +- .../alarm/alarm-details-dialog.component.ts | 2 +- .../alarm/alarm-filter-config.component.html | 2 +- .../alarm/alarm-filter-config.component.scss | 2 +- .../alarm/alarm-filter-config.component.ts | 2 +- .../components/alarm/alarm-table-config.ts | 10 +- .../alarm/alarm-table-header.component.html | 2 +- .../alarm/alarm-table-header.component.scss | 2 +- .../alarm/alarm-table-header.component.ts | 2 +- .../alarm/alarm-table.component.html | 2 +- .../alarm/alarm-table.component.scss | 2 +- .../components/alarm/alarm-table.component.ts | 2 +- ...aliases-entity-autocomplete.component.html | 2 +- .../aliases-entity-autocomplete.component.ts | 2 +- ...aliases-entity-select-panel.component.html | 2 +- ...aliases-entity-select-panel.component.scss | 2 +- .../aliases-entity-select-panel.component.ts | 2 +- .../aliases-entity-select.component.html | 2 +- .../aliases-entity-select.component.scss | 2 +- .../alias/aliases-entity-select.component.ts | 2 +- .../alias/entity-alias-dialog.component.html | 2 +- .../alias/entity-alias-dialog.component.scss | 2 +- .../alias/entity-alias-dialog.component.ts | 13 +- .../alias/entity-alias-select.component.html | 2 +- .../entity-alias-select.component.models.ts | 2 +- .../alias/entity-alias-select.component.scss | 2 +- .../alias/entity-alias-select.component.ts | 2 +- .../entity-aliases-dialog.component.html | 2 +- .../entity-aliases-dialog.component.scss | 2 +- .../alias/entity-aliases-dialog.component.ts | 2 +- .../add-attribute-dialog.component.html | 2 +- .../add-attribute-dialog.component.ts | 2 +- ...-widget-to-dashboard-dialog.component.html | 2 +- ...-widget-to-dashboard-dialog.component.scss | 2 +- ...dd-widget-to-dashboard-dialog.component.ts | 2 +- .../attribute/attribute-table.component.html | 2 +- .../attribute/attribute-table.component.scss | 2 +- .../attribute/attribute-table.component.ts | 2 +- .../delete-timeseries-panel.component.html | 3 +- .../delete-timeseries-panel.component.scss | 2 +- .../delete-timeseries-panel.component.ts | 2 +- .../edit-attribute-value-panel.component.html | 2 +- .../edit-attribute-value-panel.component.scss | 2 +- .../edit-attribute-value-panel.component.ts | 2 +- .../audit-log-details-dialog.component.html | 2 +- .../audit-log-details-dialog.component.scss | 2 +- .../audit-log-details-dialog.component.ts | 2 +- .../audit-log/audit-log-table-config.ts | 2 +- .../audit-log/audit-log-table.component.html | 2 +- .../audit-log/audit-log-table.component.scss | 2 +- .../audit-log/audit-log-table.component.ts | 2 +- .../add-widget-dialog.component.html | 2 +- .../add-widget-dialog.component.scss | 2 +- .../add-widget-dialog.component.ts | 2 +- .../dashboard-image-dialog.component.html | 10 +- .../dashboard-image-dialog.component.scss | 2 +- .../dashboard-image-dialog.component.ts | 10 +- .../dashboard-page.component.html | 4 +- .../dashboard-page.component.scss | 2 +- .../dashboard-page.component.ts | 57 +- .../dashboard-page/dashboard-page.models.ts | 2 +- .../dashboard-settings-dialog.component.html | 12 +- .../dashboard-settings-dialog.component.scss | 2 +- .../dashboard-settings-dialog.component.ts | 27 +- .../dashboard-state.component.html | 2 +- .../dashboard-state.component.scss | 2 +- .../dashboard-state.component.ts | 2 +- .../dashboard-toolbar.component.html | 2 +- .../dashboard-toolbar.component.scss | 2 +- .../dashboard-toolbar.component.ts | 2 +- .../dashboard-widget-select.component.html | 10 +- .../dashboard-widget-select.component.scss | 3 +- .../dashboard-widget-select.component.ts | 23 +- .../dashboard-page/edit-widget.component.html | 2 +- .../dashboard-page/edit-widget.component.scss | 2 +- .../dashboard-page/edit-widget.component.ts | 2 +- .../layout/dashboard-layout.component.html | 6 +- .../layout/dashboard-layout.component.scss | 2 +- .../layout/dashboard-layout.component.ts | 15 +- .../dashboard-page/layout/layout.models.ts | 2 +- ...ge-dashboard-layouts-dialog.component.html | 2 +- ...ge-dashboard-layouts-dialog.component.scss | 2 +- ...nage-dashboard-layouts-dialog.component.ts | 2 +- .../dashboard-state-dialog.component.html | 2 +- .../dashboard-state-dialog.component.ts | 2 +- .../default-state-controller.component.html | 2 +- .../default-state-controller.component.scss | 2 +- .../default-state-controller.component.ts | 2 +- .../entity-state-controller.component.html | 2 +- .../entity-state-controller.component.scss | 2 +- .../entity-state-controller.component.ts | 2 +- ...age-dashboard-states-dialog.component.html | 13 +- ...ashboard-states-dialog.component.models.ts | 2 +- ...age-dashboard-states-dialog.component.scss | 2 +- ...anage-dashboard-states-dialog.component.ts | 85 +- .../states/state-controller.component.ts | 2 +- .../states/state-controller.models.ts | 2 +- .../states/states-component.directive.ts | 2 +- .../states/states-controller.module.ts | 2 +- .../states/states-controller.service.ts | 2 +- .../widget-types-panel.component.html | 2 +- .../widget-types-panel.component.scss | 2 +- .../widget-types-panel.component.ts | 2 +- .../dashboard/dashboard.component.html | 2 +- .../dashboard/dashboard.component.scss | 2 +- .../dashboard/dashboard.component.ts | 2 +- .../components/dashboard/layout-button.scss | 2 +- ...select-target-layout-dialog.component.html | 2 +- .../select-target-layout-dialog.component.ts | 2 +- .../select-target-state-dialog.component.html | 2 +- .../select-target-state-dialog.component.ts | 2 +- .../components/details-panel.component.html | 4 +- .../components/details-panel.component.scss | 2 +- .../components/details-panel.component.ts | 2 +- .../copy-device-credentials.component.html | 2 +- .../copy-device-credentials.component.ts | 2 +- ...ce-credentials-lwm2m-server.component.html | 2 +- ...vice-credentials-lwm2m-server.component.ts | 2 +- .../device-credentials-lwm2m.component.html | 2 +- .../device-credentials-lwm2m.component.scss | 2 +- .../device-credentials-lwm2m.component.ts | 2 +- ...vice-credentials-mqtt-basic.component.html | 2 +- ...device-credentials-mqtt-basic.component.ts | 2 +- .../device/device-credentials.component.html | 2 +- .../device/device-credentials.component.scss | 2 +- .../device/device-credentials.component.ts | 2 +- .../device/device-credentials.module.ts | 2 +- .../device/device-info-filter.component.html | 2 +- .../device/device-info-filter.component.scss | 2 +- .../device/device-info-filter.component.ts | 2 +- .../edge/edge-downlink-table-config.ts | 2 +- .../edge-downlink-table-header.component.html | 2 +- .../edge-downlink-table-header.component.scss | 2 +- .../edge-downlink-table-header.component.ts | 2 +- .../edge/edge-downlink-table.component.html | 2 +- .../edge/edge-downlink-table.component.scss | 2 +- .../edge/edge-downlink-table.component.ts | 2 +- .../entity/add-entity-dialog.component.html | 2 +- .../entity/add-entity-dialog.component.scss | 2 +- .../entity/add-entity-dialog.component.ts | 2 +- .../entity/contact-based.component.ts | 2 +- .../entity/entities-table.component.html | 38 +- .../entity/entities-table.component.scss | 2 +- .../entity/entities-table.component.ts | 7 +- .../entity/entity-details-page.component.html | 4 +- .../entity/entity-details-page.component.scss | 2 +- .../entity/entity-details-page.component.ts | 8 +- .../entity-details-panel.component.html | 2 +- .../entity-details-panel.component.scss | 2 +- .../entity/entity-details-panel.component.ts | 2 +- .../entity/entity-filter-view.component.html | 2 +- .../entity/entity-filter-view.component.scss | 2 +- .../entity/entity-filter-view.component.ts | 2 +- .../entity/entity-filter.component.html | 2 +- .../entity/entity-filter.component.scss | 2 +- .../entity/entity-filter.component.ts | 56 +- .../entity/entity-table-header.component.ts | 2 +- .../entity/entity-tabs.component.ts | 2 +- .../components/entity/entity.component.ts | 2 +- .../event/event-content-dialog.component.html | 2 +- .../event/event-content-dialog.component.scss | 2 +- .../event/event-content-dialog.component.ts | 2 +- .../event/event-filter-panel.component.html | 2 +- .../event/event-filter-panel.component.scss | 2 +- .../event/event-filter-panel.component.ts | 2 +- .../components/event/event-table-config.ts | 2 +- .../event/event-table-header.component.html | 2 +- .../event/event-table-header.component.scss | 2 +- .../event/event-table-header.component.ts | 2 +- .../event/event-table.component.html | 2 +- .../event/event-table.component.scss | 2 +- .../components/event/event-table.component.ts | 2 +- .../boolean-filter-predicate.component.html | 2 +- .../boolean-filter-predicate.component.ts | 2 +- ...lex-filter-predicate-dialog.component.html | 2 +- ...mplex-filter-predicate-dialog.component.ts | 2 +- .../complex-filter-predicate.component.html | 2 +- .../complex-filter-predicate.component.ts | 2 +- .../filter/filter-component.models.ts | 2 +- .../filter/filter-dialog.component.html | 2 +- .../filter/filter-dialog.component.scss | 2 +- .../filter/filter-dialog.component.ts | 2 +- .../filter-predicate-list.component.html | 2 +- .../filter-predicate-list.component.scss | 2 +- .../filter/filter-predicate-list.component.ts | 2 +- .../filter-predicate-value.component.html | 4 +- .../filter-predicate-value.component.ts | 2 +- .../filter/filter-predicate.component.html | 2 +- .../filter/filter-predicate.component.ts | 2 +- .../components/filter/filter-predicate.scss | 2 +- .../filter/filter-select.component.html | 2 +- .../filter/filter-select.component.models.ts | 2 +- .../filter/filter-select.component.ts | 2 +- .../filter/filter-text.component.html | 2 +- .../filter/filter-text.component.scss | 2 +- .../filter/filter-text.component.ts | 2 +- .../filter-user-info-dialog.component.html | 2 +- .../filter-user-info-dialog.component.ts | 2 +- .../filter/filter-user-info.component.html | 2 +- .../filter/filter-user-info.component.ts | 2 +- .../filter/filters-dialog.component.html | 2 +- .../filter/filters-dialog.component.scss | 2 +- .../filter/filters-dialog.component.ts | 2 +- .../filter/filters-edit-panel.component.html | 2 +- .../filter/filters-edit-panel.component.scss | 2 +- .../filter/filters-edit-panel.component.ts | 2 +- .../filter/filters-edit.component.html | 2 +- .../filter/filters-edit.component.scss | 2 +- .../filter/filters-edit.component.ts | 2 +- .../filter/key-filter-dialog.component.html | 2 +- .../filter/key-filter-dialog.component.scss | 2 +- .../filter/key-filter-dialog.component.ts | 2 +- .../filter/key-filter-list.component.html | 2 +- .../filter/key-filter-list.component.scss | 2 +- .../filter/key-filter-list.component.ts | 2 +- .../numeric-filter-predicate.component.html | 2 +- .../numeric-filter-predicate.component.ts | 2 +- .../string-filter-predicate.component.html | 2 +- .../string-filter-predicate.component.ts | 2 +- .../filter/user-filter-dialog.component.html | 2 +- .../filter/user-filter-dialog.component.ts | 2 +- .../home/components/home-components.module.ts | 25 +- .../notification-bell.component.html | 2 +- .../notification-bell.component.ts | 13 +- .../send-notification-button.component.html | 2 +- .../send-notification-button.component.ts | 2 +- .../show-notification-popover.component.html | 2 +- .../show-notification-popover.component.ts | 10 +- .../add-device-profile-dialog.component.html | 7 +- .../add-device-profile-dialog.component.scss | 2 +- .../add-device-profile-dialog.component.ts | 2 +- ...rm-duration-predicate-value.component.html | 4 +- ...larm-duration-predicate-value.component.ts | 2 +- .../alarm/alarm-dynamic-value.component.html | 2 +- .../alarm/alarm-dynamic-value.component.ts | 2 +- ...alarm-rule-condition-dialog.component.html | 2 +- ...alarm-rule-condition-dialog.component.scss | 2 +- .../alarm-rule-condition-dialog.component.ts | 2 +- .../alarm/alarm-rule-condition.component.html | 2 +- .../alarm/alarm-rule-condition.component.scss | 2 +- .../alarm/alarm-rule-condition.component.ts | 2 +- .../profile/alarm/alarm-rule.component.html | 2 +- .../profile/alarm/alarm-rule.component.scss | 2 +- .../profile/alarm/alarm-rule.component.ts | 2 +- .../alarm-schedule-dialog.component.html | 2 +- .../alarm/alarm-schedule-dialog.component.ts | 2 +- .../alarm/alarm-schedule-info.component.html | 2 +- .../alarm/alarm-schedule-info.component.scss | 2 +- .../alarm/alarm-schedule-info.component.ts | 2 +- .../alarm/alarm-schedule.component.html | 2 +- .../alarm/alarm-schedule.component.scss | 2 +- .../profile/alarm/alarm-schedule.component.ts | 2 +- .../alarm/create-alarm-rules.component.html | 2 +- .../alarm/create-alarm-rules.component.scss | 2 +- .../alarm/create-alarm-rules.component.ts | 2 +- .../alarm/device-profile-alarm.component.html | 2 +- .../alarm/device-profile-alarm.component.scss | 2 +- .../alarm/device-profile-alarm.component.ts | 2 +- .../device-profile-alarms.component.html | 2 +- .../device-profile-alarms.component.scss | 2 +- .../alarm/device-profile-alarms.component.ts | 2 +- .../edit-alarm-details-dialog.component.html | 2 +- .../edit-alarm-details-dialog.component.ts | 2 +- .../asset-profile-autocomplete.component.html | 7 +- .../asset-profile-autocomplete.component.scss | 2 +- .../asset-profile-autocomplete.component.ts | 20 +- .../asset-profile-dialog.component.html | 2 +- .../profile/asset-profile-dialog.component.ts | 2 +- .../profile/asset-profile.component.html | 7 +- .../profile/asset-profile.component.ts | 2 +- ...device-profile-autocomplete.component.html | 7 +- ...device-profile-autocomplete.component.scss | 2 +- .../device-profile-autocomplete.component.ts | 20 +- .../device-profile-dialog.component.html | 2 +- .../device-profile-dialog.component.ts | 2 +- ...ile-provision-configuration.component.html | 2 +- ...ofile-provision-configuration.component.ts | 2 +- .../profile/device-profile.component.html | 7 +- .../profile/device-profile.component.ts | 2 +- ...ile-transport-configuration.component.html | 2 +- ...ile-transport-configuration.component.scss | 2 +- ...ofile-transport-configuration.component.ts | 2 +- .../common/device-profile-common.module.ts | 2 +- .../common/power-mode-setting.component.html | 2 +- .../common/power-mode-setting.component.ts | 2 +- .../common/time-unit-select.component.html | 2 +- .../common/time-unit-select.component.ts | 2 +- ...evice-profile-configuration.component.html | 2 +- ...-device-profile-configuration.component.ts | 2 +- ...ile-transport-configuration.component.html | 2 +- ...ofile-transport-configuration.component.ts | 2 +- ...evice-profile-configuration.component.html | 2 +- .../device-profile-configuration.component.ts | 2 +- ...ile-transport-configuration.component.html | 2 +- ...ofile-transport-configuration.component.ts | 2 +- .../lwm2m-attributes-dialog.component.html | 2 +- .../lwm2m-attributes-dialog.component.ts | 2 +- .../lwm2m-attributes-key-list.component.html | 2 +- .../lwm2m-attributes-key-list.component.scss | 2 +- .../lwm2m-attributes-key-list.component.ts | 2 +- .../lwm2m/lwm2m-attributes.component.html | 2 +- .../lwm2m/lwm2m-attributes.component.ts | 2 +- ...ap-add-config-server-dialog.component.html | 2 +- ...trap-add-config-server-dialog.component.ts | 2 +- ...2m-bootstrap-config-servers.component.html | 2 +- ...wm2m-bootstrap-config-servers.component.ts | 2 +- .../lwm2m-device-config-server.component.html | 2 +- .../lwm2m-device-config-server.component.ts | 2 +- ...ile-transport-configuration.component.html | 2 +- ...ile-transport-configuration.component.scss | 2 +- ...ofile-transport-configuration.component.ts | 2 +- ...object-add-instances-dialog.component.html | 2 +- ...m-object-add-instances-dialog.component.ts | 2 +- ...m-object-add-instances-list.component.html | 2 +- ...m2m-object-add-instances-list.component.ts | 2 +- .../lwm2m/lwm2m-object-list.component.html | 2 +- .../lwm2m/lwm2m-object-list.component.ts | 2 +- ...ve-attr-telemetry-instances.component.html | 2 +- ...ve-attr-telemetry-instances.component.scss | 2 +- ...erve-attr-telemetry-instances.component.ts | 2 +- ...ve-attr-telemetry-resources.component.html | 2 +- ...ve-attr-telemetry-resources.component.scss | 2 +- ...erve-attr-telemetry-resources.component.ts | 2 +- ...wm2m-observe-attr-telemetry.component.html | 2 +- ...wm2m-observe-attr-telemetry.component.scss | 2 +- .../lwm2m-observe-attr-telemetry.component.ts | 2 +- .../lwm2m/lwm2m-profile-components.module.ts | 2 +- .../lwm2m/lwm2m-profile-config.models.ts | 2 +- ...ile-transport-configuration.component.html | 2 +- ...ile-transport-configuration.component.scss | 2 +- ...ofile-transport-configuration.component.ts | 2 +- ...rofile-communication-config.component.html | 2 +- ...rofile-communication-config.component.scss | 2 +- ...-profile-communication-config.component.ts | 2 +- ...snmp-device-profile-mapping.component.html | 2 +- ...snmp-device-profile-mapping.component.scss | 2 +- .../snmp-device-profile-mapping.component.ts | 2 +- ...ile-transport-configuration.component.html | 2 +- ...ofile-transport-configuration.component.ts | 2 +- .../snmp-device-profile-transport.module.ts | 2 +- .../tenant-profile-queues.component.html | 2 +- .../tenant-profile-queues.component.scss | 2 +- .../queue/tenant-profile-queues.component.ts | 2 +- ...tenant-profile-autocomplete.component.html | 2 +- ...tenant-profile-autocomplete.component.scss | 2 +- .../tenant-profile-autocomplete.component.ts | 2 +- .../tenant-profile-data.component.html | 2 +- .../profile/tenant-profile-data.component.ts | 2 +- .../tenant-profile-dialog.component.html | 2 +- .../tenant-profile-dialog.component.scss | 2 +- .../tenant-profile-dialog.component.ts | 2 +- .../profile/tenant-profile.component.html | 2 +- .../profile/tenant-profile.component.scss | 2 +- .../profile/tenant-profile.component.ts | 2 +- ...enant-profile-configuration.component.html | 20 +- ...enant-profile-configuration.component.scss | 2 +- ...-tenant-profile-configuration.component.ts | 3 +- .../rate-limits-details-dialog.component.html | 2 +- .../rate-limits-details-dialog.component.ts | 2 +- .../rate-limits-list.component.html | 2 +- .../rate-limits-list.component.scss | 2 +- .../rate-limits/rate-limits-list.component.ts | 2 +- .../rate-limits-text.component.html | 2 +- .../rate-limits-text.component.scss | 2 +- .../rate-limits/rate-limits-text.component.ts | 2 +- .../rate-limits/rate-limits.component.html | 2 +- .../rate-limits/rate-limits.component.scss | 2 +- .../rate-limits/rate-limits.component.ts | 2 +- .../tenant/rate-limits/rate-limits.models.ts | 2 +- ...enant-profile-configuration.component.html | 2 +- .../tenant-profile-configuration.component.ts | 2 +- .../app/modules/home/components/public-api.ts | 2 +- .../queue/queue-form.component.html | 2 +- .../queue/queue-form.component.scss | 2 +- .../components/queue/queue-form.component.ts | 2 +- .../relation/relation-dialog.component.html | 2 +- .../relation/relation-dialog.component.scss | 2 +- .../relation/relation-dialog.component.ts | 2 +- .../relation/relation-filters.component.html | 2 +- .../relation/relation-filters.component.scss | 2 +- .../relation/relation-filters.component.ts | 2 +- .../relation/relation-table.component.html | 2 +- .../relation/relation-table.component.scss | 2 +- .../relation/relation-table.component.ts | 2 +- .../components/router-tabs.component.html | 2 +- .../components/router-tabs.component.scss | 2 +- .../home/components/router-tabs.component.ts | 2 +- .../rule-chain-autocomplete.component.html | 8 +- .../rule-chain-autocomplete.component.ts | 10 +- .../shared-home-components.module.ts | 2 +- ...-sns-provider-configuration.component.html | 2 +- ...ws-sns-provider-configuration.component.ts | 2 +- ...-sms-provider-configuration.component.html | 2 +- ...pp-sms-provider-configuration.component.ts | 2 +- .../sms-provider-configuration.component.html | 2 +- .../sms-provider-configuration.component.ts | 2 +- ...-sms-provider-configuration.component.html | 2 +- ...io-sms-provider-configuration.component.ts | 2 +- .../src/app/modules/home/components/tokens.ts | 2 +- .../vc/auto-commit-settings.component.html | 2 +- .../vc/auto-commit-settings.component.scss | 2 +- .../vc/auto-commit-settings.component.ts | 2 +- .../vc/complex-version-create.component.html | 2 +- .../vc/complex-version-create.component.ts | 2 +- .../vc/complex-version-load.component.html | 2 +- .../vc/complex-version-load.component.ts | 2 +- ...entity-types-version-create.component.html | 2 +- .../entity-types-version-create.component.ts | 2 +- .../entity-types-version-load.component.html | 2 +- .../vc/entity-types-version-load.component.ts | 2 +- .../vc/entity-types-version.component.scss | 2 +- .../vc/entity-version-create.component.html | 2 +- .../vc/entity-version-create.component.ts | 2 +- .../vc/entity-version-diff.component.html | 2 +- .../vc/entity-version-diff.component.scss | 2 +- .../vc/entity-version-diff.component.ts | 2 +- .../vc/entity-version-restore.component.html | 2 +- .../vc/entity-version-restore.component.ts | 2 +- .../vc/entity-versions-table.component.html | 2 +- .../vc/entity-versions-table.component.scss | 2 +- .../vc/entity-versions-table.component.ts | 2 +- ...move-other-entities-confirm.component.html | 2 +- ...remove-other-entities-confirm.component.ts | 2 +- .../vc/repository-settings.component.html | 5 +- .../vc/repository-settings.component.scss | 2 +- .../vc/repository-settings.component.ts | 2 +- .../vc/version-control.component.html | 2 +- .../vc/version-control.component.scss | 2 +- .../vc/version-control.component.ts | 2 +- .../home/components/vc/version-control.scss | 4 +- ...custom-action-pretty-editor.component.html | 2 +- ...custom-action-pretty-editor.component.scss | 2 +- .../custom-action-pretty-editor.component.ts | 2 +- ...ction-pretty-resources-tabs.component.html | 2 +- ...ction-pretty-resources-tabs.component.scss | 2 +- ...-action-pretty-resources-tabs.component.ts | 2 +- .../widget/action/custom-action.models.ts | 2 +- ...anage-widget-actions-dialog.component.html | 2 +- .../manage-widget-actions-dialog.component.ts | 2 +- .../manage-widget-actions.component.html | 2 +- .../manage-widget-actions.component.models.ts | 2 +- .../manage-widget-actions.component.scss | 2 +- .../action/manage-widget-actions.component.ts | 2 +- .../mobile-action-editor.component.html | 2 +- .../action/mobile-action-editor.component.ts | 2 +- .../action/mobile-action-editor.models.ts | 2 +- .../widget-action-dialog.component.html | 5 +- .../action/widget-action-dialog.component.ts | 2 +- .../alarm-count-basic-config.component.html | 2 +- .../alarm-count-basic-config.component.ts | 2 +- .../alarms-table-basic-config.component.html | 2 +- .../alarms-table-basic-config.component.ts | 2 +- .../widget/config/basic/basic-config.scss | 3 +- .../basic/basic-widget-config.module.ts | 20 +- .../aggregated-data-key-row.component.html | 2 +- .../aggregated-data-key-row.component.scss | 3 +- .../aggregated-data-key-row.component.ts | 2 +- .../aggregated-data-keys-panel.component.html | 2 +- .../aggregated-data-keys-panel.component.scss | 3 +- .../aggregated-data-keys-panel.component.ts | 2 +- ...ted-value-card-basic-config.component.html | 2 +- ...gated-value-card-basic-config.component.ts | 2 +- .../progress-bar-basic-config.component.html | 2 +- .../progress-bar-basic-config.component.ts | 2 +- .../simple-card-basic-config.component.html | 2 +- .../simple-card-basic-config.component.ts | 2 +- ...meseries-table-basic-config.component.html | 2 +- ...timeseries-table-basic-config.component.ts | 2 +- .../value-card-basic-config.component.html | 3 +- .../value-card-basic-config.component.ts | 2 +- ...lue-chart-card-basic-config.component.html | 2 +- ...value-chart-card-basic-config.component.ts | 2 +- ...rt-with-labels-basic-config.component.html | 248 + ...hart-with-labels-basic-config.component.ts | 323 + .../doughnut-basic-config.component.html | 19 +- .../chart/doughnut-basic-config.component.ts | 10 +- .../chart/flot-basic-config.component.html | 2 +- .../chart/flot-basic-config.component.ts | 2 +- .../range-chart-basic-config.component.html | 222 + .../range-chart-basic-config.component.ts | 269 + .../basic/common/data-key-row.component.html | 2 +- .../basic/common/data-key-row.component.scss | 3 +- .../basic/common/data-key-row.component.ts | 2 +- .../common/data-keys-panel.component.html | 2 +- .../common/data-keys-panel.component.scss | 3 +- .../basic/common/data-keys-panel.component.ts | 2 +- .../widget-actions-panel.component.html | 2 +- .../common/widget-actions-panel.component.ts | 2 +- ...entities-table-basic-config.component.html | 2 +- .../entities-table-basic-config.component.ts | 2 +- .../entity-count-basic-config.component.html | 2 +- .../entity-count-basic-config.component.ts | 2 +- .../analog-gauge-basic-config.component.html | 2 +- .../analog-gauge-basic-config.component.ts | 3 +- .../compass-gauge-basic-config.component.html | 2 +- .../compass-gauge-basic-config.component.ts | 2 +- .../radial-gauge-basic-config.component.ts | 2 +- ...eter-scale-gauge-basic-config.component.ts | 2 +- .../battery-level-basic-config.component.html | 2 +- .../battery-level-basic-config.component.ts | 2 +- ...uid-level-card-basic-config.component.html | 2 +- ...iquid-level-card-basic-config.component.ts | 2 +- ...ignal-strength-basic-config.component.html | 12 +- .../signal-strength-basic-config.component.ts | 2 +- ...peed-direction-basic-config.component.html | 2 +- ...-speed-direction-basic-config.component.ts | 2 +- .../data-key-config-dialog.component.html | 2 +- .../data-key-config-dialog.component.scss | 2 +- .../data-key-config-dialog.component.ts | 2 +- .../config/data-key-config.component.html | 2 +- .../config/data-key-config.component.ts | 2 +- .../widget/config/data-keys.component.html | 2 +- .../config/data-keys.component.models.ts | 2 +- .../widget/config/data-keys.component.scss | 3 +- .../widget/config/data-keys.component.ts | 2 +- .../widget/config/datasource.component.html | 2 +- .../config/datasource.component.models.ts | 2 +- .../widget/config/datasource.component.scss | 2 +- .../widget/config/datasource.component.ts | 2 +- .../widget/config/datasources.component.html | 2 +- .../widget/config/datasources.component.scss | 2 +- .../widget/config/datasources.component.ts | 2 +- .../timewindow-config-panel.component.html | 2 +- .../timewindow-config-panel.component.ts | 2 +- .../timewindow-style-panel.component.html | 2 +- .../timewindow-style-panel.component.scss | 3 +- .../timewindow-style-panel.component.ts | 2 +- .../config/timewindow-style.component.html | 2 +- .../config/timewindow-style.component.ts | 2 +- .../config/widget-config-components.module.ts | 2 +- .../config/widget-config.component.models.ts | 2 +- .../config/widget-settings.component.html | 2 +- .../config/widget-settings.component.scss | 2 +- .../config/widget-settings.component.ts | 2 +- .../custom-dialog-container.component.ts | 2 +- .../widget/dialog/custom-dialog.component.ts | 2 +- .../widget/dialog/custom-dialog.service.ts | 2 +- .../dialog/embed-dashboard-dialog-token.ts | 2 +- .../embed-dashboard-dialog.component.html | 2 +- .../embed-dashboard-dialog.component.scss | 2 +- .../embed-dashboard-dialog.component.ts | 2 +- .../widget/dynamic-widget.component.ts | 4 +- .../alarm/alarms-table-widget.component.html | 4 +- .../alarm/alarms-table-widget.component.scss | 2 +- .../alarm/alarms-table-widget.component.ts | 2 +- .../widget/lib/analogue-compass.models.ts | 2 +- .../components/widget/lib/analogue-compass.ts | 2 +- .../widget/lib/analogue-gauge.models.ts | 4 +- .../lib/analogue-linear-gauge.models.ts | 2 +- .../widget/lib/analogue-linear-gauge.ts | 2 +- .../lib/analogue-radial-gauge.models.ts | 2 +- .../widget/lib/analogue-radial-gauge.ts | 2 +- .../widget/lib/canvas-digital-gauge.ts | 2 +- ...ggregated-value-card-widget.component.html | 4 +- ...ggregated-value-card-widget.component.scss | 2 +- .../aggregated-value-card-widget.component.ts | 12 +- .../lib/cards/aggregated-value-card.models.ts | 6 +- .../cards/progress-bar-widget.component.html | 4 +- .../cards/progress-bar-widget.component.scss | 2 +- .../cards/progress-bar-widget.component.ts | 11 +- .../lib/cards/progress-bar-widget.models.ts | 2 +- .../cards/value-card-widget.component.html | 4 +- .../cards/value-card-widget.component.scss | 2 +- .../lib/cards/value-card-widget.component.ts | 16 +- .../lib/cards/value-card-widget.models.ts | 2 +- .../value-chart-card-widget.component.html | 4 +- .../value-chart-card-widget.component.scss | 2 +- .../value-chart-card-widget.component.ts | 13 +- .../cards/value-chart-card-widget.models.ts | 2 +- ...ar-chart-with-labels-widget.component.html | 36 + ...ar-chart-with-labels-widget.component.scss | 104 + .../bar-chart-with-labels-widget.component.ts | 482 ++ .../bar-chart-with-labels-widget.models.ts | 99 + .../lib/chart/doughnut-widget.component.html | 4 +- .../lib/chart/doughnut-widget.component.scss | 3 +- .../lib/chart/doughnut-widget.component.ts | 35 +- .../lib/chart/doughnut-widget.models.ts | 25 +- .../widget/lib/chart/echarts-widget.models.ts | 277 + .../chart/range-chart-widget.component.html | 34 + .../chart/range-chart-widget.component.scss | 104 + .../lib/chart/range-chart-widget.component.ts | 439 ++ .../lib/chart/range-chart-widget.models.ts | 95 + .../lib/count/count-widget.component.html | 2 +- .../lib/count/count-widget.component.scss | 2 +- .../lib/count/count-widget.component.ts | 6 +- .../widget/lib/count/count-widget.models.ts | 2 +- .../date-range-navigator-panel.component.html | 2 +- .../date-range-navigator-panel.component.scss | 2 +- .../date-range-navigator.component.html | 2 +- .../date-range-navigator.component.scss | 2 +- .../date-range-navigator.component.ts | 2 +- .../date-range-navigator.models.ts | 2 +- .../widget/lib/digital-gauge.models.ts | 2 +- .../components/widget/lib/digital-gauge.ts | 2 +- .../lib/display-columns-panel.component.html | 2 +- .../lib/display-columns-panel.component.scss | 2 +- .../lib/display-columns-panel.component.ts | 2 +- .../lib/edges-overview-widget.component.html | 2 +- .../lib/edges-overview-widget.component.scss | 2 +- .../lib/edges-overview-widget.component.ts | 2 +- .../lib/edges-overview-widget.models.ts | 2 +- .../entities-hierarchy-widget.component.html | 2 +- .../entities-hierarchy-widget.component.scss | 2 +- .../entities-hierarchy-widget.component.ts | 2 +- .../entities-hierarchy-widget.models.ts | 2 +- .../entities-table-widget.component.html | 6 +- .../entities-table-widget.component.scss | 2 +- .../entity/entities-table-widget.component.ts | 4 +- .../widget/lib/flot-widget.component.html | 2 +- .../widget/lib/flot-widget.component.ts | 2 +- .../widget/lib/flot-widget.models.ts | 2 +- .../home/components/widget/lib/flot-widget.ts | 14 +- .../device-gateway-command.component.html | 76 +- .../device-gateway-command.component.scss | 39 +- .../device-gateway-command.component.ts | 48 +- .../gateway-configuration.component.html | 2 +- .../gateway-configuration.component.scss | 2 +- .../gateway-configuration.component.ts | 2 +- .../gateway/gateway-connectors.component.html | 2 +- .../gateway/gateway-connectors.component.scss | 2 +- .../gateway/gateway-connectors.component.ts | 19 +- .../lib/gateway/gateway-form.component.html | 2 +- .../lib/gateway/gateway-form.component.scss | 2 +- .../lib/gateway/gateway-form.component.ts | 4 +- .../widget/lib/gateway/gateway-form.models.ts | 2 +- .../lib/gateway/gateway-logs.component.html | 2 +- .../lib/gateway/gateway-logs.component.scss | 2 +- .../lib/gateway/gateway-logs.component.ts | 10 +- .../gateway-remote-configuration-dialog.html | 2 +- .../gateway-remote-configuration-dialog.ts | 2 +- ...service-rpc-connector-template-dialog.html | 2 +- ...y-service-rpc-connector-template-dialog.ts | 2 +- ...ice-rpc-connector-templates.component.html | 2 +- ...ice-rpc-connector-templates.component.scss | 2 +- ...rvice-rpc-connector-templates.component.ts | 2 +- ...teway-service-rpc-connector.component.html | 2 +- ...teway-service-rpc-connector.component.scss | 2 +- ...gateway-service-rpc-connector.component.ts | 2 +- .../gateway-service-rpc.component.html | 2 +- .../gateway-service-rpc.component.scss | 2 +- .../gateway/gateway-service-rpc.component.ts | 2 +- .../gateway/gateway-statistics.component.html | 3 +- .../gateway/gateway-statistics.component.scss | 2 +- .../gateway/gateway-statistics.component.ts | 2 +- .../lib/gateway/gateway-widget.models.ts | 2 +- .../add-doc-link-dialog.component.html | 2 +- .../add-doc-link-dialog.component.scss | 2 +- .../add-doc-link-dialog.component.ts | 2 +- .../add-quick-link-dialog.component.html | 2 +- .../add-quick-link-dialog.component.scss | 2 +- .../add-quick-link-dialog.component.ts | 2 +- .../cluster-info-table.component.html | 2 +- .../cluster-info-table.component.scss | 2 +- .../home-page/cluster-info-table.component.ts | 2 +- .../configured-features.component.html | 2 +- .../configured-features.component.scss | 3 +- .../configured-features.component.ts | 2 +- .../lib/home-page/doc-link.component.html | 2 +- .../lib/home-page/doc-link.component.ts | 2 +- .../home-page/doc-links-widget.component.html | 2 +- .../home-page/doc-links-widget.component.ts | 2 +- .../edit-links-dialog.component.html | 2 +- .../edit-links-dialog.component.scss | 2 +- .../home-page/edit-links-dialog.component.ts | 2 +- ...ng-started-completed-dialog.component.html | 2 +- ...ng-started-completed-dialog.component.scss | 2 +- ...ting-started-completed-dialog.component.ts | 2 +- .../getting-started-widget.component.html | 2 +- .../getting-started-widget.component.scss | 3 +- .../getting-started-widget.component.ts | 2 +- .../lib/home-page/home-page-widget.scss | 2 +- .../lib/home-page/home-page-widgets.module.ts | 2 +- .../widget/lib/home-page/home-page.scss | 3 +- .../widget/lib/home-page/link.component.scss | 2 +- .../lib/home-page/links-widget.component.scss | 3 +- .../lib/home-page/quick-link.component.html | 2 +- .../lib/home-page/quick-link.component.ts | 2 +- .../quick-links-widget.component.html | 2 +- .../home-page/quick-links-widget.component.ts | 2 +- .../recent-dashboards-widget.component.html | 2 +- .../recent-dashboards-widget.component.scss | 2 +- .../recent-dashboards-widget.component.ts | 2 +- .../usage-info-widget.component.html | 2 +- .../usage-info-widget.component.scss | 2 +- .../home-page/usage-info-widget.component.ts | 2 +- .../lib/home-page/version-info.component.html | 2 +- .../lib/home-page/version-info.component.scss | 3 +- .../lib/home-page/version-info.component.ts | 2 +- .../battery-level-widget.component.html | 6 +- .../battery-level-widget.component.scss | 2 +- .../battery-level-widget.component.ts | 26 +- .../indicator/battery-level-widget.models.ts | 14 +- .../liquid-level-widget.component.html | 4 +- .../liquid-level-widget.component.scss | 2 +- .../liquid-level-widget.component.ts | 17 +- .../indicator/liquid-level-widget.models.ts | 4 +- .../signal-strength-widget.component.html | 4 +- .../signal-strength-widget.component.scss | 2 +- .../signal-strength-widget.component.ts | 25 +- .../signal-strength-widget.models.ts | 2 +- .../lib/json-input-widget.component.html | 2 +- .../lib/json-input-widget.component.scss | 2 +- .../widget/lib/json-input-widget.component.ts | 2 +- .../widget/lib/legend.component.html | 2 +- .../widget/lib/legend.component.scss | 2 +- .../components/widget/lib/legend.component.ts | 2 +- .../home/components/widget/lib/maps/circle.ts | 2 +- .../widget/lib/maps/common-maps-utils.ts | 84 +- .../select-entity-dialog.component.html | 2 +- .../select-entity-dialog.component.scss | 2 +- .../dialogs/select-entity-dialog.component.ts | 2 +- .../components/widget/lib/maps/leaflet-map.ts | 26 +- .../components/widget/lib/maps/map-models.ts | 4 +- .../widget/lib/maps/map-widget.interface.ts | 2 +- .../components/widget/lib/maps/map-widget2.ts | 2 +- .../components/widget/lib/maps/maps-utils.ts | 2 +- .../components/widget/lib/maps/markers.scss | 2 +- .../components/widget/lib/maps/markers.ts | 34 +- .../components/widget/lib/maps/polygon.ts | 2 +- .../components/widget/lib/maps/polyline.ts | 2 +- .../widget/lib/maps/providers/google-map.ts | 2 +- .../widget/lib/maps/providers/here-map.ts | 2 +- .../widget/lib/maps/providers/image-map.ts | 60 +- .../widget/lib/maps/providers/index.ts | 2 +- .../lib/maps/providers/openstreet-map.ts | 2 +- .../widget/lib/maps/providers/tencent-map.ts | 2 +- .../widget/lib/markdown-widget.component.html | 2 +- .../widget/lib/markdown-widget.component.ts | 2 +- .../lib/multiple-input-widget.component.html | 20 +- .../lib/multiple-input-widget.component.scss | 4 +- .../lib/multiple-input-widget.component.ts | 12 +- .../lib/navigation-card-widget.component.html | 2 +- .../lib/navigation-card-widget.component.scss | 2 +- .../lib/navigation-card-widget.component.ts | 2 +- .../navigation-cards-widget.component.html | 2 +- .../navigation-cards-widget.component.scss | 2 +- .../lib/navigation-cards-widget.component.ts | 2 +- .../lib/photo-camera-input.component.html | 2 +- .../lib/photo-camera-input.component.scss | 2 +- .../lib/photo-camera-input.component.ts | 2 +- .../widget/lib/qrcode-widget.component.html | 2 +- .../widget/lib/qrcode-widget.component.ts | 2 +- .../widget/lib/rpc/knob.component.html | 2 +- .../widget/lib/rpc/knob.component.scss | 2 +- .../widget/lib/rpc/knob.component.ts | 2 +- .../lib/rpc/led-indicator.component.html | 2 +- .../lib/rpc/led-indicator.component.scss | 2 +- .../widget/lib/rpc/led-indicator.component.ts | 2 +- .../rpc/persistent-add-dialog.component.html | 2 +- .../rpc/persistent-add-dialog.component.scss | 2 +- .../rpc/persistent-add-dialog.component.ts | 2 +- .../persistent-details-dialog.component.html | 2 +- .../persistent-details-dialog.component.scss | 2 +- .../persistent-details-dialog.component.ts | 2 +- .../persistent-filter-panel.component.html | 2 +- .../persistent-filter-panel.component.scss | 2 +- .../rpc/persistent-filter-panel.component.ts | 2 +- .../lib/rpc/persistent-table.component.html | 2 +- .../lib/rpc/persistent-table.component.scss | 2 +- .../lib/rpc/persistent-table.component.ts | 2 +- .../lib/rpc/round-switch.component.html | 2 +- .../lib/rpc/round-switch.component.scss | 2 +- .../widget/lib/rpc/round-switch.component.ts | 2 +- .../widget/lib/rpc/rpc-widgets.module.ts | 2 +- .../widget/lib/rpc/switch.component.html | 2 +- .../widget/lib/rpc/switch.component.scss | 2 +- .../widget/lib/rpc/switch.component.ts | 2 +- .../components/widget/lib/settings.models.ts | 2 +- ...alarm-count-widget-settings.component.html | 2 +- .../alarm-count-widget-settings.component.ts | 2 +- .../alarms-table-key-settings.component.html | 2 +- .../alarms-table-key-settings.component.ts | 2 +- ...larms-table-widget-settings.component.html | 2 +- .../alarms-table-widget-settings.component.ts | 2 +- ...ted-value-card-key-settings.component.html | 2 +- ...gated-value-card-key-settings.component.ts | 2 +- ...-value-card-widget-settings.component.html | 2 +- ...ed-value-card-widget-settings.component.ts | 2 +- ...board-state-widget-settings.component.html | 2 +- ...shboard-state-widget-settings.component.ts | 2 +- ...ck-overview-widget-settings.component.html | 2 +- ...uick-overview-widget-settings.component.ts | 2 +- .../html-card-widget-settings.component.html | 2 +- .../html-card-widget-settings.component.ts | 2 +- .../cards/label-widget-label.component.html | 2 +- .../cards/label-widget-label.component.scss | 2 +- .../cards/label-widget-label.component.ts | 2 +- .../label-widget-settings.component.html | 6 +- .../cards/label-widget-settings.component.ts | 2 +- .../markdown-widget-settings.component.html | 2 +- .../markdown-widget-settings.component.ts | 2 +- ...rogress-bar-widget-settings.component.html | 2 +- .../progress-bar-widget-settings.component.ts | 2 +- .../qrcode-widget-settings.component.html | 2 +- .../cards/qrcode-widget-settings.component.ts | 2 +- ...simple-card-widget-settings.component.html | 2 +- .../simple-card-widget-settings.component.ts | 2 +- ...meseries-table-key-settings.component.html | 2 +- ...timeseries-table-key-settings.component.ts | 2 +- ...s-table-latest-key-settings.component.html | 2 +- ...ies-table-latest-key-settings.component.ts | 2 +- ...eries-table-widget-settings.component.html | 16 +- ...eseries-table-widget-settings.component.ts | 12 +- .../value-card-widget-settings.component.html | 2 +- .../value-card-widget-settings.component.ts | 2 +- ...-chart-card-widget-settings.component.html | 2 +- ...ue-chart-card-widget-settings.component.ts | 2 +- ...with-labels-widget-settings.component.html | 150 + ...t-with-labels-widget-settings.component.ts | 170 + .../chart-widget-settings.component.html | 2 +- .../chart/chart-widget-settings.component.ts | 2 +- ...ghnut-chart-widget-settings.component.html | 2 +- ...oughnut-chart-widget-settings.component.ts | 2 +- .../doughnut-widget-settings.component.html | 18 +- .../doughnut-widget-settings.component.ts | 15 +- .../flot-bar-key-settings.component.html | 2 +- .../chart/flot-bar-key-settings.component.ts | 2 +- .../flot-bar-widget-settings.component.html | 2 +- .../flot-bar-widget-settings.component.ts | 2 +- .../chart/flot-key-settings.component.html | 2 +- .../chart/flot-key-settings.component.ts | 2 +- .../flot-latest-key-settings.component.html | 2 +- .../flot-latest-key-settings.component.ts | 2 +- .../flot-line-key-settings.component.html | 2 +- .../chart/flot-line-key-settings.component.ts | 2 +- .../flot-line-widget-settings.component.html | 2 +- .../flot-line-widget-settings.component.ts | 2 +- .../flot-pie-key-settings.component.html | 2 +- .../chart/flot-pie-key-settings.component.ts | 2 +- .../flot-pie-widget-settings.component.html | 2 +- .../flot-pie-widget-settings.component.ts | 2 +- .../chart/flot-threshold.component.html | 2 +- .../chart/flot-threshold.component.scss | 3 +- .../chart/flot-threshold.component.ts | 2 +- .../chart/flot-widget-settings.component.html | 2 +- .../chart/flot-widget-settings.component.ts | 2 +- .../chart/label-data-key.component.html | 2 +- .../chart/label-data-key.component.scss | 2 +- .../chart/label-data-key.component.ts | 2 +- ...range-chart-widget-settings.component.html | 140 + .../range-chart-widget-settings.component.ts | 147 + .../background-settings-panel.component.html | 16 +- .../background-settings-panel.component.scss | 9 +- .../background-settings-panel.component.ts | 26 +- .../common/background-settings.component.html | 4 +- .../common/background-settings.component.scss | 2 +- .../common/background-settings.component.ts | 42 +- .../common/color-range-list.component.html | 2 +- .../common/color-range-list.component.ts | 2 +- .../common/color-range-panel.component.html | 2 +- .../common/color-range-panel.component.ts | 2 +- .../color-range-settings.component.html | 2 +- .../common/color-range-settings.component.ts | 6 +- .../color-settings-panel.component.html | 2 +- .../color-settings-panel.component.scss | 3 +- .../common/color-settings-panel.component.ts | 2 +- .../common/color-settings.component.html | 2 +- .../common/color-settings.component.ts | 2 +- .../count-widget-settings.component.html | 2 +- .../common/count-widget-settings.component.ts | 2 +- .../common/css-unit-select.component.html | 2 +- .../common/css-unit-select.component.ts | 2 +- .../common/date-format-select.component.html | 2 +- .../common/date-format-select.component.ts | 17 +- .../date-format-settings-panel.component.html | 2 +- .../date-format-settings-panel.component.scss | 3 +- .../date-format-settings-panel.component.ts | 2 +- .../common/font-settings-panel.component.html | 2 +- .../common/font-settings-panel.component.scss | 2 +- .../common/font-settings-panel.component.ts | 15 +- .../common/font-settings.component.html | 2 +- .../common/font-settings.component.ts | 10 +- .../common/image-cards-select.component.html | 2 +- .../common/image-cards-select.component.scss | 2 +- .../common/image-cards-select.component.ts | 2 +- .../common/legend-config.component.html | 2 +- .../common/legend-config.component.ts | 2 +- .../common/value-source.component.html | 2 +- .../settings/common/value-source.component.ts | 2 +- .../common/widget-font.component.html | 2 +- .../settings/common/widget-font.component.ts | 2 +- .../common/widget-settings-common.module.ts | 2 +- .../device-key-autocomplete.component.html | 2 +- .../device-key-autocomplete.component.ts | 2 +- ...nob-control-widget-settings.component.html | 2 +- .../knob-control-widget-settings.component.ts | 2 +- ...d-indicator-widget-settings.component.html | 2 +- ...led-indicator-widget-settings.component.ts | 2 +- ...stent-table-widget-settings.component.html | 2 +- ...sistent-table-widget-settings.component.ts | 2 +- ...ound-switch-widget-settings.component.html | 2 +- .../round-switch-widget-settings.component.ts | 2 +- .../control/rpc-button-style.component.html | 2 +- .../control/rpc-button-style.component.ts | 2 +- .../rpc-shell-widget-settings.component.html | 2 +- .../rpc-shell-widget-settings.component.ts | 2 +- ...pc-terminal-widget-settings.component.html | 2 +- .../rpc-terminal-widget-settings.component.ts | 2 +- .../send-rpc-widget-settings.component.html | 2 +- .../send-rpc-widget-settings.component.ts | 2 +- ...lide-toggle-widget-settings.component.html | 2 +- .../slide-toggle-widget-settings.component.ts | 2 +- ...tch-control-widget-settings.component.html | 2 +- ...witch-control-widget-settings.component.ts | 2 +- .../switch-rpc-settings.component.html | 2 +- .../control/switch-rpc-settings.component.ts | 2 +- ...e-attribute-widget-settings.component.html | 2 +- ...ice-attribute-widget-settings.component.ts | 2 +- ...e-navigator-widget-settings.component.html | 2 +- ...nge-navigator-widget-settings.component.ts | 2 +- ...s-hierarchy-widget-settings.component.html | 2 +- ...ies-hierarchy-widget-settings.component.ts | 2 +- ...entities-table-key-settings.component.html | 2 +- .../entities-table-key-settings.component.ts | 2 +- ...ities-table-widget-settings.component.html | 2 +- ...ntities-table-widget-settings.component.ts | 2 +- ...ntity-count-widget-settings.component.html | 2 +- .../entity-count-widget-settings.component.ts | 2 +- ...ngle-device-widget-settings.component.html | 2 +- ...single-device-widget-settings.component.ts | 2 +- ...eway-config-widget-settings.component.html | 2 +- ...ateway-config-widget-settings.component.ts | 2 +- ...eway-events-widget-settings.component.html | 2 +- ...ateway-events-widget-settings.component.ts | 2 +- .../gateway-logs-settings.component.html | 2 +- .../gateway-logs-settings.component.ts | 2 +- ...ateway-service-rpc-settings.component.html | 2 +- .../gateway-service-rpc-settings.component.ts | 2 +- ...gue-compass-widget-settings.component.html | 2 +- ...logue-compass-widget-settings.component.ts | 2 +- ...logue-gauge-widget-settings.component.html | 2 +- ...nalogue-gauge-widget-settings.component.ts | 4 +- ...-linear-gauge-widget-settings.component.ts | 2 +- ...-radial-gauge-widget-settings.component.ts | 2 +- ...gital-gauge-widget-settings.component.html | 2 +- ...digital-gauge-widget-settings.component.ts | 2 +- .../gauge/fixed-color-level.component.html | 2 +- .../gauge/fixed-color-level.component.scss | 2 +- .../gauge/fixed-color-level.component.ts | 2 +- .../settings/gauge/tick-value.component.html | 2 +- .../settings/gauge/tick-value.component.scss | 2 +- .../settings/gauge/tick-value.component.ts | 2 +- ...pio-control-widget-settings.component.html | 2 +- .../gpio-control-widget-settings.component.ts | 2 +- .../settings/gpio/gpio-item.component.html | 2 +- .../settings/gpio/gpio-item.component.scss | 2 +- .../lib/settings/gpio/gpio-item.component.ts | 2 +- .../gpio-panel-widget-settings.component.html | 2 +- .../gpio-panel-widget-settings.component.ts | 2 +- .../doc-links-widget-settings.component.html | 2 +- .../doc-links-widget-settings.component.ts | 2 +- ...quick-links-widget-settings.component.html | 2 +- .../quick-links-widget-settings.component.ts | 2 +- ...ttery-level-widget-settings.component.html | 2 +- ...battery-level-widget-settings.component.ts | 2 +- ...-level-card-widget-settings.component.html | 2 +- ...id-level-card-widget-settings.component.ts | 2 +- ...al-strength-widget-settings.component.html | 12 +- ...gnal-strength-widget-settings.component.ts | 2 +- .../datakey-select-option.component.html | 2 +- .../datakey-select-option.component.scss | 2 +- .../input/datakey-select-option.component.ts | 2 +- ...ce-claiming-widget-settings.component.html | 2 +- ...vice-claiming-widget-settings.component.ts | 2 +- ...amera-input-widget-settings.component.html | 2 +- ...-camera-input-widget-settings.component.ts | 2 +- ...-attribute-general-settings.component.html | 2 +- ...te-attribute-general-settings.component.ts | 2 +- ...n-attribute-widget-settings.component.html | 2 +- ...ean-attribute-widget-settings.component.ts | 2 +- ...e-attribute-widget-settings.component.html | 2 +- ...ate-attribute-widget-settings.component.ts | 2 +- ...e-attribute-widget-settings.component.html | 2 +- ...ble-attribute-widget-settings.component.ts | 2 +- ...e-attribute-widget-settings.component.html | 2 +- ...age-attribute-widget-settings.component.ts | 2 +- ...r-attribute-widget-settings.component.html | 2 +- ...ger-attribute-widget-settings.component.ts | 2 +- ...n-attribute-widget-settings.component.html | 2 +- ...son-attribute-widget-settings.component.ts | 2 +- ...n-attribute-widget-settings.component.html | 2 +- ...ion-attribute-widget-settings.component.ts | 2 +- ...ple-attributes-key-settings.component.html | 6 +- ...tiple-attributes-key-settings.component.ts | 2 +- ...-attributes-widget-settings.component.html | 2 +- ...le-attributes-widget-settings.component.ts | 2 +- ...g-attribute-widget-settings.component.html | 2 +- ...ing-attribute-widget-settings.component.ts | 2 +- .../map/circle-settings.component.html | 2 +- .../settings/map/circle-settings.component.ts | 2 +- .../map/common-map-settings.component.html | 2 +- .../map/common-map-settings.component.ts | 2 +- ...atasources-key-autocomplete.component.html | 2 +- .../datasources-key-autocomplete.component.ts | 2 +- ...oogle-map-provider-settings.component.html | 2 +- .../google-map-provider-settings.component.ts | 2 +- .../here-map-provider-settings.component.html | 2 +- .../here-map-provider-settings.component.ts | 2 +- ...image-map-provider-settings.component.html | 6 +- .../image-map-provider-settings.component.ts | 2 +- .../map/map-editor-settings.component.html | 2 +- .../map/map-editor-settings.component.ts | 2 +- .../map/map-provider-settings.component.html | 2 +- .../map/map-provider-settings.component.ts | 2 +- .../settings/map/map-settings.component.html | 2 +- .../settings/map/map-settings.component.ts | 2 +- .../map/map-widget-settings.component.html | 2 +- .../map/map-widget-settings.component.ts | 2 +- .../marker-clustering-settings.component.html | 2 +- .../marker-clustering-settings.component.ts | 2 +- .../map/markers-settings.component.html | 14 +- .../map/markers-settings.component.ts | 2 +- ...treet-map-provider-settings.component.html | 2 +- ...nstreet-map-provider-settings.component.ts | 2 +- .../map/polygon-settings.component.html | 2 +- .../map/polygon-settings.component.ts | 2 +- .../map/route-map-settings.component.html | 2 +- .../map/route-map-settings.component.ts | 2 +- .../route-map-widget-settings.component.html | 2 +- .../route-map-widget-settings.component.ts | 2 +- ...ncent-map-provider-settings.component.html | 2 +- ...tencent-map-provider-settings.component.ts | 2 +- ...p-animation-common-settings.component.html | 2 +- ...rip-animation-common-settings.component.ts | 2 +- ...p-animation-marker-settings.component.html | 14 +- ...rip-animation-marker-settings.component.ts | 2 +- ...rip-animation-path-settings.component.html | 2 +- .../trip-animation-path-settings.component.ts | 2 +- ...ip-animation-point-settings.component.html | 2 +- ...trip-animation-point-settings.component.ts | 2 +- ...p-animation-widget-settings.component.html | 2 +- ...rip-animation-widget-settings.component.ts | 2 +- ...gation-card-widget-settings.component.html | 2 +- ...vigation-card-widget-settings.component.ts | 2 +- ...ation-cards-widget-settings.component.html | 2 +- ...igation-cards-widget-settings.component.ts | 2 +- ...d-direction-widget-settings.component.html | 2 +- ...eed-direction-widget-settings.component.ts | 2 +- .../lib/settings/widget-settings.module.ts | 20 +- .../widget/lib/settings/widget-settings.scss | 2 +- .../widget/lib/table-widget.models.ts | 5 +- .../components/widget/lib/table-widget.scss | 2 +- .../timeseries-table-widget.component.html | 6 +- .../timeseries-table-widget.component.scss | 2 +- .../lib/timeseries-table-widget.component.ts | 11 +- .../trip-animation.component.html | 2 +- .../trip-animation.component.scss | 2 +- .../trip-animation.component.ts | 2 +- ...wind-speed-direction-widget.component.html | 4 +- ...wind-speed-direction-widget.component.scss | 2 +- .../wind-speed-direction-widget.component.ts | 11 +- .../wind-speed-direction-widget.models.ts | 2 +- .../widget/widget-component.service.ts | 2 +- .../widget/widget-components.module.ts | 94 +- .../widget/widget-config.component.html | 2 +- .../widget/widget-config.component.scss | 3 +- .../widget/widget-config.component.ts | 2 +- .../widget/widget-container.component.html | 2 +- .../widget/widget-container.component.scss | 3 +- .../widget/widget-container.component.ts | 2 +- .../widget/widget-preview.component.html | 2 +- .../widget/widget-preview.component.scss | 2 +- .../widget/widget-preview.component.ts | 2 +- .../components/widget/widget.component.html | 2 +- .../components/widget/widget.component.scss | 2 +- .../components/widget/widget.component.ts | 2 +- .../device-wizard-dialog.component.html | 2 +- .../device-wizard-dialog.component.scss | 2 +- .../wizard/device-wizard-dialog.component.ts | 2 +- ...entities-to-customer-dialog.component.html | 2 +- ...d-entities-to-customer-dialog.component.ts | 2 +- ...add-entities-to-edge-dialog.component.html | 2 +- .../add-entities-to-edge-dialog.component.ts | 2 +- .../assign-to-customer-dialog.component.html | 2 +- .../assign-to-customer-dialog.component.ts | 2 +- .../home/dialogs/home-dialogs.module.ts | 2 +- .../home/dialogs/home-dialogs.service.ts | 4 +- .../app/modules/home/home-routing.module.ts | 2 +- .../src/app/modules/home/home.component.html | 2 +- .../src/app/modules/home/home.component.scss | 2 +- ui-ngx/src/app/modules/home/home.component.ts | 2 +- ui-ngx/src/app/modules/home/home.module.ts | 2 +- .../home/menu/menu-link.component.html | 2 +- .../home/menu/menu-link.component.scss | 2 +- .../modules/home/menu/menu-link.component.ts | 2 +- .../home/menu/menu-toggle.component.html | 2 +- .../home/menu/menu-toggle.component.scss | 2 +- .../home/menu/menu-toggle.component.ts | 2 +- .../home/menu/side-menu.component.html | 2 +- .../home/menu/side-menu.component.scss | 2 +- .../modules/home/menu/side-menu.component.ts | 2 +- .../app/modules/home/models/contact.models.ts | 2 +- .../home/models/dashboard-component.models.ts | 2 +- .../models/datasource/attribute-datasource.ts | 2 +- .../models/datasource/entity-datasource.ts | 2 +- .../models/datasource/relation-datasource.ts | 2 +- .../entity/entities-table-config.models.ts | 19 +- .../models/entity/entity-component.models.ts | 2 +- .../entity-details-page-component.models.ts | 2 +- .../entity/entity-table-component.models.ts | 2 +- .../models/searchable-component.models.ts | 2 +- .../app/modules/home/models/services.map.ts | 4 +- .../home/models/widget-component.models.ts | 5 +- .../pages/account/account-routing.module.ts | 2 +- .../home/pages/account/account.module.ts | 2 +- .../home/pages/admin/admin-routing.module.ts | 22 +- .../modules/home/pages/admin/admin.module.ts | 2 +- .../auto-commit-admin-settings.component.html | 2 +- .../auto-commit-admin-settings.component.ts | 2 +- .../admin/general-settings.component.html | 2 +- .../admin/general-settings.component.scss | 2 +- .../pages/admin/general-settings.component.ts | 4 +- .../pages/admin/home-settings.component.html | 2 +- .../pages/admin/home-settings.component.scss | 2 +- .../pages/admin/home-settings.component.ts | 2 +- .../pages/admin/mail-server.component.html | 4 +- .../pages/admin/mail-server.component.scss | 2 +- .../home/pages/admin/mail-server.component.ts | 2 +- .../admin/oauth2-settings.component.html | 8 +- .../admin/oauth2-settings.component.scss | 2 +- .../pages/admin/oauth2-settings.component.ts | 2 +- .../pages/admin/queue/queue.component.html | 2 +- .../home/pages/admin/queue/queue.component.ts | 2 +- .../queue/queues-table-config.resolver.ts | 2 +- .../repository-admin-settings.component.html | 2 +- .../repository-admin-settings.component.ts | 2 +- .../resources-library-table-config.resolve.ts | 4 +- .../resource/resources-library.component.html | 4 +- .../resource/resources-library.component.ts | 5 +- .../resources-table-header.component.html | 2 +- .../resources-table-header.component.ts | 2 +- .../admin/security-settings.component.html | 64 +- .../admin/security-settings.component.scss | 2 +- .../admin/security-settings.component.ts | 35 +- .../admin/send-test-sms-dialog.component.html | 2 +- .../admin/send-test-sms-dialog.component.ts | 2 +- .../home/pages/admin/settings-card.scss | 2 +- .../pages/admin/sms-provider.component.html | 2 +- .../pages/admin/sms-provider.component.scss | 2 +- .../pages/admin/sms-provider.component.ts | 2 +- .../two-factor-auth-settings.component.html | 2 +- .../two-factor-auth-settings.component.scss | 2 +- .../two-factor-auth-settings.component.ts | 2 +- .../home/pages/alarm/alarm-routing.module.ts | 2 +- .../modules/home/pages/alarm/alarm.module.ts | 2 +- .../api-usage/api-usage-routing.module.ts | 2 +- .../pages/api-usage/api-usage.component.html | 2 +- .../pages/api-usage/api-usage.component.scss | 2 +- .../pages/api-usage/api-usage.component.ts | 2 +- .../home/pages/api-usage/api-usage.module.ts | 2 +- .../asset-profile-routing.module.ts | 2 +- .../asset-profile-tabs.component.html | 2 +- .../asset-profile-tabs.component.ts | 2 +- .../asset-profile/asset-profile.module.ts | 2 +- .../asset-profiles-table-config.resolver.ts | 4 +- .../home/pages/asset/asset-routing.module.ts | 2 +- .../asset/asset-table-header.component.html | 2 +- .../asset/asset-table-header.component.ts | 2 +- .../pages/asset/asset-tabs.component.html | 2 +- .../home/pages/asset/asset-tabs.component.ts | 2 +- .../home/pages/asset/asset.component.html | 2 +- .../home/pages/asset/asset.component.scss | 2 +- .../home/pages/asset/asset.component.ts | 2 +- .../modules/home/pages/asset/asset.module.ts | 2 +- .../asset/assets-table-config.resolver.ts | 2 +- .../audit-log/audit-log-routing.module.ts | 2 +- .../home/pages/audit-log/audit-log.module.ts | 2 +- .../pages/customer/customer-routing.module.ts | 2 +- .../customer/customer-tabs.component.html | 2 +- .../pages/customer/customer-tabs.component.ts | 2 +- .../pages/customer/customer.component.html | 2 +- .../pages/customer/customer.component.scss | 2 +- .../home/pages/customer/customer.component.ts | 2 +- .../home/pages/customer/customer.module.ts | 2 +- .../customers-table-config.resolver.ts | 2 +- .../dashboard/dashboard-form.component.html | 35 +- .../dashboard/dashboard-form.component.scss | 2 +- .../dashboard/dashboard-form.component.ts | 11 +- .../dashboard/dashboard-routing.module.ts | 2 +- .../dashboard/dashboard-tabs.component.html | 2 +- .../dashboard/dashboard-tabs.component.ts | 2 +- .../home/pages/dashboard/dashboard.module.ts | 2 +- .../dashboards-table-config.resolver.ts | 52 +- ...ake-dashboard-public-dialog.component.html | 2 +- .../make-dashboard-public-dialog.component.ts | 2 +- ...-dashboard-customers-dialog.component.html | 2 +- ...ge-dashboard-customers-dialog.component.ts | 2 +- .../device-profile-routing.module.ts | 2 +- .../device-profile-tabs.component.html | 2 +- .../device-profile-tabs.component.ts | 2 +- .../device-profile/device-profile.module.ts | 2 +- .../device-profiles-table-config.resolver.ts | 4 +- ...ice-transport-configuration.component.html | 2 +- ...evice-transport-configuration.component.ts | 2 +- ...efault-device-configuration.component.html | 2 +- .../default-device-configuration.component.ts | 2 +- ...ice-transport-configuration.component.html | 2 +- ...evice-transport-configuration.component.ts | 2 +- .../data/device-configuration.component.html | 2 +- .../data/device-configuration.component.ts | 2 +- .../device/data/device-data.component.html | 2 +- .../device/data/device-data.component.ts | 2 +- ...ice-transport-configuration.component.html | 2 +- ...evice-transport-configuration.component.ts | 2 +- ...ice-transport-configuration.component.html | 2 +- ...evice-transport-configuration.component.ts | 2 +- ...ice-transport-configuration.component.html | 2 +- ...evice-transport-configuration.component.ts | 2 +- ...ice-transport-configuration.component.html | 2 +- ...evice-transport-configuration.component.ts | 2 +- ...e-check-connectivity-dialog.component.html | 4 +- ...e-check-connectivity-dialog.component.scss | 3 +- ...ice-check-connectivity-dialog.component.ts | 2 +- .../device-credentials-dialog.component.html | 2 +- .../device-credentials-dialog.component.scss | 2 +- .../device-credentials-dialog.component.ts | 2 +- .../pages/device/device-routing.module.ts | 2 +- .../device/device-table-header.component.html | 2 +- .../device/device-table-header.component.ts | 2 +- .../pages/device/device-tabs.component.html | 2 +- .../pages/device/device-tabs.component.ts | 2 +- .../home/pages/device/device.component.html | 2 +- .../home/pages/device/device.component.scss | 2 +- .../home/pages/device/device.component.ts | 2 +- .../home/pages/device/device.module.ts | 2 +- .../device/devices-table-config.resolver.ts | 2 +- .../edge-instructions-dialog.component.html | 2 +- .../edge-instructions-dialog.component.scss | 3 +- .../edge-instructions-dialog.component.ts | 39 +- .../home/pages/edge/edge-routing.module.ts | 2 +- .../edge/edge-table-header.component.html | 2 +- .../pages/edge/edge-table-header.component.ts | 2 +- .../home/pages/edge/edge-tabs.component.html | 2 +- .../home/pages/edge/edge-tabs.component.ts | 2 +- .../home/pages/edge/edge.component.html | 29 +- .../home/pages/edge/edge.component.scss | 2 +- .../modules/home/pages/edge/edge.component.ts | 9 +- .../modules/home/pages/edge/edge.module.ts | 2 +- .../pages/edge/edges-table-config.resolver.ts | 12 +- .../pages/entities/entities-routing.module.ts | 2 +- .../home/pages/entities/entities.module.ts | 2 +- .../entity-view/entity-view-routing.module.ts | 2 +- .../entity-view-table-header.component.html | 2 +- .../entity-view-table-header.component.ts | 2 +- .../entity-view-tabs.component.html | 2 +- .../entity-view/entity-view-tabs.component.ts | 2 +- .../entity-view/entity-view.component.html | 2 +- .../entity-view/entity-view.component.scss | 2 +- .../entity-view/entity-view.component.ts | 2 +- .../pages/entity-view/entity-view.module.ts | 2 +- .../entity-views-table-config.resolver.ts | 2 +- .../pages/features/features-routing.module.ts | 2 +- .../home/pages/features/features.module.ts | 2 +- .../home-links/home-links-routing.module.ts | 2 +- .../home-links/home-links.component.html | 2 +- .../home-links/home-links.component.scss | 2 +- .../pages/home-links/home-links.component.ts | 2 +- .../pages/home-links/home-links.module.ts | 2 +- .../modules/home/pages/home-pages.models.ts | 2 +- .../modules/home/pages/home-pages.module.ts | 2 +- .../inbox-notification-dialog.component.html | 2 +- .../inbox-notification-dialog.component.scss | 2 +- .../inbox-notification-dialog.component.ts | 2 +- .../inbox/inbox-table-config.resolver.ts | 2 +- .../inbox/inbox-table-header.component.html | 2 +- .../inbox/inbox-table-header.component.scss | 2 +- .../inbox/inbox-table-header.component.ts | 2 +- .../notification-routing.module.ts | 2 +- .../pages/notification/notification.module.ts | 2 +- ...cipient-notification-dialog.component.html | 2 +- ...cipient-notification-dialog.component.scss | 2 +- ...recipient-notification-dialog.component.ts | 2 +- .../recipient-table-config.resolver.ts | 2 +- .../recipient-table-header.component.html | 2 +- .../recipient-table-header.component.scss | 2 +- .../recipient-table-header.component.ts | 2 +- .../rule/escalation-form.component.html | 2 +- .../rule/escalation-form.component.scss | 2 +- .../rule/escalation-form.component.ts | 2 +- .../rule/escalations.component.html | 2 +- .../rule/escalations.component.ts | 2 +- .../rule-notification-dialog.component.html | 2 +- .../rule-notification-dialog.component.scss | 2 +- .../rule-notification-dialog.component.ts | 2 +- .../rule/rule-table-config.resolver.ts | 6 +- .../rule/rule-table-header.component.html | 2 +- .../rule/rule-table-header.component.scss | 2 +- .../rule/rule-table-header.component.ts | 2 +- .../sent/sent-error-dialog.component.html | 2 +- .../sent/sent-error-dialog.component.scss | 2 +- .../sent/sent-error-dialog.component.ts | 2 +- .../sent-notification-dialog.component.html | 2 +- .../sent-notification-dialog.component.scss | 2 +- .../sent/sent-notification-dialog.componet.ts | 2 +- .../sent/sent-table-config.resolver.ts | 4 +- .../notification-setting-form.component.html | 2 +- .../notification-setting-form.component.scss | 2 +- .../notification-setting-form.component.ts | 2 +- .../notification-settings-routing.modules.ts | 2 +- .../notification-settings.component.html | 2 +- .../notification-settings.component.scss | 2 +- .../notification-settings.component.ts | 25 +- .../template/template-configuration.ts | 4 +- ...emplate-notification-dialog.component.html | 2 +- ...emplate-notification-dialog.component.scss | 2 +- .../template-notification-dialog.component.ts | 2 +- .../template-table-config.resolver.ts | 2 +- .../template-table-header.component.html | 2 +- .../template-table-header.component.scss | 2 +- .../template-table-header.component.ts | 2 +- .../ota-update/ota-update-routing.module.ts | 2 +- .../ota-update-table-config.resolve.ts | 2 +- .../ota-update/ota-update.component.html | 3 +- .../pages/ota-update/ota-update.component.ts | 2 +- .../pages/ota-update/ota-update.module.ts | 2 +- .../pages/profile/profile-routing.module.ts | 2 +- .../home/pages/profile/profile.component.html | 2 +- .../home/pages/profile/profile.component.scss | 2 +- .../home/pages/profile/profile.component.ts | 2 +- .../home/pages/profile/profile.module.ts | 2 +- .../pages/profiles/profiles-routing.module.ts | 2 +- .../home/pages/profiles/profiles.module.ts | 2 +- .../src/app/modules/home/pages/public-api.ts | 2 +- .../add-rule-node-dialog.component.html | 2 +- .../add-rule-node-dialog.component.scss | 2 +- .../add-rule-node-link-dialog.component.html | 2 +- .../add-rule-node-link-dialog.component.scss | 2 +- ...ate-nested-rulechain-dialog.component.html | 2 +- .../rulechain/link-labels.component.html | 2 +- .../pages/rulechain/link-labels.component.ts | 2 +- .../pages/rulechain/rule-node-colors.scss | 2 +- .../rulechain/rule-node-config.component.html | 2 +- .../rulechain/rule-node-config.component.scss | 2 +- .../rulechain/rule-node-config.component.ts | 2 +- .../rule-node-details.component.html | 24 +- .../rule-node-details.component.scss | 2 +- .../rulechain/rule-node-details.component.ts | 71 +- .../rulechain/rule-node-link.component.html | 2 +- .../rulechain/rule-node-link.component.ts | 2 +- .../rulechain/rulechain-page.component.html | 2 +- .../rulechain/rulechain-page.component.scss | 2 +- .../rulechain/rulechain-page.component.ts | 9 +- .../pages/rulechain/rulechain-page.models.ts | 2 +- .../rulechain/rulechain-routing.module.ts | 2 +- .../rulechain/rulechain-tabs.component.html | 2 +- .../rulechain/rulechain-tabs.component.ts | 2 +- .../pages/rulechain/rulechain.component.html | 2 +- .../pages/rulechain/rulechain.component.scss | 2 +- .../pages/rulechain/rulechain.component.ts | 2 +- .../home/pages/rulechain/rulechain.module.ts | 2 +- .../rulechains-table-config.resolver.ts | 10 +- .../pages/rulechain/rulenode.component.html | 2 +- .../pages/rulechain/rulenode.component.scss | 2 +- .../pages/rulechain/rulenode.component.ts | 2 +- .../authentication-dialog.component.scss | 2 +- .../authentication-dialog.map.ts | 2 +- .../backup-code-auth-dialog.component.html | 2 +- .../backup-code-auth-dialog.component.ts | 4 +- .../email-auth-dialog.component.html | 2 +- .../email-auth-dialog.component.ts | 2 +- .../sms-auth-dialog.component.html | 2 +- .../sms-auth-dialog.component.ts | 2 +- .../totp-auth-dialog.component.html | 2 +- .../totp-auth-dialog.component.ts | 2 +- .../pages/security/security-routing.module.ts | 2 +- .../pages/security/security.component.html | 32 +- .../pages/security/security.component.scss | 2 +- .../home/pages/security/security.component.ts | 6 +- .../home/pages/security/security.module.ts | 2 +- .../tenant-profile-routing.module.ts | 2 +- .../tenant-profile-tabs.component.html | 2 +- .../tenant-profile-tabs.component.ts | 2 +- .../tenant-profile/tenant-profile.module.ts | 2 +- .../tenant-profiles-table-config.resolver.ts | 8 +- .../pages/tenant/tenant-routing.module.ts | 2 +- .../pages/tenant/tenant-tabs.component.html | 2 +- .../pages/tenant/tenant-tabs.component.ts | 2 +- .../home/pages/tenant/tenant.component.html | 2 +- .../home/pages/tenant/tenant.component.scss | 2 +- .../home/pages/tenant/tenant.component.ts | 2 +- .../home/pages/tenant/tenant.module.ts | 2 +- .../tenant/tenants-table-config.resolver.ts | 2 +- .../activation-link-dialog.component.html | 2 +- .../user/activation-link-dialog.component.ts | 2 +- .../pages/user/add-user-dialog.component.html | 2 +- .../pages/user/add-user-dialog.component.scss | 2 +- .../pages/user/add-user-dialog.component.ts | 2 +- .../home/pages/user/user-routing.module.ts | 2 +- .../home/pages/user/user-tabs.component.html | 2 +- .../home/pages/user/user-tabs.component.ts | 2 +- .../home/pages/user/user.component.html | 2 +- .../home/pages/user/user.component.scss | 2 +- .../modules/home/pages/user/user.component.ts | 2 +- .../modules/home/pages/user/user.module.ts | 2 +- .../pages/user/users-table-config.resolver.ts | 4 +- .../home/pages/vc/vc-routing.module.ts | 2 +- .../app/modules/home/pages/vc/vc.module.ts | 2 +- .../save-widget-type-as-dialog.component.html | 2 +- .../save-widget-type-as-dialog.component.ts | 2 +- .../select-widget-type-dialog.component.html | 2 +- .../select-widget-type-dialog.component.scss | 2 +- .../select-widget-type-dialog.component.ts | 2 +- .../pages/widget/widget-editor.component.html | 7 +- .../pages/widget/widget-editor.component.scss | 2 +- .../pages/widget/widget-editor.component.ts | 2 +- .../home/pages/widget/widget-editor.models.ts | 2 +- .../widget/widget-library-routing.module.ts | 50 +- .../pages/widget/widget-library.module.ts | 3 +- .../widget-type-autocomplete.component.html | 2 +- .../widget-type-autocomplete.component.scss | 2 +- .../widget-type-autocomplete.component.ts | 2 +- .../widget/widget-type-tabs.component.html | 2 +- .../widget/widget-type-tabs.component.ts | 2 +- .../pages/widget/widget-type.component.html | 13 +- .../pages/widget/widget-type.component.ts | 2 +- .../widget-types-table-config.resolver.ts | 24 +- .../widget/widgets-bundle-tabs.component.html | 2 +- .../widget/widgets-bundle-tabs.component.ts | 2 +- .../widgets-bundle-widgets.component.html | 4 +- .../widgets-bundle-widgets.component.scss | 5 +- .../widgets-bundle-widgets.component.ts | 14 +- .../widget/widgets-bundle.component.html | 17 +- .../widget/widgets-bundle.component.scss | 2 +- .../pages/widget/widgets-bundle.component.ts | 2 +- .../widgets-bundles-table-config.resolver.ts | 20 +- ui-ngx/src/app/modules/home/public-api.ts | 2 +- .../app/modules/login/login-routing.module.ts | 2 +- ui-ngx/src/app/modules/login/login.module.ts | 2 +- .../login/create-password.component.html | 2 +- .../login/create-password.component.scss | 2 +- .../pages/login/create-password.component.ts | 2 +- .../login/pages/login/login.component.html | 5 +- .../login/pages/login/login.component.scss | 2 +- .../login/pages/login/login.component.ts | 6 +- .../reset-password-request.component.html | 2 +- .../reset-password-request.component.scss | 2 +- .../login/reset-password-request.component.ts | 2 +- .../pages/login/reset-password.component.html | 2 +- .../pages/login/reset-password.component.scss | 2 +- .../pages/login/reset-password.component.ts | 2 +- .../two-factor-auth-login.component.html | 2 +- .../two-factor-auth-login.component.scss | 2 +- .../login/two-factor-auth-login.component.ts | 2 +- .../shared/adapter/custom-datatime-adapter.ts | 2 +- .../animations/speed-dial-fab.animations.ts | 2 +- .../components/breadcrumb.component.html | 2 +- .../components/breadcrumb.component.scss | 2 +- .../shared/components/breadcrumb.component.ts | 2 +- .../src/app/shared/components/breadcrumb.ts | 2 +- .../button/copy-button.component.html | 8 +- .../button/copy-button.component.scss | 2 +- .../button/copy-button.component.ts | 3 +- .../button/toggle-password.component.html | 2 +- .../button/toggle-password.component.ts | 2 +- .../shared/components/cheatsheet.component.ts | 2 +- .../components/circular-progress.directive.ts | 2 +- .../components/color-input.component.html | 2 +- .../components/color-input.component.scss | 3 +- .../components/color-input.component.ts | 2 +- .../color-picker-panel.component.html | 2 +- .../color-picker-panel.component.scss | 2 +- .../color-picker-panel.component.ts | 2 +- .../color-picker/color-picker.component.html | 2 +- .../color-picker/color-picker.component.scss | 4 +- .../color-picker/color-picker.component.ts | 2 +- .../shared/components/contact.component.html | 2 +- .../shared/components/contact.component.ts | 2 +- .../app/shared/components/css.component.html | 2 +- .../app/shared/components/css.component.scss | 2 +- .../app/shared/components/css.component.ts | 2 +- .../dashboard-autocomplete.component.html | 8 +- .../dashboard-autocomplete.component.ts | 26 +- .../dashboard-select-panel.component.html | 2 +- .../dashboard-select-panel.component.scss | 2 +- .../dashboard-select-panel.component.ts | 2 +- .../dashboard-select.component.html | 2 +- .../dashboard-select.component.scss | 2 +- .../components/dashboard-select.component.ts | 2 +- ...ashboard-state-autocomplete.component.html | 2 +- .../dashboard-state-autocomplete.component.ts | 2 +- .../app/shared/components/dialog.component.ts | 2 +- .../dialog/alert-dialog.component.html | 2 +- .../dialog/alert-dialog.component.scss | 2 +- .../dialog/alert-dialog.component.ts | 2 +- .../dialog/color-picker-dialog.component.html | 2 +- .../dialog/color-picker-dialog.component.scss | 2 +- .../dialog/color-picker-dialog.component.ts | 2 +- .../dialog/confirm-dialog.component.html | 2 +- .../dialog/confirm-dialog.component.scss | 2 +- .../dialog/confirm-dialog.component.ts | 2 +- .../dialog/error-alert-dialog.component.html | 2 +- .../dialog/error-alert-dialog.component.scss | 2 +- .../dialog/error-alert-dialog.component.ts | 2 +- .../json-object-edit-dialog.component.html | 2 +- .../json-object-edit-dialog.component.ts | 2 +- .../material-icons-dialog.component.html | 2 +- .../material-icons-dialog.component.scss | 2 +- .../dialog/material-icons-dialog.component.ts | 2 +- .../node-script-test-dialog.component.html | 2 +- .../node-script-test-dialog.component.scss | 2 +- .../node-script-test-dialog.component.ts | 2 +- .../dialog/todo-dialog.component.html | 2 +- .../dialog/todo-dialog.component.scss | 2 +- .../dialog/todo-dialog.component.ts | 2 +- .../directives/component-outlet.directive.ts | 2 +- .../sring-template-outlet.directive.ts | 2 +- .../directives/tb-json-to-string.directive.ts | 2 +- .../entity/entity-autocomplete.component.html | 8 +- .../entity/entity-autocomplete.component.ts | 7 +- .../entity-gateway-select.component.html | 2 +- .../entity/entity-gateway-select.component.ts | 2 +- .../entity/entity-keys-list.component.html | 2 +- .../entity/entity-keys-list.component.ts | 2 +- .../entity/entity-list-select.component.html | 2 +- .../entity/entity-list-select.component.scss | 2 +- .../entity/entity-list-select.component.ts | 2 +- .../entity/entity-list.component.html | 2 +- .../entity/entity-list.component.ts | 2 +- .../entity/entity-select.component.html | 2 +- .../entity/entity-select.component.scss | 2 +- .../entity/entity-select.component.ts | 2 +- ...entity-subtype-autocomplete.component.html | 2 +- .../entity-subtype-autocomplete.component.ts | 2 +- .../entity/entity-subtype-list.component.html | 2 +- .../entity/entity-subtype-list.component.ts | 4 +- .../entity-subtype-select.component.html | 2 +- .../entity-subtype-select.component.scss | 2 +- .../entity/entity-subtype-select.component.ts | 2 +- .../entity/entity-type-list.component.html | 2 +- .../entity/entity-type-list.component.ts | 2 +- .../entity/entity-type-select.component.html | 2 +- .../entity/entity-type-select.component.scss | 2 +- .../entity/entity-type-select.component.ts | 2 +- .../components/fab-toolbar.component.html | 2 +- .../components/fab-toolbar.component.scss | 2 +- .../components/fab-toolbar.component.ts | 2 +- .../components/file-input.component.html | 17 +- .../components/file-input.component.scss | 39 +- .../shared/components/file-input.component.ts | 62 +- .../footer-fab-buttons.component.html | 2 +- .../footer-fab-buttons.component.scss | 2 +- .../footer-fab-buttons.component.ts | 2 +- .../shared/components/footer.component.html | 2 +- .../shared/components/footer.component.scss | 2 +- .../app/shared/components/footer.component.ts | 2 +- .../shared/components/fullscreen.directive.ts | 2 +- .../grid}/scroll-grid-datasource.ts | 28 +- .../grid/scroll-grid.component.html | 11 +- .../grid/scroll-grid.component.scss | 3 +- .../components/grid/scroll-grid.component.ts | 76 +- .../components/help-markdown.component.html | 2 +- .../components/help-markdown.component.scss | 2 +- .../components/help-markdown.component.ts | 2 +- .../components/help-popup.component.html | 2 +- .../components/help-popup.component.scss | 2 +- .../shared/components/help-popup.component.ts | 2 +- .../app/shared/components/help.component.html | 2 +- .../app/shared/components/help.component.ts | 2 +- .../hint-tooltip-icon.component.html | 2 +- .../hint-tooltip-icon.component.scss | 2 +- .../components/hint-tooltip-icon.component.ts | 2 +- .../shared/components/hotkeys.directive.ts | 2 +- .../app/shared/components/html.component.html | 2 +- .../app/shared/components/html.component.scss | 2 +- .../app/shared/components/html.component.ts | 2 +- .../app/shared/components/icon.component.ts | 2 +- .../components/image-input.component.html | 7 +- .../components/image-input.component.scss | 31 +- .../components/image-input.component.ts | 63 +- .../image/embed-image-dialog.component.html | 60 + .../image/embed-image-dialog.component.scss | 71 + .../image/embed-image-dialog.component.ts | 94 + .../image/gallery-image-input.component.html | 94 + .../image/gallery-image-input.component.scss | 190 + .../image/gallery-image-input.component.ts | 205 + .../image/image-dialog.component.html | 107 + .../image/image-dialog.component.scss | 96 + .../image/image-dialog.component.ts | 163 + .../image/image-gallery-dialog.component.html | 32 + .../image/image-gallery-dialog.component.scss | 47 + .../image/image-gallery-dialog.component.ts | 62 + .../image/image-gallery.component.html | 397 + .../image/image-gallery.component.scss | 274 + .../image/image-gallery.component.ts | 702 ++ .../image/image-references.component.html | 54 + .../image/image-references.component.scss | 92 + .../image/image-references.component.ts | 171 + .../components/image/images-datasource.ts | 130 + .../image/images-in-use-dialog.component.html | 82 + .../image/images-in-use-dialog.component.scss | 40 + .../image/images-in-use-dialog.component.ts | 114 + ...ultiple-gallery-image-input.component.html | 111 + ...ultiple-gallery-image-input.component.scss | 225 + .../multiple-gallery-image-input.component.ts | 181 + .../image/upload-image-dialog.component.html | 65 + .../image/upload-image-dialog.component.ts | 115 + .../shared/components/js-func.component.html | 2 +- .../shared/components/js-func.component.scss | 2 +- .../shared/components/js-func.component.ts | 2 +- .../components/json-content.component.html | 2 +- .../components/json-content.component.scss | 2 +- .../components/json-content.component.ts | 2 +- .../json-form/json-form-component.models.ts | 2 +- .../json-form/json-form.component.html | 2 +- .../json-form/json-form.component.scss | 2 +- .../json-form/json-form.component.ts | 2 +- .../json-form/react/json-form-ace-editor.tsx | 2 +- .../json-form/react/json-form-array.tsx | 2 +- .../react/json-form-base-component.tsx | 2 +- .../json-form/react/json-form-checkbox.tsx | 2 +- .../json-form/react/json-form-color.tsx | 2 +- .../json-form/react/json-form-css.tsx | 2 +- .../json-form/react/json-form-date.tsx | 2 +- .../json-form/react/json-form-fieldset.tsx | 2 +- .../json-form/react/json-form-help.tsx | 2 +- .../json-form/react/json-form-html.tsx | 2 +- .../json-form/react/json-form-icon.tsx | 2 +- .../json-form/react/json-form-image.tsx | 2 +- .../json-form/react/json-form-javascript.tsx | 2 +- .../json-form/react/json-form-json.tsx | 2 +- .../json-form/react/json-form-markdown.tsx | 2 +- .../json-form/react/json-form-number.tsx | 2 +- .../json-form/react/json-form-radios.tsx | 2 +- .../json-form/react/json-form-rc-select.tsx | 2 +- .../json-form/react/json-form-react.tsx | 2 +- .../json-form/react/json-form-schema-form.tsx | 2 +- .../json-form/react/json-form-select.tsx | 2 +- .../json-form/react/json-form-text.tsx | 2 +- .../json-form/react/json-form-utils.ts | 2 +- .../json-form/react/json-form.models.ts | 2 +- .../components/json-form/react/json-form.scss | 2 +- .../react/styles/thingsboardTheme.ts | 2 +- .../json-object-edit.component.html | 2 +- .../json-object-edit.component.scss | 2 +- .../components/json-object-edit.component.ts | 2 +- .../json-object-view.component.html | 2 +- .../json-object-view.component.scss | 2 +- .../components/json-object-view.component.ts | 2 +- .../shared/components/kv-map.component.html | 2 +- .../shared/components/kv-map.component.scss | 2 +- .../app/shared/components/kv-map.component.ts | 2 +- .../components/led-light.component.html | 2 +- .../shared/components/led-light.component.ts | 2 +- .../app/shared/components/logo.component.html | 2 +- .../app/shared/components/logo.component.scss | 2 +- .../app/shared/components/logo.component.ts | 2 +- .../components/markdown-editor.component.html | 2 +- .../components/markdown-editor.component.scss | 2 +- .../components/markdown-editor.component.ts | 2 +- .../shared/components/markdown.component.html | 2 +- .../shared/components/markdown.component.scss | 3 +- .../shared/components/markdown.component.ts | 2 +- .../components/marked-options.service.ts | 2 +- .../material-icon-select.component.html | 2 +- .../material-icon-select.component.scss | 2 +- .../material-icon-select.component.ts | 2 +- .../components/material-icons.component.html | 2 +- .../components/material-icons.component.scss | 2 +- .../components/material-icons.component.ts | 2 +- .../message-type-autocomplete.component.html | 2 +- .../message-type-autocomplete.component.ts | 2 +- .../multiple-image-input.component.html | 2 +- .../multiple-image-input.component.scss | 2 +- .../multiple-image-input.component.ts | 2 +- .../shared/components/nav-tree.component.html | 2 +- .../shared/components/nav-tree.component.scss | 2 +- .../shared/components/nav-tree.component.ts | 2 +- .../notification/notification.component.html | 2 +- .../notification/notification.component.scss | 2 +- .../notification/notification.component.ts | 2 +- .../template-autocomplete.component.html | 2 +- .../template-autocomplete.component.scss | 2 +- .../template-autocomplete.component.ts | 2 +- .../ota-package-autocomplete.component.html | 7 +- .../ota-package-autocomplete.component.scss | 2 +- .../ota-package-autocomplete.component.ts | 26 +- .../app/shared/components/page.component.ts | 2 +- .../components/phone-input.component.html | 2 +- .../components/phone-input.component.scss | 2 +- .../components/phone-input.component.ts | 2 +- .../shared/components/popover.component.scss | 2 +- .../shared/components/popover.component.ts | 9 +- .../app/shared/components/popover.models.ts | 2 +- .../app/shared/components/popover.service.ts | 13 +- .../protobuf-content.component.html | 2 +- .../protobuf-content.component.scss | 2 +- .../components/protobuf-content.component.ts | 2 +- .../src/app/shared/components/public-api.ts | 4 +- .../queue/queue-autocomplete.component.html | 2 +- .../queue/queue-autocomplete.component.scss | 2 +- .../queue/queue-autocomplete.component.ts | 2 +- .../relation-type-autocomplete.component.html | 2 +- .../relation-type-autocomplete.component.ts | 2 +- .../resource-autocomplete.component.html | 2 +- .../resource-autocomplete.component.ts | 2 +- .../rule-chain-select.component.html | 2 +- .../rule-chain-select.component.scss | 2 +- .../rule-chain/rule-chain-select.component.ts | 4 +- .../components/script-lang.component.html | 2 +- .../components/script-lang.component.scss | 2 +- .../components/script-lang.component.ts | 2 +- ...k-conversation-autocomplete.component.html | 2 +- ...k-conversation-autocomplete.component.scss | 2 +- ...ack-conversation-autocomplete.component.ts | 2 +- .../components/snack-bar-component.html | 2 +- .../components/snack-bar-component.scss | 2 +- .../socialshare-panel.component.html | 2 +- .../socialshare-panel.component.scss | 2 +- .../components/socialshare-panel.component.ts | 2 +- .../string-autocomplete.component.html | 2 +- .../string-autocomplete.component.scss | 2 +- .../string-autocomplete.component.ts | 2 +- .../string-items-list.component.html | 2 +- .../components/string-items-list.component.ts | 2 +- .../shared/components/tb-anchor.component.ts | 2 +- .../components/tb-checkbox.component.html | 2 +- .../components/tb-checkbox.component.ts | 2 +- .../shared/components/tb-error.component.ts | 2 +- .../time/datetime-period.component.html | 2 +- .../time/datetime-period.component.scss | 2 +- .../time/datetime-period.component.ts | 2 +- .../components/time/datetime.component.html | 2 +- .../components/time/datetime.component.ts | 2 +- .../history-selector.component.html | 2 +- .../history-selector.component.scss | 2 +- .../history-selector.component.ts | 2 +- .../time/quick-time-interval.component.html | 2 +- .../time/quick-time-interval.component.scss | 2 +- .../time/quick-time-interval.component.ts | 2 +- .../time/timeinterval.component.html | 4 +- .../time/timeinterval.component.scss | 2 +- .../components/time/timeinterval.component.ts | 82 +- .../time/timewindow-panel.component.html | 6 +- .../time/timewindow-panel.component.scss | 2 +- .../time/timewindow-panel.component.ts | 35 +- .../components/time/timewindow.component.html | 2 +- .../components/time/timewindow.component.scss | 2 +- .../components/time/timewindow.component.ts | 2 +- .../time/timezone-select.component.html | 2 +- .../time/timezone-select.component.ts | 2 +- .../app/shared/components/toast.directive.ts | 2 +- .../components/toggle-header.component.html | 2 +- .../components/toggle-header.component.scss | 3 +- .../components/toggle-header.component.ts | 2 +- .../components/toggle-select.component.html | 2 +- .../components/toggle-select.component.ts | 2 +- ui-ngx/src/app/shared/components/tokens.ts | 2 +- .../components/unit-input.component.html | 2 +- .../components/unit-input.component.scss | 2 +- .../shared/components/unit-input.component.ts | 2 +- .../components/user-menu.component.html | 2 +- .../components/user-menu.component.scss | 2 +- .../shared/components/user-menu.component.ts | 2 +- .../components/value-input.component.html | 2 +- .../components/value-input.component.scss | 2 +- .../components/value-input.component.ts | 2 +- .../vc/branch-autocomplete.component.html | 2 +- .../vc/branch-autocomplete.component.scss | 2 +- .../vc/branch-autocomplete.component.ts | 2 +- .../widgets-bundle-search.component.html | 2 +- .../widgets-bundle-search.component.scss | 2 +- .../widgets-bundle-search.component.ts | 2 +- .../widgets-bundle-select.component.html | 2 +- .../widgets-bundle-select.component.scss | 2 +- .../widgets-bundle-select.component.ts | 2 +- ui-ngx/src/app/shared/decorators/coercion.ts | 2 +- .../src/app/shared/decorators/enumerable.ts | 2 +- .../src/app/shared/decorators/public-api.ts | 2 +- ui-ngx/src/app/shared/decorators/tb-inject.ts | 2 +- ...xport-widgets-bundle-dialog.component.html | 2 +- .../export-widgets-bundle-dialog.component.ts | 6 +- .../import-dialog-csv.component.html | 2 +- .../import-dialog-csv.component.scss | 2 +- .../import-dialog-csv.component.ts | 10 +- .../import-dialog.component.html | 2 +- .../import-export/import-dialog.component.ts | 2 +- .../import-export/import-export.models.ts | 2 +- .../import-export/import-export.service.ts | 293 +- .../table-columns-assignment.component.html | 2 +- .../table-columns-assignment.component.scss | 2 +- .../table-columns-assignment.component.ts | 4 +- .../app/shared/layout/layout.directives.ts | 2 +- .../src/app/shared/models/ace/ace.models.ts | 2 +- .../shared/models/ace/completion.models.ts | 2 +- .../models/ace/service-completion.models.ts | 2 +- .../app/shared/models/ace/tbel/mode-tbel.js | 2 +- .../app/shared/models/ace/tbel/worker-tbel.js | 2 +- .../models/ace/widget-completion.models.ts | 2 +- ui-ngx/src/app/shared/models/alarm.models.ts | 5 +- ui-ngx/src/app/shared/models/alias.models.ts | 2 +- .../src/app/shared/models/api-usage.models.ts | 2 +- ui-ngx/src/app/shared/models/asset.models.ts | 8 +- .../src/app/shared/models/audit-log.models.ts | 2 +- .../src/app/shared/models/authority.enum.ts | 2 +- ui-ngx/src/app/shared/models/base-data.ts | 4 +- .../src/app/shared/models/beautify.models.ts | 2 +- .../models/component-descriptor.models.ts | 3 +- ui-ngx/src/app/shared/models/constants.ts | 6 +- .../app/shared/models/contact-based.model.ts | 2 +- .../src/app/shared/models/country.models.ts | 2 +- .../src/app/shared/models/customer.model.ts | 5 +- .../src/app/shared/models/dashboard.models.ts | 9 +- ui-ngx/src/app/shared/models/device.models.ts | 17 +- ui-ngx/src/app/shared/models/edge.models.ts | 11 +- .../app/shared/models/entity-type.models.ts | 8 +- .../app/shared/models/entity-view.models.ts | 5 +- ui-ngx/src/app/shared/models/entity.models.ts | 7 +- ui-ngx/src/app/shared/models/error.models.ts | 2 +- ui-ngx/src/app/shared/models/event.models.ts | 2 +- ui-ngx/src/app/shared/models/icon.models.ts | 2 +- .../app/shared/models/id/alarm-comment-id.ts | 2 +- ui-ngx/src/app/shared/models/id/alarm-id.ts | 2 +- ui-ngx/src/app/shared/models/id/asset-id.ts | 2 +- .../app/shared/models/id/asset-profile-id.ts | 2 +- .../src/app/shared/models/id/audit-log-id.ts | 2 +- .../src/app/shared/models/id/customer-id.ts | 2 +- .../src/app/shared/models/id/dashboard-id.ts | 2 +- .../shared/models/id/device-credentials-id.ts | 2 +- ui-ngx/src/app/shared/models/id/device-id.ts | 2 +- .../app/shared/models/id/device-profile-id.ts | 2 +- ui-ngx/src/app/shared/models/id/edge-id.ts | 2 +- ui-ngx/src/app/shared/models/id/entity-id.ts | 2 +- .../app/shared/models/id/entity-view-id.ts | 2 +- ui-ngx/src/app/shared/models/id/event-id.ts | 2 +- ui-ngx/src/app/shared/models/id/has-uuid.ts | 2 +- .../app/shared/models/id/notification-id.ts | 2 +- .../models/id/notification-request-id.ts | 2 +- .../shared/models/id/notification-rule-id.ts | 2 +- .../models/id/notification-target-id.ts | 2 +- .../models/id/notification-template-id.ts | 2 +- .../app/shared/models/id/ota-package-id.ts | 2 +- ui-ngx/src/app/shared/models/id/public-api.ts | 2 +- ui-ngx/src/app/shared/models/id/queue-id.ts | 2 +- ui-ngx/src/app/shared/models/id/rpc-id.ts | 2 +- .../src/app/shared/models/id/rule-chain-id.ts | 2 +- .../src/app/shared/models/id/rule-node-id.ts | 2 +- .../app/shared/models/id/tb-resource-id.ts | 2 +- ui-ngx/src/app/shared/models/id/tenant-id.ts | 2 +- .../app/shared/models/id/tenant-profile-id.ts | 2 +- ui-ngx/src/app/shared/models/id/user-id.ts | 2 +- .../app/shared/models/id/widget-type-id.ts | 2 +- .../app/shared/models/id/widgets-bundle-id.ts | 2 +- .../app/shared/models/limited-api.models.ts | 2 +- ui-ngx/src/app/shared/models/login.models.ts | 2 +- .../models/lwm2m-security-config.models.ts | 2 +- .../src/app/shared/models/material.models.ts | 2 +- .../app/shared/models/notification.models.ts | 17 +- ui-ngx/src/app/shared/models/oauth2.models.ts | 2 +- .../app/shared/models/ota-package.models.ts | 5 +- .../src/app/shared/models/overlay.models.ts | 2 +- .../src/app/shared/models/page/page-data.ts | 2 +- .../src/app/shared/models/page/page-link.ts | 2 +- .../src/app/shared/models/page/public-api.ts | 2 +- .../src/app/shared/models/page/sort-order.ts | 2 +- ui-ngx/src/app/shared/models/public-api.ts | 4 +- .../app/shared/models/query/query.models.ts | 8 +- ui-ngx/src/app/shared/models/queue.models.ts | 5 +- .../src/app/shared/models/relation.models.ts | 2 +- .../src/app/shared/models/resource.models.ts | 107 +- ui-ngx/src/app/shared/models/rpc.models.ts | 2 +- .../app/shared/models/rule-chain.models.ts | 5 +- .../src/app/shared/models/rule-node.models.ts | 4 +- .../src/app/shared/models/settings.models.ts | 4 +- .../models/telemetry/telemetry.models.ts | 380 +- ui-ngx/src/app/shared/models/tenant.model.ts | 8 +- .../src/app/shared/models/time/time.models.ts | 190 +- .../shared/models/two-factor-auth.models.ts | 2 +- ui-ngx/src/app/shared/models/unit.models.ts | 2 +- ui-ngx/src/app/shared/models/usage.models.ts | 2 +- .../app/shared/models/user-settings.models.ts | 3 +- ui-ngx/src/app/shared/models/user.model.ts | 5 +- ui-ngx/src/app/shared/models/vc.models.ts | 6 +- .../websocket/notification-ws.models.ts | 240 - .../models/websocket/websocket.models.ts | 3 +- .../shared/models/widget-settings.models.ts | 137 +- ui-ngx/src/app/shared/models/widget.models.ts | 17 +- .../app/shared/models/widgets-bundle.model.ts | 5 +- .../app/shared/models/window-message.model.ts | 2 +- ui-ngx/src/app/shared/pipe/date-ago.pipe.ts | 2 +- .../src/app/shared/pipe/enum-to-array.pipe.ts | 2 +- ui-ngx/src/app/shared/pipe/file-size.pipe.ts | 2 +- ui-ngx/src/app/shared/pipe/highlight.pipe.ts | 2 +- ui-ngx/src/app/shared/pipe/image.pipe.ts | 70 + .../app/shared/pipe/keyboard-shortcut.pipe.ts | 2 +- .../pipe/milliseconds-to-time-string.pipe.ts | 2 +- ui-ngx/src/app/shared/pipe/nospace.pipe.ts | 2 +- ui-ngx/src/app/shared/pipe/public-api.ts | 3 +- ui-ngx/src/app/shared/pipe/safe.pipe.ts | 2 +- .../shared/pipe/selectable-columns.pipe.ts | 2 +- .../src/app/shared/pipe/short-number.pipe.ts | 2 +- ui-ngx/src/app/shared/pipe/tbJson.pipe.ts | 2 +- ui-ngx/src/app/shared/pipe/truncate.pipe.ts | 2 +- ui-ngx/src/app/shared/public-api.ts | 2 +- .../shared/services/custom-paginator-intl.ts | 2 +- ui-ngx/src/app/shared/shared.module.ts | 54 +- ui-ngx/src/assets/fonts/material-icons.css | 2 +- .../help/en_US/notification/rule_node.md | 1 + ...e_originator_node_fields_templatization.md | 81 + .../common_node_fields_templatization.md | 11 +- .../to_email_node_fields_templatization.md | 68 + .../examples/change-originator-ft-2.png | Bin 0 -> 43794 bytes .../examples/change-originator-ft-3.png | Bin 0 -> 43804 bytes .../examples/change-originator-ft.png | Bin 0 -> 45433 bytes .../images/rulenode/examples/to-email-ft.png | Bin 0 -> 85702 bytes .../assets/locale/locale.constant-ca_ES.json | 4 +- .../assets/locale/locale.constant-cs_CZ.json | 1 - .../assets/locale/locale.constant-de_DE.json | 233 +- .../assets/locale/locale.constant-en_US.json | 341 +- .../assets/locale/locale.constant-es_ES.json | 36 +- .../assets/locale/locale.constant-fr_FR.json | 1 - .../assets/locale/locale.constant-nl_BE.json | 6951 +++++++++++++++++ .../assets/locale/locale.constant-ru_RU.json | 1875 ----- .../assets/locale/locale.constant-tr_TR.json | 1 - .../assets/locale/locale.constant-uk_UA.json | 208 +- .../assets/locale/locale.constant-zh_CN.json | 1553 +++- .../assets/locale/locale.constant-zh_TW.json | 1 - ui-ngx/src/assets/metadata/units.json | 5 + ui-ngx/src/environments/environment.prod.ts | 2 +- ui-ngx/src/environments/environment.ts | 2 +- ui-ngx/src/form.scss | 4 +- ui-ngx/src/index.html | 2 +- ui-ngx/src/karma.conf.js | 2 +- ui-ngx/src/main.ts | 2 +- ui-ngx/src/polyfills.ts | 2 +- ui-ngx/src/scss/animations.scss | 2 +- ui-ngx/src/scss/constants.scss | 2 +- ui-ngx/src/scss/fonts.scss | 2 +- ui-ngx/src/scss/mixins.scss | 2 +- ui-ngx/src/styles.scss | 2 +- ui-ngx/src/test.ts | 2 +- ui-ngx/src/theme-overwrites.scss | 2 +- ui-ngx/src/theme.scss | 2 +- ui-ngx/src/theme/datepicker-theme.scss | 2 +- ui-ngx/src/typings/jquery.flot.typings.d.ts | 2 +- ui-ngx/src/typings/jquery.jstree.typings.d.ts | 2 +- ui-ngx/src/typings/jquery.typings.d.ts | 2 +- ui-ngx/src/typings/leaflet-extend-tb.d.ts | 2 +- ui-ngx/src/typings/leaflet-geoman-extend.d.ts | 2 +- ui-ngx/src/typings/rawloader.typings.d.ts | 2 +- ui-ngx/src/typings/split.js.typings.d.ts | 2 +- ui-ngx/src/typings/utils.d.ts | 2 +- ui-ngx/src/zone-flags.ts | 2 +- ui-ngx/yarn.lock | 5 + 6174 files changed, 49730 insertions(+), 16385 deletions(-) delete mode 100644 application/src/main/data/json/demo/dashboards/gateways.json delete mode 100644 application/src/main/data/json/edge/install_instructions/docker/localhost_warning.md rename application/src/main/data/json/edge/{install_instructions => instructions/install}/centos/instructions.md (91%) rename application/src/main/data/json/edge/{install_instructions => instructions/install}/docker/instructions.md (77%) rename application/src/main/data/json/edge/{install_instructions => instructions/install}/ubuntu/instructions.md (97%) create mode 100644 application/src/main/data/json/edge/instructions/upgrade/centos/instructions.md create mode 100644 application/src/main/data/json/edge/instructions/upgrade/docker/instructions.md create mode 100644 application/src/main/data/json/edge/instructions/upgrade/docker/start_service.md create mode 100644 application/src/main/data/json/edge/instructions/upgrade/docker/upgrade_db.md create mode 100644 application/src/main/data/json/edge/instructions/upgrade/docker/upgrade_preparing.md create mode 100644 application/src/main/data/json/edge/instructions/upgrade/start_service.md create mode 100644 application/src/main/data/json/edge/instructions/upgrade/ubuntu/instructions.md create mode 100644 application/src/main/data/json/edge/instructions/upgrade/upgrade_db.md create mode 100644 application/src/main/data/json/edge/instructions/upgrade/upgrade_preparing.md create mode 100644 application/src/main/data/json/system/widget_bundles/industial_widgets.json create mode 100644 application/src/main/data/json/system/widget_types/bar_chart_with_labels.json create mode 100644 application/src/main/data/json/system/widget_types/carbon_monoxide__co__card.json create mode 100644 application/src/main/data/json/system/widget_types/carbon_monoxide__co__card_with_background.json create mode 100644 application/src/main/data/json/system/widget_types/carbon_monoxide__co__chart_card.json create mode 100644 application/src/main/data/json/system/widget_types/carbon_monoxide__co__chart_card_with_background.json create mode 100644 application/src/main/data/json/system/widget_types/efficiency_card.json create mode 100644 application/src/main/data/json/system/widget_types/efficiency_card_with_background.json create mode 100644 application/src/main/data/json/system/widget_types/efficiency_chart_card.json create mode 100644 application/src/main/data/json/system/widget_types/efficiency_chart_card_with_background.json create mode 100644 application/src/main/data/json/system/widget_types/efficiency_progress_bar.json create mode 100644 application/src/main/data/json/system/widget_types/efficiency_progress_bar_with_background.json create mode 100644 application/src/main/data/json/system/widget_types/efficiency_range_chart.json create mode 100644 application/src/main/data/json/system/widget_types/efficiency_range_chart_with_background.json create mode 100644 application/src/main/data/json/system/widget_types/flow_rate_card.json create mode 100644 application/src/main/data/json/system/widget_types/flow_rate_card_with_background.json create mode 100644 application/src/main/data/json/system/widget_types/flow_rate_chart_card.json create mode 100644 application/src/main/data/json/system/widget_types/flow_rate_chart_card_with_background.json create mode 100644 application/src/main/data/json/system/widget_types/flow_rate_gauge.json create mode 100644 application/src/main/data/json/system/widget_types/flow_rate_progress_bar.json create mode 100644 application/src/main/data/json/system/widget_types/flow_rate_progress_bar_with_background.json create mode 100644 application/src/main/data/json/system/widget_types/flow_rate_range_chart.json create mode 100644 application/src/main/data/json/system/widget_types/flow_rate_range_chart_with_background.json create mode 100644 application/src/main/data/json/system/widget_types/fluid_pressure_card.json create mode 100644 application/src/main/data/json/system/widget_types/fluid_pressure_card_with_background.json create mode 100644 application/src/main/data/json/system/widget_types/fluid_pressure_chart_card.json create mode 100644 application/src/main/data/json/system/widget_types/fluid_pressure_chart_card_with_background.json create mode 100644 application/src/main/data/json/system/widget_types/fluid_pressure_gauge.json create mode 100644 application/src/main/data/json/system/widget_types/fluid_pressure_progress_bar.json create mode 100644 application/src/main/data/json/system/widget_types/fluid_pressure_progress_bar_with_background.json create mode 100644 application/src/main/data/json/system/widget_types/fluid_pressure_range_chart.json create mode 100644 application/src/main/data/json/system/widget_types/fluid_pressure_range_chart_with_background.json create mode 100644 application/src/main/data/json/system/widget_types/horizontal_carbon_monoxide__co__card.json create mode 100644 application/src/main/data/json/system/widget_types/horizontal_carbon_monoxide__co__card_with_background.json create mode 100644 application/src/main/data/json/system/widget_types/horizontal_efficiency_card.json create mode 100644 application/src/main/data/json/system/widget_types/horizontal_efficiency_card_with_background.json create mode 100644 application/src/main/data/json/system/widget_types/horizontal_flow_rate_card.json create mode 100644 application/src/main/data/json/system/widget_types/horizontal_flow_rate_card_with_background.json create mode 100644 application/src/main/data/json/system/widget_types/horizontal_fluid_pressure_card.json create mode 100644 application/src/main/data/json/system/widget_types/horizontal_fluid_pressure_card_with_background.json create mode 100644 application/src/main/data/json/system/widget_types/horizontal_individual_allergy_index__iai__card.json create mode 100644 application/src/main/data/json/system/widget_types/horizontal_individual_allergy_index__iai__card_with_background.json create mode 100644 application/src/main/data/json/system/widget_types/horizontal_nitrogen_dioxide__no2__card.json create mode 100644 application/src/main/data/json/system/widget_types/horizontal_nitrogen_dioxide__no2__card_with_background.json create mode 100644 application/src/main/data/json/system/widget_types/horizontal_ozone__o3__card.json create mode 100644 application/src/main/data/json/system/widget_types/horizontal_ozone__o3__card_with_background.json create mode 100644 application/src/main/data/json/system/widget_types/horizontal_power_consumption_card.json create mode 100644 application/src/main/data/json/system/widget_types/horizontal_power_consumption_card_with_background.json create mode 100644 application/src/main/data/json/system/widget_types/horizontal_pump_vibration_card.json create mode 100644 application/src/main/data/json/system/widget_types/horizontal_pump_vibration_card_with_background.json create mode 100644 application/src/main/data/json/system/widget_types/horizontal_rotational_speed_card.json create mode 100644 application/src/main/data/json/system/widget_types/horizontal_rotational_speed_card_with_background.json create mode 100644 application/src/main/data/json/system/widget_types/horizontal_sulfur_dioxide__so2__card.json create mode 100644 application/src/main/data/json/system/widget_types/horizontal_sulfur_dioxide__so2__card_with_background.json create mode 100644 application/src/main/data/json/system/widget_types/individual_allergy_index__iai__card.json create mode 100644 application/src/main/data/json/system/widget_types/individual_allergy_index__iai__card_with_background.json create mode 100644 application/src/main/data/json/system/widget_types/individual_allergy_index__iai__chart_card.json create mode 100644 application/src/main/data/json/system/widget_types/individual_allergy_index__iai__chart_card_with_background.json create mode 100644 application/src/main/data/json/system/widget_types/indoor_temperature_gauge.json create mode 100644 application/src/main/data/json/system/widget_types/indoor_temperature_range_chart.json create mode 100644 application/src/main/data/json/system/widget_types/indoor_temperature_range_chart_with_background.json create mode 100644 application/src/main/data/json/system/widget_types/nitrogen_dioxide__no2__card.json create mode 100644 application/src/main/data/json/system/widget_types/nitrogen_dioxide__no2__card_with_background.json create mode 100644 application/src/main/data/json/system/widget_types/nitrogen_dioxide__no2__chart_card.json create mode 100644 application/src/main/data/json/system/widget_types/nitrogen_dioxide__no2__chart_card_with_background.json create mode 100644 application/src/main/data/json/system/widget_types/ozone__o3__card.json create mode 100644 application/src/main/data/json/system/widget_types/ozone__o3__card_with_background.json create mode 100644 application/src/main/data/json/system/widget_types/ozone__o3__chart_card.json create mode 100644 application/src/main/data/json/system/widget_types/ozone__o3__chart_card_with_background.json create mode 100644 application/src/main/data/json/system/widget_types/power_consumption_card.json create mode 100644 application/src/main/data/json/system/widget_types/power_consumption_card_with_background.json create mode 100644 application/src/main/data/json/system/widget_types/power_consumption_chart_card.json create mode 100644 application/src/main/data/json/system/widget_types/power_consumption_chart_card_with_background.json create mode 100644 application/src/main/data/json/system/widget_types/power_consumption_range_chart.json create mode 100644 application/src/main/data/json/system/widget_types/power_consumption_range_chart_with_background.json create mode 100644 application/src/main/data/json/system/widget_types/pump_vibration_card.json create mode 100644 application/src/main/data/json/system/widget_types/pump_vibration_card_with_background.json create mode 100644 application/src/main/data/json/system/widget_types/pump_vibration_chart_card.json create mode 100644 application/src/main/data/json/system/widget_types/pump_vibration_chart_card_with_background.json create mode 100644 application/src/main/data/json/system/widget_types/pump_vibration_range_chart.json create mode 100644 application/src/main/data/json/system/widget_types/pump_vibration_range_chart_with_background.json create mode 100644 application/src/main/data/json/system/widget_types/range_chart.json create mode 100644 application/src/main/data/json/system/widget_types/rotational_speed_card.json create mode 100644 application/src/main/data/json/system/widget_types/rotational_speed_card_with_background.json create mode 100644 application/src/main/data/json/system/widget_types/rotational_speed_chart_card.json create mode 100644 application/src/main/data/json/system/widget_types/rotational_speed_chart_card_with_background.json create mode 100644 application/src/main/data/json/system/widget_types/rotational_speed_gauge.json create mode 100644 application/src/main/data/json/system/widget_types/rotational_speed_progress_bar.json create mode 100644 application/src/main/data/json/system/widget_types/rotational_speed_progress_bar_with_background.json create mode 100644 application/src/main/data/json/system/widget_types/rotational_speed_range_chart.json create mode 100644 application/src/main/data/json/system/widget_types/rotational_speed_range_chart_with_background.json create mode 100644 application/src/main/data/json/system/widget_types/simple_carbon_monoxide__co__chart_card.json create mode 100644 application/src/main/data/json/system/widget_types/simple_carbon_monoxide__co__chart_card_with_background.json create mode 100644 application/src/main/data/json/system/widget_types/simple_efficiency_chart_card.json create mode 100644 application/src/main/data/json/system/widget_types/simple_efficiency_chart_card_with_background.json create mode 100644 application/src/main/data/json/system/widget_types/simple_flow_rate_chart_card.json create mode 100644 application/src/main/data/json/system/widget_types/simple_flow_rate_chart_card_with_background.json create mode 100644 application/src/main/data/json/system/widget_types/simple_fluid_pressure_chart_card.json create mode 100644 application/src/main/data/json/system/widget_types/simple_fluid_pressure_chart_card_with_background.json create mode 100644 application/src/main/data/json/system/widget_types/simple_individual_allergy_index__iai__chart_card.json create mode 100644 application/src/main/data/json/system/widget_types/simple_individual_allergy_index__iai__chart_card_with_background.json create mode 100644 application/src/main/data/json/system/widget_types/simple_nitrogen_dioxide__no2__chart_card.json create mode 100644 application/src/main/data/json/system/widget_types/simple_nitrogen_dioxide__no2__chart_card_with_background.json create mode 100644 application/src/main/data/json/system/widget_types/simple_ozone__o3__chart_card.json create mode 100644 application/src/main/data/json/system/widget_types/simple_ozone__o3__chart_card_with_background.json create mode 100644 application/src/main/data/json/system/widget_types/simple_power_consumption_chart_card.json create mode 100644 application/src/main/data/json/system/widget_types/simple_power_consumption_chart_card_with_background.json create mode 100644 application/src/main/data/json/system/widget_types/simple_pump_vibration_chart_card.json create mode 100644 application/src/main/data/json/system/widget_types/simple_pump_vibration_chart_card_with_background.json create mode 100644 application/src/main/data/json/system/widget_types/simple_rotational_speed_chart_card.json create mode 100644 application/src/main/data/json/system/widget_types/simple_rotational_speed_chart_card_with_background.json create mode 100644 application/src/main/data/json/system/widget_types/simple_sulfur_dioxide__so2__chart_card.json create mode 100644 application/src/main/data/json/system/widget_types/simple_sulfur_dioxide__so2__chart_card_with_background.json create mode 100644 application/src/main/data/json/system/widget_types/sulfur_dioxide__so2__card.json create mode 100644 application/src/main/data/json/system/widget_types/sulfur_dioxide__so2__card_with_background.json create mode 100644 application/src/main/data/json/system/widget_types/sulfur_dioxide__so2__chart_card.json create mode 100644 application/src/main/data/json/system/widget_types/sulfur_dioxide__so2__chart_card_with_background.json create mode 100644 application/src/main/data/json/system/widget_types/temperature_gauge.json create mode 100644 application/src/main/data/json/system/widget_types/temperature_range_chart.json create mode 100644 application/src/main/data/json/system/widget_types/temperature_range_chart_with_background.json rename application/src/main/data/json/{demo/dashboards/gateway.json => tenant/dashboards/gateways.json} (96%) create mode 100644 application/src/main/data/upgrade/3.6.1/save_attributes_node_update.sql create mode 100644 application/src/main/data/upgrade/3.6.1/schema_update.sql create mode 100644 application/src/main/data/upgrade/3.6.2/schema_update.sql create mode 100644 application/src/main/java/org/thingsboard/server/config/TbRuleEngineSecurityConfiguration.java create mode 100644 application/src/main/java/org/thingsboard/server/controller/ImageController.java create mode 100644 application/src/main/java/org/thingsboard/server/exception/ThingsboardCredentialsViolationResponse.java rename application/src/main/java/org/thingsboard/server/service/edge/instructions/{DefaultEdgeInstallService.java => DefaultEdgeInstallInstructionsService.java} (77%) create mode 100644 application/src/main/java/org/thingsboard/server/service/edge/instructions/DefaultEdgeUpgradeInstructionsService.java rename application/src/main/java/org/thingsboard/server/service/edge/instructions/{EdgeInstallService.java => EdgeInstallInstructionsService.java} (67%) create mode 100644 application/src/main/java/org/thingsboard/server/service/edge/instructions/EdgeUpgradeInstructionsService.java delete mode 100644 application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/AssetMsgConstructor.java create mode 100644 application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/BaseMsgConstructorFactory.java delete mode 100644 application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/DeviceProfileMsgConstructor.java rename application/src/main/java/org/thingsboard/server/service/{ws/notification/cmd/WsCmd.java => edge/rpc/constructor/MsgConstructor.java} (78%) delete mode 100644 application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/TenantProfileMsgConstructor.java delete mode 100644 application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/WidgetsBundleMsgConstructor.java create mode 100644 application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/alarm/AlarmMsgConstructor.java create mode 100644 application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/alarm/AlarmMsgConstructorFactory.java rename application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/{AlarmMsgConstructor.java => alarm/AlarmMsgConstructorV1.java} (88%) create mode 100644 application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/alarm/AlarmMsgConstructorV2.java create mode 100644 application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/alarm/BaseAlarmMsgConstructor.java create mode 100644 application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/asset/AssetMsgConstructor.java create mode 100644 application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/asset/AssetMsgConstructorFactory.java rename application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/{AssetProfileMsgConstructor.java => asset/AssetMsgConstructorV1.java} (58%) create mode 100644 application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/asset/AssetMsgConstructorV2.java create mode 100644 application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/asset/BaseAssetMsgConstructor.java create mode 100644 application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/customer/BaseCustomerMsgConstructor.java create mode 100644 application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/customer/CustomerMsgConstructor.java create mode 100644 application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/customer/CustomerMsgConstructorFactory.java rename application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/{CustomerMsgConstructor.java => customer/CustomerMsgConstructorV1.java} (80%) create mode 100644 application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/customer/CustomerMsgConstructorV2.java create mode 100644 application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/dashboard/BaseDashboardMsgConstructor.java create mode 100644 application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/dashboard/DashboardMsgConstructor.java create mode 100644 application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/dashboard/DashboardMsgConstructorFactory.java rename application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/{DashboardMsgConstructor.java => dashboard/DashboardMsgConstructorV1.java} (77%) create mode 100644 application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/dashboard/DashboardMsgConstructorV2.java create mode 100644 application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/device/BaseDeviceMsgConstructor.java create mode 100644 application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/device/DeviceMsgConstructor.java create mode 100644 application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/device/DeviceMsgConstructorFactory.java rename application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/{DeviceMsgConstructor.java => device/DeviceMsgConstructorV1.java} (56%) create mode 100644 application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/device/DeviceMsgConstructorV2.java rename application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/{ => edge}/EdgeMsgConstructor.java (94%) create mode 100644 application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/entityview/BaseEntityViewMsgConstructor.java create mode 100644 application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/entityview/EntityViewMsgConstructor.java create mode 100644 application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/entityview/EntityViewMsgConstructorFactory.java rename application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/{EntityViewMsgConstructor.java => entityview/EntityViewMsgConstructorV1.java} (71%) create mode 100644 application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/entityview/EntityViewMsgConstructorV2.java create mode 100644 application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/ota/BaseOtaPackageMsgConstructor.java create mode 100644 application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/ota/OtaPackageMsgConstructor.java create mode 100644 application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/ota/OtaPackageMsgConstructorFactory.java rename application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/{OtaPackageMsgConstructor.java => ota/OtaPackageMsgConstructorV1.java} (83%) create mode 100644 application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/ota/OtaPackageMsgConstructorV2.java create mode 100644 application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/queue/BaseQueueMsgConstructor.java create mode 100644 application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/queue/QueueMsgConstructor.java create mode 100644 application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/queue/QueueMsgConstructorFactory.java rename application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/{QueueMsgConstructor.java => queue/QueueMsgConstructorV1.java} (92%) create mode 100644 application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/queue/QueueMsgConstructorV2.java create mode 100644 application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/relation/RelationMsgConstructor.java create mode 100644 application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/relation/RelationMsgConstructorFactory.java rename application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/{RelationMsgConstructor.java => relation/RelationMsgConstructorV1.java} (90%) create mode 100644 application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/relation/RelationMsgConstructorV2.java create mode 100644 application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/resource/BaseResourceMsgConstructor.java create mode 100644 application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/resource/ResourceMsgConstructor.java create mode 100644 application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/resource/ResourceMsgConstructorFactory.java rename application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/{ResourceMsgConstructor.java => resource/ResourceMsgConstructorV1.java} (72%) create mode 100644 application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/resource/ResourceMsgConstructorV2.java rename application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/rule/{AbstractRuleChainMetadataConstructor.java => BaseRuleChainMetadataConstructor.java} (87%) rename application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/{RuleChainMsgConstructor.java => rule/BaseRuleChainMsgConstructor.java} (52%) create mode 100644 application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/rule/RuleChainMetadataConstructorV362.java create mode 100644 application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/rule/RuleChainMsgConstructor.java create mode 100644 application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/rule/RuleChainMsgConstructorFactory.java create mode 100644 application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/rule/RuleChainMsgConstructorV1.java create mode 100644 application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/rule/RuleChainMsgConstructorV2.java create mode 100644 application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/settings/AdminSettingsMsgConstructor.java create mode 100644 application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/settings/AdminSettingsMsgConstructorFactory.java rename application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/{AdminSettingsMsgConstructor.java => settings/AdminSettingsMsgConstructorV1.java} (78%) create mode 100644 application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/settings/AdminSettingsMsgConstructorV2.java rename application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/{ => telemetry}/EntityDataMsgConstructor.java (96%) create mode 100644 application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/tenant/TenantMsgConstructor.java create mode 100644 application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/tenant/TenantMsgConstructorFactory.java rename application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/{TenantMsgConstructor.java => tenant/TenantMsgConstructorV1.java} (58%) create mode 100644 application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/tenant/TenantMsgConstructorV2.java create mode 100644 application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/user/BaseUserMsgConstructor.java create mode 100644 application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/user/UserMsgConstructor.java create mode 100644 application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/user/UserMsgConstructorFactory.java rename application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/{UserMsgConstructor.java => user/UserMsgConstructorV1.java} (77%) create mode 100644 application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/user/UserMsgConstructorV2.java create mode 100644 application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/widget/BaseWidgetMsgConstructor.java create mode 100644 application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/widget/WidgetMsgConstructor.java create mode 100644 application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/widget/WidgetMsgConstructorFactory.java rename application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/{WidgetTypeMsgConstructor.java => widget/WidgetMsgConstructorV1.java} (62%) create mode 100644 application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/widget/WidgetMsgConstructorV2.java delete mode 100644 application/src/main/java/org/thingsboard/server/service/edge/rpc/fetch/BaseResourceEdgeEventFetcher.java delete mode 100644 application/src/main/java/org/thingsboard/server/service/edge/rpc/fetch/SystemResourcesEdgeEventFetcher.java create mode 100644 application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/BaseEdgeProcessorFactory.java create mode 100644 application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/EdgeProcessor.java create mode 100644 application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/alarm/AlarmEdgeProcessorFactory.java create mode 100644 application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/alarm/AlarmEdgeProcessorV1.java create mode 100644 application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/alarm/AlarmEdgeProcessorV2.java create mode 100644 application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/alarm/AlarmProcessor.java create mode 100644 application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/asset/AssetEdgeProcessorFactory.java create mode 100644 application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/asset/AssetEdgeProcessorV1.java create mode 100644 application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/asset/AssetEdgeProcessorV2.java create mode 100644 application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/asset/AssetProcessor.java rename application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/asset/{ => profile}/AssetProfileEdgeProcessor.java (77%) create mode 100644 application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/asset/profile/AssetProfileEdgeProcessorFactory.java create mode 100644 application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/asset/profile/AssetProfileEdgeProcessorV1.java create mode 100644 application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/asset/profile/AssetProfileEdgeProcessorV2.java create mode 100644 application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/asset/profile/AssetProfileProcessor.java rename application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/asset/{ => profile}/BaseAssetProfileProcessor.java (57%) create mode 100644 application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/dashboard/DashboardEdgeProcessorFactory.java create mode 100644 application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/dashboard/DashboardEdgeProcessorV1.java create mode 100644 application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/dashboard/DashboardEdgeProcessorV2.java create mode 100644 application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/dashboard/DashboardProcessor.java delete mode 100644 application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/device/BaseDeviceProfileProcessor.java create mode 100644 application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/device/DeviceEdgeProcessorFactory.java create mode 100644 application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/device/DeviceEdgeProcessorV1.java create mode 100644 application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/device/DeviceEdgeProcessorV2.java create mode 100644 application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/device/DeviceProcessor.java create mode 100644 application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/device/profile/BaseDeviceProfileProcessor.java rename application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/device/{ => profile}/DeviceProfileEdgeProcessor.java (78%) create mode 100644 application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/device/profile/DeviceProfileEdgeProcessorFactory.java create mode 100644 application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/device/profile/DeviceProfileEdgeProcessorV1.java create mode 100644 application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/device/profile/DeviceProfileEdgeProcessorV2.java create mode 100644 application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/device/profile/DeviceProfileProcessor.java create mode 100644 application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/entityview/EntityViewProcessor.java create mode 100644 application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/entityview/EntityViewProcessorFactory.java create mode 100644 application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/entityview/EntityViewProcessorV1.java create mode 100644 application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/entityview/EntityViewProcessorV2.java create mode 100644 application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/relation/RelationEdgeProcessorFactory.java create mode 100644 application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/relation/RelationEdgeProcessorV1.java create mode 100644 application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/relation/RelationEdgeProcessorV2.java create mode 100644 application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/relation/RelationProcessor.java create mode 100644 application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/resource/ResourceEdgeProcessorFactory.java create mode 100644 application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/resource/ResourceEdgeProcessorV1.java create mode 100644 application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/resource/ResourceEdgeProcessorV2.java create mode 100644 application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/resource/ResourceProcessor.java create mode 100644 application/src/main/java/org/thingsboard/server/service/executors/PubSubRuleNodeExecutorProvider.java create mode 100644 application/src/main/java/org/thingsboard/server/service/executors/VersionControlExecutor.java create mode 100644 application/src/main/java/org/thingsboard/server/service/install/update/ImagesUpdater.java create mode 100644 application/src/main/java/org/thingsboard/server/service/resource/DefaultTbImageService.java create mode 100644 application/src/main/java/org/thingsboard/server/service/resource/TbImageService.java create mode 100644 application/src/main/java/org/thingsboard/server/service/security/exception/UserPasswordNotValidException.java create mode 100644 application/src/main/java/org/thingsboard/server/service/sync/ie/exporting/impl/ResourceExportService.java create mode 100644 application/src/main/java/org/thingsboard/server/service/sync/ie/importing/impl/ResourceImportService.java rename rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/flow/TbCheckpointNodeConfiguration.java => application/src/main/java/org/thingsboard/server/service/ws/AuthCmd.java (60%) create mode 100644 application/src/main/java/org/thingsboard/server/service/ws/WsCmd.java create mode 100644 application/src/main/java/org/thingsboard/server/service/ws/WsCmdType.java create mode 100644 application/src/main/java/org/thingsboard/server/service/ws/WsCommandsWrapper.java rename application/src/main/java/org/thingsboard/server/service/ws/telemetry/cmd/{TelemetryPluginCmdsWrapper.java => TelemetryCmdsWrapper.java} (68%) create mode 100644 application/src/test/java/org/thingsboard/server/controller/ImageControllerTest.java create mode 100644 application/src/test/java/org/thingsboard/server/transport/coap/client/CoapClientIntegrationTest.java create mode 100644 common/dao-api/src/main/java/org/thingsboard/server/dao/resource/ImageService.java create mode 100644 common/data/src/main/java/org/thingsboard/server/common/data/EdgeUpgradeInfo.java create mode 100644 common/data/src/main/java/org/thingsboard/server/common/data/EdgeUpgradeMessage.java create mode 100644 common/data/src/main/java/org/thingsboard/server/common/data/FstStatsService.java create mode 100644 common/data/src/main/java/org/thingsboard/server/common/data/HasImage.java create mode 100644 common/data/src/main/java/org/thingsboard/server/common/data/ImageDescriptor.java create mode 100644 common/data/src/main/java/org/thingsboard/server/common/data/ImageExportData.java create mode 100644 common/data/src/main/java/org/thingsboard/server/common/data/TbImageDeleteResult.java rename common/data/src/main/java/org/thingsboard/server/common/data/edge/{EdgeInstallInstructions.java => EdgeInstructions.java} (86%) create mode 100644 common/data/src/main/java/org/thingsboard/server/common/data/kv/AggregationParams.java create mode 100644 common/data/src/main/java/org/thingsboard/server/common/data/kv/IntervalType.java create mode 100644 common/data/src/main/java/org/thingsboard/server/common/data/util/ThrowingSupplier.java create mode 100644 common/message/src/main/java/org/thingsboard/server/common/msg/rule/engine/DeviceDeleteMsg.java create mode 100644 common/proto/pom.xml rename common/{transport/transport-api/src/main/java/org/thingsboard/server/common/transport => proto/src/main/java/org/thingsboard/server/common}/adaptor/AdaptorException.java (90%) rename common/{transport/transport-api/src/main/java/org/thingsboard/server/common/transport => proto/src/main/java/org/thingsboard/server/common}/adaptor/JsonConverter.java (99%) rename common/{transport/transport-api/src/main/java/org/thingsboard/server/common/transport => proto/src/main/java/org/thingsboard/server/common}/adaptor/JsonConverterConfig.java (92%) rename common/{transport/transport-api/src/main/java/org/thingsboard/server/common/transport => proto/src/main/java/org/thingsboard/server/common}/adaptor/ProtoConverter.java (99%) rename {application/src/main/java/org/thingsboard/server/service/queue => common/proto/src/main/java/org/thingsboard/server/common/util}/ProtoUtils.java (95%) rename common/{cluster-api => proto}/src/main/proto/jsinvoke.proto (97%) rename common/{cluster-api => proto}/src/main/proto/queue.proto (98%) rename common/{transport/transport-api => proto}/src/main/proto/transport.proto (97%) rename common/{transport/transport-api/src/test/java => proto/src/test/java/org/thingsboard/server/common/adaptor}/JsonConverterTest.java (97%) rename {application/src/test/java/org/thingsboard/server/service/queue => common/proto/src/test/java/org/thingsboard/server/common/util}/ProtoUtilsTest.java (99%) create mode 100644 common/script/script-api/src/test/java/org/thingsboard/script/api/tbel/TbDateConstructorTest.java create mode 100644 common/stats/src/main/java/org/thingsboard/server/common/stats/FstStatsServiceImpl.java create mode 100644 common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/activity/AbstractActivityManager.java create mode 100644 common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/activity/ActivityManager.java create mode 100644 common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/activity/ActivityReportCallback.java create mode 100644 common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/activity/ActivityState.java create mode 100644 common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/activity/strategy/ActivityStrategy.java create mode 100644 common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/activity/strategy/ActivityStrategyType.java create mode 100644 common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/activity/strategy/AllEventsActivityStrategy.java create mode 100644 common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/activity/strategy/FirstAndLastEventActivityStrategy.java create mode 100644 common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/activity/strategy/FirstEventActivityStrategy.java create mode 100644 common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/activity/strategy/LastEventActivityStrategy.java create mode 100644 common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/limits/DefaultEntityLimitsCache.java create mode 100644 common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/limits/EntityLimitKey.java create mode 100644 common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/limits/EntityLimitsCache.java delete mode 100644 common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/SessionActivityData.java create mode 100644 common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/TransportActivityManager.java create mode 100644 common/transport/transport-api/src/test/java/org/thingsboard/server/common/transport/activity/strategy/ActivityStrategyTypeTest.java create mode 100644 common/transport/transport-api/src/test/java/org/thingsboard/server/common/transport/activity/strategy/AllEventsActivityStrategyTest.java create mode 100644 common/transport/transport-api/src/test/java/org/thingsboard/server/common/transport/activity/strategy/FirstAndLastEventActivityStrategyTest.java create mode 100644 common/transport/transport-api/src/test/java/org/thingsboard/server/common/transport/activity/strategy/FirstEventActivityStrategyTest.java create mode 100644 common/transport/transport-api/src/test/java/org/thingsboard/server/common/transport/activity/strategy/LastEventActivityStrategyTest.java create mode 100644 common/transport/transport-api/src/test/java/org/thingsboard/server/common/transport/service/TransportActivityManagerTest.java create mode 100644 common/util/src/main/java/org/thingsboard/common/util/ExecutorProvider.java create mode 100644 dao/src/main/java/org/thingsboard/server/dao/ImageContainerDao.java create mode 100644 dao/src/main/java/org/thingsboard/server/dao/exception/EntitiesLimitException.java create mode 100644 dao/src/main/java/org/thingsboard/server/dao/resource/BaseImageService.java create mode 100644 dao/src/main/java/org/thingsboard/server/dao/resource/ImageCacheKey.java create mode 100644 dao/src/main/java/org/thingsboard/server/dao/util/ImageUtils.java create mode 100644 dao/src/main/java/org/thingsboard/server/dao/util/JsonNodeProcessingTask.java create mode 100644 dao/src/main/java/org/thingsboard/server/dao/util/JsonPathProcessingTask.java create mode 100644 dao/src/main/java/org/thingsboard/server/dao/util/TimeUtils.java create mode 100644 dao/src/test/java/org/thingsboard/server/dao/util/DeviceConnectivityUtilTest.java create mode 100644 dao/src/test/java/org/thingsboard/server/dao/util/TimeUtilsTest.java create mode 100644 monitoring/src/main/resources/root_rule_chain.json create mode 100644 msa/black-box-tests/src/test/java/org/thingsboard/server/msa/rule/node/MqttNodeTest.java create mode 100644 msa/black-box-tests/src/test/resources/MqttRuleNodeTestMetadata.json create mode 100644 msa/black-box-tests/src/test/resources/docker-compose.mosquitto.yml create mode 100644 msa/black-box-tests/src/test/resources/mosquitto/mosquitto.conf create mode 100644 rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbAbstractTransformNodeWithTbMsgSource.java create mode 100644 rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/AbstractRuleNodeUpgradeTest.java create mode 100644 rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/debug/TbMsgGeneratorNodeTest.java create mode 100644 rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/flow/TbCheckpointNodeTest.java create mode 100644 ui-ngx/src/app/core/http/image.service.ts create mode 100644 ui-ngx/src/app/modules/home/components/widget/config/basic/chart/bar-chart-with-labels-basic-config.component.html create mode 100644 ui-ngx/src/app/modules/home/components/widget/config/basic/chart/bar-chart-with-labels-basic-config.component.ts create mode 100644 ui-ngx/src/app/modules/home/components/widget/config/basic/chart/range-chart-basic-config.component.html create mode 100644 ui-ngx/src/app/modules/home/components/widget/config/basic/chart/range-chart-basic-config.component.ts create mode 100644 ui-ngx/src/app/modules/home/components/widget/lib/chart/bar-chart-with-labels-widget.component.html create mode 100644 ui-ngx/src/app/modules/home/components/widget/lib/chart/bar-chart-with-labels-widget.component.scss create mode 100644 ui-ngx/src/app/modules/home/components/widget/lib/chart/bar-chart-with-labels-widget.component.ts create mode 100644 ui-ngx/src/app/modules/home/components/widget/lib/chart/bar-chart-with-labels-widget.models.ts create mode 100644 ui-ngx/src/app/modules/home/components/widget/lib/chart/echarts-widget.models.ts create mode 100644 ui-ngx/src/app/modules/home/components/widget/lib/chart/range-chart-widget.component.html create mode 100644 ui-ngx/src/app/modules/home/components/widget/lib/chart/range-chart-widget.component.scss create mode 100644 ui-ngx/src/app/modules/home/components/widget/lib/chart/range-chart-widget.component.ts create mode 100644 ui-ngx/src/app/modules/home/components/widget/lib/chart/range-chart-widget.models.ts create mode 100644 ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/bar-chart-with-labels-widget-settings.component.html create mode 100644 ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/bar-chart-with-labels-widget-settings.component.ts create mode 100644 ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/range-chart-widget-settings.component.html create mode 100644 ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/range-chart-widget-settings.component.ts rename ui-ngx/src/app/{modules/home/models/datasource => shared/components/grid}/scroll-grid-datasource.ts (92%) rename ui-ngx/src/app/{modules/home => shared}/components/grid/scroll-grid.component.html (80%) rename ui-ngx/src/app/{modules/home => shared}/components/grid/scroll-grid.component.scss (93%) rename ui-ngx/src/app/{modules/home => shared}/components/grid/scroll-grid.component.ts (54%) create mode 100644 ui-ngx/src/app/shared/components/image/embed-image-dialog.component.html create mode 100644 ui-ngx/src/app/shared/components/image/embed-image-dialog.component.scss create mode 100644 ui-ngx/src/app/shared/components/image/embed-image-dialog.component.ts create mode 100644 ui-ngx/src/app/shared/components/image/gallery-image-input.component.html create mode 100644 ui-ngx/src/app/shared/components/image/gallery-image-input.component.scss create mode 100644 ui-ngx/src/app/shared/components/image/gallery-image-input.component.ts create mode 100644 ui-ngx/src/app/shared/components/image/image-dialog.component.html create mode 100644 ui-ngx/src/app/shared/components/image/image-dialog.component.scss create mode 100644 ui-ngx/src/app/shared/components/image/image-dialog.component.ts create mode 100644 ui-ngx/src/app/shared/components/image/image-gallery-dialog.component.html create mode 100644 ui-ngx/src/app/shared/components/image/image-gallery-dialog.component.scss create mode 100644 ui-ngx/src/app/shared/components/image/image-gallery-dialog.component.ts create mode 100644 ui-ngx/src/app/shared/components/image/image-gallery.component.html create mode 100644 ui-ngx/src/app/shared/components/image/image-gallery.component.scss create mode 100644 ui-ngx/src/app/shared/components/image/image-gallery.component.ts create mode 100644 ui-ngx/src/app/shared/components/image/image-references.component.html create mode 100644 ui-ngx/src/app/shared/components/image/image-references.component.scss create mode 100644 ui-ngx/src/app/shared/components/image/image-references.component.ts create mode 100644 ui-ngx/src/app/shared/components/image/images-datasource.ts create mode 100644 ui-ngx/src/app/shared/components/image/images-in-use-dialog.component.html create mode 100644 ui-ngx/src/app/shared/components/image/images-in-use-dialog.component.scss create mode 100644 ui-ngx/src/app/shared/components/image/images-in-use-dialog.component.ts create mode 100644 ui-ngx/src/app/shared/components/image/multiple-gallery-image-input.component.html create mode 100644 ui-ngx/src/app/shared/components/image/multiple-gallery-image-input.component.scss create mode 100644 ui-ngx/src/app/shared/components/image/multiple-gallery-image-input.component.ts create mode 100644 ui-ngx/src/app/shared/components/image/upload-image-dialog.component.html create mode 100644 ui-ngx/src/app/shared/components/image/upload-image-dialog.component.ts rename ui-ngx/src/app/{modules/home/components => shared}/import-export/export-widgets-bundle-dialog.component.html (96%) rename ui-ngx/src/app/{modules/home/components => shared}/import-export/export-widgets-bundle-dialog.component.ts (89%) rename ui-ngx/src/app/{modules/home/components => shared}/import-export/import-dialog-csv.component.html (99%) rename ui-ngx/src/app/{modules/home/components => shared}/import-export/import-dialog-csv.component.scss (96%) rename ui-ngx/src/app/{modules/home/components => shared}/import-export/import-dialog-csv.component.ts (96%) rename ui-ngx/src/app/{modules/home/components => shared}/import-export/import-dialog.component.html (97%) rename ui-ngx/src/app/{modules/home/components => shared}/import-export/import-dialog.component.ts (98%) rename ui-ngx/src/app/{modules/home/components => shared}/import-export/import-export.models.ts (99%) rename ui-ngx/src/app/{modules/home/components => shared}/import-export/import-export.service.ts (85%) rename ui-ngx/src/app/{modules/home/components => shared}/import-export/table-columns-assignment.component.html (98%) rename ui-ngx/src/app/{modules/home/components => shared}/import-export/table-columns-assignment.component.scss (94%) rename ui-ngx/src/app/{modules/home/components => shared}/import-export/table-columns-assignment.component.ts (98%) delete mode 100644 ui-ngx/src/app/shared/models/websocket/notification-ws.models.ts create mode 100644 ui-ngx/src/app/shared/pipe/image.pipe.ts create mode 100644 ui-ngx/src/assets/help/en_US/rulenode/change_originator_node_fields_templatization.md create mode 100644 ui-ngx/src/assets/help/en_US/rulenode/to_email_node_fields_templatization.md create mode 100644 ui-ngx/src/assets/help/images/rulenode/examples/change-originator-ft-2.png create mode 100644 ui-ngx/src/assets/help/images/rulenode/examples/change-originator-ft-3.png create mode 100644 ui-ngx/src/assets/help/images/rulenode/examples/change-originator-ft.png create mode 100644 ui-ngx/src/assets/help/images/rulenode/examples/to-email-ft.png create mode 100644 ui-ngx/src/assets/locale/locale.constant-nl_BE.json delete mode 100644 ui-ngx/src/assets/locale/locale.constant-ru_RU.json diff --git a/.github/release.yml b/.github/release.yml index 1d760fe7bf..5e0ddc4300 100644 --- a/.github/release.yml +++ b/.github/release.yml @@ -1,5 +1,5 @@ # -# Copyright © 2016-2023 The Thingsboard Authors +# Copyright © 2016-2024 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. diff --git a/.github/workflows/check-configuration-files.yml b/.github/workflows/check-configuration-files.yml index 0b292ded79..94bfc85ce3 100644 --- a/.github/workflows/check-configuration-files.yml +++ b/.github/workflows/check-configuration-files.yml @@ -1,5 +1,5 @@ # -# Copyright © 2016-2023 The Thingsboard Authors +# Copyright © 2016-2024 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. diff --git a/application/pom.xml b/application/pom.xml index 9c30c4cb77..aaa8a1f447 100644 --- a/application/pom.xml +++ b/application/pom.xml @@ -1,6 +1,6 @@ + + 4.0.0 + + org.thingsboard + 3.6.3-SNAPSHOT + common + + org.thingsboard.common + proto + jar + + Thingsboard Server Common Protobuf and gRPC structures + https://thingsboard.io + + + UTF-8 + ${basedir}/../.. + + + + + org.thingsboard.common + data + + + org.thingsboard.common + message + + + com.google.protobuf + protobuf-java + + + com.google.protobuf + protobuf-java-util + + + org.springframework.boot + spring-boot-starter-web + provided + + + org.springframework.boot + spring-boot-starter-test + test + + + org.junit.vintage + junit-vintage-engine + test + + + org.awaitility + awaitility + test + + + + + + + org.xolstice.maven.plugins + protobuf-maven-plugin + + + + + + + thingsboard-repo-deploy + ThingsBoard Repo Deployment + https://repo.thingsboard.io/artifactory/libs-release-public + + + + \ No newline at end of file diff --git a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/adaptor/AdaptorException.java b/common/proto/src/main/java/org/thingsboard/server/common/adaptor/AdaptorException.java similarity index 90% rename from common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/adaptor/AdaptorException.java rename to common/proto/src/main/java/org/thingsboard/server/common/adaptor/AdaptorException.java index 8b2908a4b5..226ea644a6 100644 --- a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/adaptor/AdaptorException.java +++ b/common/proto/src/main/java/org/thingsboard/server/common/adaptor/AdaptorException.java @@ -1,5 +1,5 @@ /** - * Copyright © 2016-2023 The Thingsboard Authors + * Copyright © 2016-2024 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. @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.thingsboard.server.common.transport.adaptor; +package org.thingsboard.server.common.adaptor; public class AdaptorException extends Exception { diff --git a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/adaptor/JsonConverter.java b/common/proto/src/main/java/org/thingsboard/server/common/adaptor/JsonConverter.java similarity index 99% rename from common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/adaptor/JsonConverter.java rename to common/proto/src/main/java/org/thingsboard/server/common/adaptor/JsonConverter.java index 51e74d5097..42da1d740f 100644 --- a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/adaptor/JsonConverter.java +++ b/common/proto/src/main/java/org/thingsboard/server/common/adaptor/JsonConverter.java @@ -1,5 +1,5 @@ /** - * Copyright © 2016-2023 The Thingsboard Authors + * Copyright © 2016-2024 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. @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.thingsboard.server.common.transport.adaptor; +package org.thingsboard.server.common.adaptor; import com.google.gson.Gson; import com.google.gson.JsonArray; diff --git a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/adaptor/JsonConverterConfig.java b/common/proto/src/main/java/org/thingsboard/server/common/adaptor/JsonConverterConfig.java similarity index 92% rename from common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/adaptor/JsonConverterConfig.java rename to common/proto/src/main/java/org/thingsboard/server/common/adaptor/JsonConverterConfig.java index 0a9df150e5..335bf2265b 100644 --- a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/adaptor/JsonConverterConfig.java +++ b/common/proto/src/main/java/org/thingsboard/server/common/adaptor/JsonConverterConfig.java @@ -1,5 +1,5 @@ /** - * Copyright © 2016-2023 The Thingsboard Authors + * Copyright © 2016-2024 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. @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.thingsboard.server.common.transport.adaptor; +package org.thingsboard.server.common.adaptor; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; diff --git a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/adaptor/ProtoConverter.java b/common/proto/src/main/java/org/thingsboard/server/common/adaptor/ProtoConverter.java similarity index 99% rename from common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/adaptor/ProtoConverter.java rename to common/proto/src/main/java/org/thingsboard/server/common/adaptor/ProtoConverter.java index 54358709f0..b90b5f054f 100644 --- a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/adaptor/ProtoConverter.java +++ b/common/proto/src/main/java/org/thingsboard/server/common/adaptor/ProtoConverter.java @@ -1,5 +1,5 @@ /** - * Copyright © 2016-2023 The Thingsboard Authors + * Copyright © 2016-2024 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. @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.thingsboard.server.common.transport.adaptor; +package org.thingsboard.server.common.adaptor; import com.google.gson.Gson; import com.google.gson.JsonElement; diff --git a/application/src/main/java/org/thingsboard/server/service/queue/ProtoUtils.java b/common/proto/src/main/java/org/thingsboard/server/common/util/ProtoUtils.java similarity index 95% rename from application/src/main/java/org/thingsboard/server/service/queue/ProtoUtils.java rename to common/proto/src/main/java/org/thingsboard/server/common/util/ProtoUtils.java index 36038568bc..9daa9de9da 100644 --- a/application/src/main/java/org/thingsboard/server/service/queue/ProtoUtils.java +++ b/common/proto/src/main/java/org/thingsboard/server/common/util/ProtoUtils.java @@ -1,5 +1,5 @@ /** - * Copyright © 2016-2023 The Thingsboard Authors + * Copyright © 2016-2024 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. @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.thingsboard.server.service.queue; +package org.thingsboard.server.common.util; import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.id.DeviceId; @@ -46,6 +46,7 @@ import org.thingsboard.server.common.msg.rpc.ToDeviceRpcRequest; import org.thingsboard.server.common.msg.rpc.ToDeviceRpcRequestActorMsg; import org.thingsboard.server.common.msg.rule.engine.DeviceAttributesEventNotificationMsg; import org.thingsboard.server.common.msg.rule.engine.DeviceCredentialsUpdateNotificationMsg; +import org.thingsboard.server.common.msg.rule.engine.DeviceDeleteMsg; import org.thingsboard.server.common.msg.rule.engine.DeviceEdgeUpdateMsg; import org.thingsboard.server.common.msg.rule.engine.DeviceNameOrTypeUpdateMsg; import org.thingsboard.server.gen.transport.TransportProtos; @@ -384,6 +385,21 @@ public class ProtoUtils { ); } + private static TransportProtos.DeviceDeleteMsgProto toProto(DeviceDeleteMsg msg) { + return TransportProtos.DeviceDeleteMsgProto.newBuilder() + .setTenantIdMSB(msg.getTenantId().getId().getMostSignificantBits()) + .setTenantIdLSB(msg.getTenantId().getId().getLeastSignificantBits()) + .setDeviceIdMSB(msg.getDeviceId().getId().getMostSignificantBits()) + .setDeviceIdLSB(msg.getDeviceId().getId().getLeastSignificantBits()) + .build(); + } + + private static DeviceDeleteMsg fromProto(TransportProtos.DeviceDeleteMsgProto proto) { + return new DeviceDeleteMsg( + TenantId.fromUUID(new UUID(proto.getTenantIdMSB(), proto.getTenantIdLSB())), + new DeviceId(new UUID(proto.getDeviceIdMSB(), proto.getDeviceIdLSB()))); + } + public static TransportProtos.ToDeviceActorNotificationMsgProto toProto(ToDeviceActorNotificationMsg msg) { if (msg instanceof DeviceEdgeUpdateMsg) { DeviceEdgeUpdateMsg updateMsg = (DeviceEdgeUpdateMsg) msg; @@ -413,6 +429,10 @@ public class ProtoUtils { RemoveRpcActorMsg updateMsg = (RemoveRpcActorMsg) msg; TransportProtos.RemoveRpcActorMsgProto proto = toProto(updateMsg); return TransportProtos.ToDeviceActorNotificationMsgProto.newBuilder().setRemoveRpcActorMsg(proto).build(); + } else if (msg instanceof DeviceDeleteMsg) { + DeviceDeleteMsg updateMsg = (DeviceDeleteMsg) msg; + TransportProtos.DeviceDeleteMsgProto proto = toProto(updateMsg); + return TransportProtos.ToDeviceActorNotificationMsgProto.newBuilder().setDeviceDeleteMsg(proto).build(); } return null; } @@ -432,6 +452,8 @@ public class ProtoUtils { return fromProto(proto.getFromDeviceRpcResponseMsg()); } else if (proto.hasRemoveRpcActorMsg()) { return fromProto(proto.getRemoveRpcActorMsg()); + } else if (proto.hasDeviceDeleteMsg()) { + return fromProto(proto.getDeviceDeleteMsg()); } return null; } diff --git a/common/cluster-api/src/main/proto/jsinvoke.proto b/common/proto/src/main/proto/jsinvoke.proto similarity index 97% rename from common/cluster-api/src/main/proto/jsinvoke.proto rename to common/proto/src/main/proto/jsinvoke.proto index 14712bb384..c8ddc03e2b 100644 --- a/common/cluster-api/src/main/proto/jsinvoke.proto +++ b/common/proto/src/main/proto/jsinvoke.proto @@ -1,5 +1,5 @@ /** - * Copyright © 2016-2023 The Thingsboard Authors + * Copyright © 2016-2024 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. diff --git a/common/cluster-api/src/main/proto/queue.proto b/common/proto/src/main/proto/queue.proto similarity index 98% rename from common/cluster-api/src/main/proto/queue.proto rename to common/proto/src/main/proto/queue.proto index 016a40f5dc..4da2883291 100644 --- a/common/cluster-api/src/main/proto/queue.proto +++ b/common/proto/src/main/proto/queue.proto @@ -1,5 +1,5 @@ /** - * Copyright © 2016-2023 The Thingsboard Authors + * Copyright © 2016-2024 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. @@ -255,6 +255,12 @@ message GetOrCreateDeviceFromGatewayRequestMsg { message GetOrCreateDeviceFromGatewayResponseMsg { DeviceInfoProto deviceInfo = 1; bytes profileBody = 2; + TransportApiRequestErrorCode error = 3; +} + +enum TransportApiRequestErrorCode { + UNKNOWN_TRANSPORT_API_ERROR = 0; + ENTITY_LIMIT = 1; } message GetEntityProfileRequestMsg { @@ -300,6 +306,17 @@ message CoreStartupMsg { int64 ts = 3; } +message ResourceCacheInvalidateMsg { + int64 tenantIdMSB = 1; + int64 tenantIdLSB = 2; + repeated ImageCacheKeyProto keys = 3; +} + +message ImageCacheKeyProto { + optional string resourceKey = 1; + optional string publicResourceKey = 2; +} + message LwM2MRegistrationRequestMsg { string tenantId = 1; string endpoint = 2; @@ -1004,6 +1021,13 @@ message RemoveRpcActorMsgProto { int64 deviceIdLSB = 6; } +message DeviceDeleteMsgProto { + int64 tenantIdMSB = 1; + int64 tenantIdLSB = 2; + int64 deviceIdMSB = 3; + int64 deviceIdLSB = 4; +} + message ToDeviceActorNotificationMsgProto { DeviceEdgeUpdateMsgProto deviceEdgeUpdateMsg = 1; DeviceNameOrTypeUpdateMsgProto deviceNameOrTypeMsg = 2; @@ -1012,6 +1036,7 @@ message ToDeviceActorNotificationMsgProto { ToDeviceRpcRequestActorMsgProto toDeviceRpcRequestMsg = 5; FromDeviceRpcResponseActorMsgProto fromDeviceRpcResponseMsg = 6; RemoveRpcActorMsgProto removeRpcActorMsg = 7; + DeviceDeleteMsgProto deviceDeleteMsg = 8; } /** @@ -1267,6 +1292,7 @@ message ToCoreNotificationMsg { EdgeEventUpdateMsgProto edgeEventUpdate = 14; ToEdgeSyncRequestMsgProto toEdgeSyncRequest = 15; FromEdgeSyncResponseMsgProto fromEdgeSyncResponse = 16; + ResourceCacheInvalidateMsg resourceCacheInvalidateMsg = 17; } /* Messages that are handled by ThingsBoard RuleEngine Service */ diff --git a/common/transport/transport-api/src/main/proto/transport.proto b/common/proto/src/main/proto/transport.proto similarity index 97% rename from common/transport/transport-api/src/main/proto/transport.proto rename to common/proto/src/main/proto/transport.proto index 12c7f3e8c6..b3faf24539 100644 --- a/common/transport/transport-api/src/main/proto/transport.proto +++ b/common/proto/src/main/proto/transport.proto @@ -1,5 +1,5 @@ /** - * Copyright © 2016-2023 The Thingsboard Authors + * Copyright © 2016-2024 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. diff --git a/common/transport/transport-api/src/test/java/JsonConverterTest.java b/common/proto/src/test/java/org/thingsboard/server/common/adaptor/JsonConverterTest.java similarity index 97% rename from common/transport/transport-api/src/test/java/JsonConverterTest.java rename to common/proto/src/test/java/org/thingsboard/server/common/adaptor/JsonConverterTest.java index 39ed04a29a..773ebbea3d 100644 --- a/common/transport/transport-api/src/test/java/JsonConverterTest.java +++ b/common/proto/src/test/java/org/thingsboard/server/common/adaptor/JsonConverterTest.java @@ -1,5 +1,5 @@ /** - * Copyright © 2016-2023 The Thingsboard Authors + * Copyright © 2016-2024 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. @@ -13,13 +13,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +package org.thingsboard.server.common.adaptor; + import com.google.gson.JsonParser; import com.google.gson.JsonSyntaxException; import org.junit.Assert; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.thingsboard.server.common.transport.adaptor.JsonConverter; import java.util.ArrayList; diff --git a/application/src/test/java/org/thingsboard/server/service/queue/ProtoUtilsTest.java b/common/proto/src/test/java/org/thingsboard/server/common/util/ProtoUtilsTest.java similarity index 99% rename from application/src/test/java/org/thingsboard/server/service/queue/ProtoUtilsTest.java rename to common/proto/src/test/java/org/thingsboard/server/common/util/ProtoUtilsTest.java index 1a696b730d..4bb98f6cd2 100644 --- a/application/src/test/java/org/thingsboard/server/service/queue/ProtoUtilsTest.java +++ b/common/proto/src/test/java/org/thingsboard/server/common/util/ProtoUtilsTest.java @@ -1,5 +1,5 @@ /** - * Copyright © 2016-2023 The Thingsboard Authors + * Copyright © 2016-2024 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. @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.thingsboard.server.service.queue; +package org.thingsboard.server.common.util; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; diff --git a/common/queue/pom.xml b/common/queue/pom.xml index 32d740812d..1eb4dd6ce8 100644 --- a/common/queue/pom.xml +++ b/common/queue/pom.xml @@ -1,6 +1,6 @@ - diff --git a/ui-ngx/src/app/modules/home/components/alarm/alarm-assignee.component.scss b/ui-ngx/src/app/modules/home/components/alarm/alarm-assignee.component.scss index 3aed0ccb5e..505db79a36 100644 --- a/ui-ngx/src/app/modules/home/components/alarm/alarm-assignee.component.scss +++ b/ui-ngx/src/app/modules/home/components/alarm/alarm-assignee.component.scss @@ -1,5 +1,5 @@ /** - * Copyright © 2016-2023 The Thingsboard Authors + * Copyright © 2016-2024 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. @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - .user-avatar { display: inline-flex; justify-content: center; diff --git a/ui-ngx/src/app/modules/home/components/alarm/alarm-assignee.component.ts b/ui-ngx/src/app/modules/home/components/alarm/alarm-assignee.component.ts index 1fb1d3f689..0fc489fbfe 100644 --- a/ui-ngx/src/app/modules/home/components/alarm/alarm-assignee.component.ts +++ b/ui-ngx/src/app/modules/home/components/alarm/alarm-assignee.component.ts @@ -1,5 +1,5 @@ /// -/// Copyright © 2016-2023 The Thingsboard Authors +/// Copyright © 2016-2024 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. diff --git a/ui-ngx/src/app/modules/home/components/alarm/alarm-comment-dialog.component.html b/ui-ngx/src/app/modules/home/components/alarm/alarm-comment-dialog.component.html index 8618592ae0..8145c31b06 100644 --- a/ui-ngx/src/app/modules/home/components/alarm/alarm-comment-dialog.component.html +++ b/ui-ngx/src/app/modules/home/components/alarm/alarm-comment-dialog.component.html @@ -1,6 +1,6 @@ -
- + {{ getSortDirectionIcon() }} + +
- - - - - Windows - - - - - - - - - - Linux - - - - - - - - - - MacOS - - - - - - - -
- -
-
device.connectivity.execute-following-command
+
+
gateway.launch-gateway
+
gateway.launch-docker-compose
- +
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/device-gateway-command.component.scss b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/device-gateway-command.component.scss index befa034375..6a1ea79a80 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/device-gateway-command.component.scss +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/device-gateway-command.component.scss @@ -1,5 +1,5 @@ /** - * Copyright © 2016-2023 The Thingsboard Authors + * Copyright © 2016-2024 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. @@ -14,28 +14,35 @@ * limitations under the License. */ :host { - width: 100%; - height: 100%; - display: block; + .tb-commands-hint { + color: inherit; + font-weight: normal; + flex: 1; + } } :host ::ng-deep { .tb-markdown-view { .start-code { - code[class*="language-"] { - white-space: break-spaces; - word-break: break-all; - } - pre[class*="language-"] { - overflow: hidden; - background: #F3F6FA; - border-color: #305680; - } .code-wrapper { padding: 0; + + pre[class*=language-] { + margin: 0; + background: #F3F6FA; + border-color: #305680; + padding-right: 38px; + overflow: scroll; + padding-bottom: 4px; + + &::-webkit-scrollbar { + width: 4px; + height: 4px; + } + } } button.clipboard-btn { - right: 0; + right: -2px; p { color: #305680; } @@ -60,9 +67,5 @@ } } } - - .tb-form-panel.tb-tab-body { - margin-top: 16px; - } } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/device-gateway-command.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/device-gateway-command.component.ts index d5516dd59b..8465b5879d 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/device-gateway-command.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/device-gateway-command.component.ts @@ -1,5 +1,5 @@ /// -/// Copyright © 2016-2023 The Thingsboard Authors +/// Copyright © 2016-2024 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. @@ -14,11 +14,8 @@ /// limitations under the License. /// -import { ChangeDetectorRef, Component, Input, OnInit } from '@angular/core'; +import { Component, Input } from '@angular/core'; import { DeviceService } from '@core/http/device.service'; -import { helpBaseUrl } from '@shared/models/constants'; -import { getOS } from '@core/utils'; -import { PublishLaunchCommand } from '@shared/models/device.models'; @Component({ selector: 'tb-gateway-command', @@ -26,47 +23,20 @@ import { PublishLaunchCommand } from '@shared/models/device.models'; styleUrls: ['./device-gateway-command.component.scss'] }) -export class DeviceGatewayCommandComponent implements OnInit { - - @Input() - token: string; +export class DeviceGatewayCommandComponent { @Input() deviceId: string; - commands: PublishLaunchCommand; - - helpLink: string = helpBaseUrl + '/docs/iot-gateway/install/docker-installation/'; - - tabIndex = 0; - - constructor(private cd: ChangeDetectorRef, - private deviceService: DeviceService) { + constructor(private deviceService: DeviceService) { } - - ngOnInit(): void { - if (this.deviceId) { - this.deviceService.getDevicePublishLaunchCommands(this.deviceId).subscribe(commands => { - this.commands = commands; - this.cd.detectChanges(); - }); + download($event: Event) { + if ($event) { + $event.stopPropagation(); } - const currentOS = getOS(); - switch (currentOS) { - case 'linux': - case 'android': - this.tabIndex = 1; - break; - case 'macos': - case 'ios': - this.tabIndex = 2; - break; - case 'windows': - this.tabIndex = 0; - break; - default: - this.tabIndex = 1; + if (this.deviceId) { + this.deviceService.downloadGatewayDockerComposeFile(this.deviceId).subscribe(() => {}); } } } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-configuration.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-configuration.component.html index 7ddf0c8cd9..153b6b0e14 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-configuration.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-configuration.component.html @@ -1,6 +1,6 @@ -
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-statistics.component.scss b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-statistics.component.scss index e704120560..cd7722d12d 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-statistics.component.scss +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-statistics.component.scss @@ -1,5 +1,5 @@ /** - * Copyright © 2016-2023 The Thingsboard Authors + * Copyright © 2016-2024 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. diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-statistics.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-statistics.component.ts index 503f5643bf..a3cb79e125 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-statistics.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-statistics.component.ts @@ -1,5 +1,5 @@ /// -/// Copyright © 2016-2023 The Thingsboard Authors +/// Copyright © 2016-2024 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. diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-widget.models.ts b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-widget.models.ts index 1d1c280053..e75bf97d23 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-widget.models.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-widget.models.ts @@ -1,5 +1,5 @@ /// -/// Copyright © 2016-2023 The Thingsboard Authors +/// Copyright © 2016-2024 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. diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/home-page/add-doc-link-dialog.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/home-page/add-doc-link-dialog.component.html index 1eaf791577..7f86897f7e 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/home-page/add-doc-link-dialog.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/home-page/add-doc-link-dialog.component.html @@ -1,6 +1,6 @@ -
+
@@ -25,7 +25,7 @@
+ [style.background-size]="vertical ? '100% ' + (batteryFillValue + 1) + '%' : (batteryFillValue + 1) + '% 100%'">
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/indicator/battery-level-widget.component.scss b/ui-ngx/src/app/modules/home/components/widget/lib/indicator/battery-level-widget.component.scss index fbf244a383..444417fb09 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/indicator/battery-level-widget.component.scss +++ b/ui-ngx/src/app/modules/home/components/widget/lib/indicator/battery-level-widget.component.scss @@ -1,5 +1,5 @@ /** - * Copyright © 2016-2023 The Thingsboard Authors + * Copyright © 2016-2024 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. diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/indicator/battery-level-widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/indicator/battery-level-widget.component.ts index 31f98aff6c..5251a0c602 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/indicator/battery-level-widget.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/indicator/battery-level-widget.component.ts @@ -1,5 +1,5 @@ /// -/// Copyright © 2016-2023 The Thingsboard Authors +/// Copyright © 2016-2024 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. @@ -46,6 +46,9 @@ import { BatteryLevelWidgetSettings } from '@home/components/widget/lib/indicator/battery-level-widget.models'; import { ResizeObserver } from '@juggle/resize-observer'; +import { Observable } from 'rxjs'; +import { ImagePipe } from '@shared/pipe/image.pipe'; +import { DomSanitizer } from '@angular/platform-browser'; const verticalBatteryDimensions = { shapeAspectRatio: 64 / 113, @@ -117,6 +120,8 @@ export class BatteryLevelWidgetComponent implements OnInit, OnDestroy, AfterView value: number; + batteryFillValue: number; + batterySections: boolean[]; dividedBorderRadius: string; dividedGap: string; @@ -125,7 +130,7 @@ export class BatteryLevelWidgetComponent implements OnInit, OnDestroy, AfterView batteryShapeColor: ColorProcessor; - backgroundStyle: ComponentStyle = {}; + backgroundStyle$: Observable; overlayStyle: ComponentStyle = {}; batteryBoxResize$: ResizeObserver; @@ -136,6 +141,8 @@ export class BatteryLevelWidgetComponent implements OnInit, OnDestroy, AfterView private units = ''; constructor(private date: DatePipe, + private imagePipe: ImagePipe, + private sanitizer: DomSanitizer, private widgetComponent: WidgetComponent, private renderer: Renderer2, private cd: ChangeDetectorRef) { @@ -190,7 +197,7 @@ export class BatteryLevelWidgetComponent implements OnInit, OnDestroy, AfterView this.batteryShapeColor = ColorProcessor.fromSettings(this.settings.batteryShapeColor); - this.backgroundStyle = backgroundStyle(this.settings.background); + this.backgroundStyle$ = backgroundStyle(this.settings.background, this.imagePipe, this.sanitizer); this.overlayStyle = overlayStyle(this.settings.background.overlay); this.hasCardClickAction = this.ctx.actionsApi.getActionDescriptors('cardClick').length > 0; @@ -221,9 +228,10 @@ export class BatteryLevelWidgetComponent implements OnInit, OnDestroy, AfterView public onDataUpdated() { const tsValue = getSingleTsValue(this.ctx.data); - this.value = 0; + this.batteryFillValue = 0; if (tsValue && isDefinedAndNotNull(tsValue[1]) && isNumeric(tsValue[1])) { this.value = tsValue[1]; + this.batteryFillValue = this.parseBatteryFillValue(this.value); this.valueText = formatValue(this.value, this.decimals, this.units, false); } else { this.valueText = 'N/A'; @@ -240,6 +248,16 @@ export class BatteryLevelWidgetComponent implements OnInit, OnDestroy, AfterView this.cd.detectChanges(); } + parseBatteryFillValue(value: number) { + if (value < 0) { + return 0; + } else if (value > 100) { + return 100; + } else { + return value; + } + } + public trackBySection(index: number): number { return index; } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/indicator/battery-level-widget.models.ts b/ui-ngx/src/app/modules/home/components/widget/lib/indicator/battery-level-widget.models.ts index 34c00a4b92..081aae6558 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/indicator/battery-level-widget.models.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/indicator/battery-level-widget.models.ts @@ -1,5 +1,5 @@ /// -/// Copyright © 2016-2023 The Thingsboard Authors +/// Copyright © 2016-2024 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. @@ -78,22 +78,22 @@ export const batteryLevelDefaultSettings: BatteryLevelWidgetSettings = { }, valueColor: constantColor('rgba(0, 0, 0, 0.87)'), batteryLevelColor: { - color: 'rgba(92, 223, 144, 1)', + color: 'rgba(224, 224, 224, 1)', type: ColorType.range, rangeList: [ - {from: 0, to: 25, color: 'rgba(227, 71, 71, 1)'}, + {from: null, to: 25, color: 'rgba(227, 71, 71, 1)'}, {from: 25, to: 50, color: 'rgba(246, 206, 67, 1)'}, - {from: 50, to: 100, color: 'rgba(92, 223, 144, 1)'} + {from: 50, to: null, color: 'rgba(92, 223, 144, 1)'} ], colorFunction: defaultColorFunction }, batteryShapeColor: { - color: 'rgba(92, 223, 144, 0.32)', + color: 'rgba(224, 224, 224, 0.32)', type: ColorType.range, rangeList: [ - {from: 0, to: 25, color: 'rgba(227, 71, 71, 0.32)'}, + {from: null, to: 25, color: 'rgba(227, 71, 71, 0.32)'}, {from: 25, to: 50, color: 'rgba(246, 206, 67, 0.32)'}, - {from: 50, to: 100, color: 'rgba(92, 223, 144, 0.32)'} + {from: 50, to: null, color: 'rgba(92, 223, 144, 0.32)'} ], colorFunction: defaultColorFunction }, diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/indicator/liquid-level-widget.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/indicator/liquid-level-widget.component.html index 4c14686b9c..5c247ca794 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/indicator/liquid-level-widget.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/indicator/liquid-level-widget.component.html @@ -1,6 +1,6 @@ -
+
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/indicator/liquid-level-widget.component.scss b/ui-ngx/src/app/modules/home/components/widget/lib/indicator/liquid-level-widget.component.scss index 046d1a7d3e..360a75f54c 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/indicator/liquid-level-widget.component.scss +++ b/ui-ngx/src/app/modules/home/components/widget/lib/indicator/liquid-level-widget.component.scss @@ -1,5 +1,5 @@ /** - * Copyright © 2016-2023 The Thingsboard Authors + * Copyright © 2016-2024 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. diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/indicator/liquid-level-widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/indicator/liquid-level-widget.component.ts index 847937581b..3c79883bf3 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/indicator/liquid-level-widget.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/indicator/liquid-level-widget.component.ts @@ -1,5 +1,5 @@ /// -/// Copyright © 2016-2023 The Thingsboard Authors +/// Copyright © 2016-2024 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. @@ -58,6 +58,9 @@ import { ResourcesService } from '@core/services/resources.service'; import { NULL_UUID } from '@shared/models/id/has-uuid'; import { TranslateService } from '@ngx-translate/core'; import ITooltipsterInstance = JQueryTooltipster.ITooltipsterInstance; +import { ImagePipe } from '@shared/pipe/image.pipe'; +import { DomSanitizer } from '@angular/platform-browser'; +import { DataEntry } from '@shared/models/widget.models'; @Component({ selector: 'tb-liquid-level-widget', @@ -76,7 +79,7 @@ export class LiquidLevelWidgetComponent implements OnInit { @Input() widgetTitlePanel: TemplateRef; - backgroundStyle: ComponentStyle = {}; + backgroundStyle$: Observable; overlayStyle: ComponentStyle = {}; hasCardClickAction = false; @@ -106,7 +109,9 @@ export class LiquidLevelWidgetComponent implements OnInit { private capacityUnits = Object.values(CapacityUnits); - constructor(private cd: ChangeDetectorRef, + constructor(private imagePipe: ImagePipe, + private sanitizer: DomSanitizer, + private cd: ChangeDetectorRef, private resourcesService: ResourcesService, private translate: TranslateService) { } @@ -116,7 +121,7 @@ export class LiquidLevelWidgetComponent implements OnInit { this.settings = {...levelCardDefaultSettings, ...this.ctx.settings}; this.declareStyles(); - this.backgroundStyle = backgroundStyle(this.settings.background); + this.backgroundStyle$ = backgroundStyle(this.settings.background, this.imagePipe, this.sanitizer); this.overlayStyle = overlayStyle(this.settings.background.overlay); this.hasCardClickAction = this.ctx.actionsApi.getActionDescriptors('cardClick').length > 0; @@ -395,7 +400,7 @@ export class LiquidLevelWidgetComponent implements OnInit { return limits.min + (percentage / 100) * (limits.max - limits.min); } - private updateTooltip(value: [number, any]): void { + private updateTooltip(value: DataEntry): void { this.tooltipContent = this.getTooltipContent(value); if (this.tooltip) { @@ -490,7 +495,7 @@ export class LiquidLevelWidgetComponent implements OnInit { } } - private getTooltipContent(value?: [number, any]): string { + private getTooltipContent(value?: DataEntry): string { const contentValue = value || [0, '']; let tooltipValue: string | number = 'N/A'; diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/indicator/liquid-level-widget.models.ts b/ui-ngx/src/app/modules/home/components/widget/lib/indicator/liquid-level-widget.models.ts index cf526d6c97..954e228e79 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/indicator/liquid-level-widget.models.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/indicator/liquid-level-widget.models.ts @@ -1,5 +1,5 @@ /// -/// Copyright © 2016-2023 The Thingsboard Authors +/// Copyright © 2016-2024 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. @@ -418,7 +418,7 @@ export const createAbsoluteLayout = (values?: {inputValue: number | string; volu export const createPercentLayout = (value: number | string = 50, valueTextStyle: string = valueTextStyleDefaults): string => `
- +
`; export const optionsFilter = (searchText: string): ((key: DataKey) => boolean) => diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/indicator/signal-strength-widget.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/indicator/signal-strength-widget.component.html index a2bf74e942..79f95c52d3 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/indicator/signal-strength-widget.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/indicator/signal-strength-widget.component.html @@ -1,6 +1,6 @@ -
+
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/indicator/signal-strength-widget.component.scss b/ui-ngx/src/app/modules/home/components/widget/lib/indicator/signal-strength-widget.component.scss index c2c14ffb76..3af5baa58b 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/indicator/signal-strength-widget.component.scss +++ b/ui-ngx/src/app/modules/home/components/widget/lib/indicator/signal-strength-widget.component.scss @@ -1,5 +1,5 @@ /** - * Copyright © 2016-2023 The Thingsboard Authors + * Copyright © 2016-2024 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. diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/indicator/signal-strength-widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/indicator/signal-strength-widget.component.ts index 8427cf362b..bee975bd1f 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/indicator/signal-strength-widget.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/indicator/signal-strength-widget.component.ts @@ -1,3 +1,19 @@ +/// +/// Copyright © 2016-2024 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. +/// + /// /// Copyright © 2016-2023 The Thingsboard Authors @@ -51,6 +67,9 @@ import { } from '@home/components/widget/lib/indicator/signal-strength-widget.models'; import tinycolor from 'tinycolor2'; import { TranslateService } from '@ngx-translate/core'; +import { Observable } from 'rxjs'; +import { ImagePipe } from '@shared/pipe/image.pipe'; +import { DomSanitizer } from '@angular/platform-browser'; const shapeWidth = 149; const shapeHeight = 113; @@ -104,7 +123,7 @@ export class SignalStrengthWidgetComponent implements OnInit, OnDestroy, AfterVi }; tooltipDateStyle: ComponentStyle = {}; - backgroundStyle: ComponentStyle = {}; + backgroundStyle$: Observable; overlayStyle: ComponentStyle = {}; shapeResize$: ResizeObserver; @@ -128,6 +147,8 @@ export class SignalStrengthWidgetComponent implements OnInit, OnDestroy, AfterVi private noData = false; constructor(public widgetComponent: WidgetComponent, + private imagePipe: ImagePipe, + private sanitizer: DomSanitizer, private translate: TranslateService, private renderer: Renderer2, private cd: ChangeDetectorRef) { @@ -186,7 +207,7 @@ export class SignalStrengthWidgetComponent implements OnInit, OnDestroy, AfterVi this.tooltipDateLabelStyle = {...this.tooltipDateStyle, ...this.tooltipDateLabelStyle}; } - this.backgroundStyle = backgroundStyle(this.settings.background); + this.backgroundStyle$ = backgroundStyle(this.settings.background, this.imagePipe, this.sanitizer); this.overlayStyle = overlayStyle(this.settings.background.overlay); this.hasCardClickAction = this.ctx.actionsApi.getActionDescriptors('cardClick').length > 0; diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/indicator/signal-strength-widget.models.ts b/ui-ngx/src/app/modules/home/components/widget/lib/indicator/signal-strength-widget.models.ts index 59c782f5d4..144d9e891b 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/indicator/signal-strength-widget.models.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/indicator/signal-strength-widget.models.ts @@ -1,5 +1,5 @@ /// -/// Copyright © 2016-2023 The Thingsboard Authors +/// Copyright © 2016-2024 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. diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/json-input-widget.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/json-input-widget.component.html index 40636a9d1b..b24ad37ede 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/json-input-widget.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/json-input-widget.component.html @@ -1,6 +1,6 @@
- - +
widgets.label-widget.labels
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/label-widget-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/label-widget-settings.component.ts index 191586b683..ff38162bbe 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/label-widget-settings.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/label-widget-settings.component.ts @@ -1,5 +1,5 @@ /// -/// Copyright © 2016-2023 The Thingsboard Authors +/// Copyright © 2016-2024 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. diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/markdown-widget-settings.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/markdown-widget-settings.component.html index cf5415afe0..e33529a179 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/markdown-widget-settings.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/markdown-widget-settings.component.html @@ -1,6 +1,6 @@ + +
+
widgets.bar-chart.bar-chart-card-style
+
+ + {{ 'widgets.bar-chart.label-on-bar' | translate }} + +
+ + + + +
+
+
+ + {{ 'widgets.bar-chart.value-on-bar' | translate }} + +
+ + + + +
+
+
+ + + + + {{ 'widget-config.legend' | translate }} + + + + +
+
{{ 'legend.position' | translate }}
+ + + + {{ legendPositionTranslationMap.get(pos) | translate }} + + + +
+
+
{{ 'legend.label' | translate }}
+
+ + + + +
+
+
+
+
+
+ + + + + {{ 'widget-config.tooltip' | translate }} + + + + +
+
{{ 'tooltip.value' | translate }}
+
+ + + + +
+
+
+ + {{ 'tooltip.date' | translate }} + +
+ + + + + +
+
+
+
{{ 'tooltip.background-color' | translate }}
+ + +
+
+
{{ 'tooltip.background-blur' | translate }}
+ + +
px
+
+
+
+
+
+
+
{{ 'widgets.background.background' | translate }}
+ + +
+
+
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/bar-chart-with-labels-widget-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/bar-chart-with-labels-widget-settings.component.ts new file mode 100644 index 0000000000..0d547922eb --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/bar-chart-with-labels-widget-settings.component.ts @@ -0,0 +1,170 @@ +/// +/// Copyright © 2016-2024 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, Injector } from '@angular/core'; +import { + legendPositions, + legendPositionTranslationMap, + WidgetSettings, + WidgetSettingsComponent +} from '@shared/models/widget.models'; +import { UntypedFormBuilder, UntypedFormGroup } from '@angular/forms'; +import { Store } from '@ngrx/store'; +import { AppState } from '@core/core.state'; +import { formatValue } from '@core/utils'; +import { DateFormatProcessor, DateFormatSettings } from '@shared/models/widget-settings.models'; +import { + barChartWithLabelsDefaultSettings +} from '@home/components/widget/lib/chart/bar-chart-with-labels-widget.models'; + +@Component({ + selector: 'tb-bar-chart-with-labels-widget-settings', + templateUrl: './bar-chart-with-labels-widget-settings.component.html', + styleUrls: [] +}) +export class BarChartWithLabelsWidgetSettingsComponent extends WidgetSettingsComponent { + + legendPositions = legendPositions; + + legendPositionTranslationMap = legendPositionTranslationMap; + + barChartWidgetSettingsForm: UntypedFormGroup; + + tooltipValuePreviewFn = this._tooltipValuePreviewFn.bind(this); + + tooltipDatePreviewFn = this._tooltipDatePreviewFn.bind(this); + + constructor(protected store: Store, + private $injector: Injector, + private fb: UntypedFormBuilder) { + super(store); + } + + protected settingsForm(): UntypedFormGroup { + return this.barChartWidgetSettingsForm; + } + + protected defaultSettings(): WidgetSettings { + return {...barChartWithLabelsDefaultSettings}; + } + + protected onSettingsSet(settings: WidgetSettings) { + this.barChartWidgetSettingsForm = this.fb.group({ + + showBarLabel: [settings.showBarLabel, []], + barLabelFont: [settings.barLabelFont, []], + barLabelColor: [settings.barLabelColor, []], + showBarValue: [settings.showBarValue, []], + barValueFont: [settings.barValueFont, []], + barValueColor: [settings.barValueColor, []], + + showLegend: [settings.showLegend, []], + legendPosition: [settings.legendPosition, []], + legendLabelFont: [settings.legendLabelFont, []], + legendLabelColor: [settings.legendLabelColor, []], + + showTooltip: [settings.showTooltip, []], + tooltipValueFont: [settings.tooltipValueFont, []], + tooltipValueColor: [settings.tooltipValueColor, []], + tooltipShowDate: [settings.tooltipShowDate, []], + tooltipDateFormat: [settings.tooltipDateFormat, []], + tooltipDateFont: [settings.tooltipDateFont, []], + tooltipDateColor: [settings.tooltipDateColor, []], + tooltipBackgroundColor: [settings.tooltipBackgroundColor, []], + tooltipBackgroundBlur: [settings.tooltipBackgroundBlur, []], + + background: [settings.background, []] + }); + } + + protected validatorTriggers(): string[] { + return ['showBarLabel', 'showBarValue', 'showLegend', 'showTooltip', 'tooltipShowDate']; + } + + protected updateValidators(emitEvent: boolean) { + const showBarLabel: boolean = this.barChartWidgetSettingsForm.get('showBarLabel').value; + const showBarValue: boolean = this.barChartWidgetSettingsForm.get('showBarValue').value; + const showLegend: boolean = this.barChartWidgetSettingsForm.get('showLegend').value; + const showTooltip: boolean = this.barChartWidgetSettingsForm.get('showTooltip').value; + const tooltipShowDate: boolean = this.barChartWidgetSettingsForm.get('tooltipShowDate').value; + + if (showBarLabel) { + this.barChartWidgetSettingsForm.get('barLabelFont').enable(); + this.barChartWidgetSettingsForm.get('barLabelColor').enable(); + } else { + this.barChartWidgetSettingsForm.get('barLabelFont').disable(); + this.barChartWidgetSettingsForm.get('barLabelColor').disable(); + } + + if (showBarValue) { + this.barChartWidgetSettingsForm.get('barValueFont').enable(); + this.barChartWidgetSettingsForm.get('barValueColor').enable(); + } else { + this.barChartWidgetSettingsForm.get('barValueFont').disable(); + this.barChartWidgetSettingsForm.get('barValueColor').disable(); + } + + if (showLegend) { + this.barChartWidgetSettingsForm.get('legendPosition').enable(); + this.barChartWidgetSettingsForm.get('legendLabelFont').enable(); + this.barChartWidgetSettingsForm.get('legendLabelColor').enable(); + } else { + this.barChartWidgetSettingsForm.get('legendPosition').disable(); + this.barChartWidgetSettingsForm.get('legendLabelFont').disable(); + this.barChartWidgetSettingsForm.get('legendLabelColor').disable(); + } + + if (showTooltip) { + this.barChartWidgetSettingsForm.get('tooltipValueFont').enable(); + this.barChartWidgetSettingsForm.get('tooltipValueColor').enable(); + this.barChartWidgetSettingsForm.get('tooltipShowDate').enable({emitEvent: false}); + this.barChartWidgetSettingsForm.get('tooltipBackgroundColor').enable(); + this.barChartWidgetSettingsForm.get('tooltipBackgroundBlur').enable(); + if (tooltipShowDate) { + this.barChartWidgetSettingsForm.get('tooltipDateFormat').enable(); + this.barChartWidgetSettingsForm.get('tooltipDateFont').enable(); + this.barChartWidgetSettingsForm.get('tooltipDateColor').enable(); + } else { + this.barChartWidgetSettingsForm.get('tooltipDateFormat').disable(); + this.barChartWidgetSettingsForm.get('tooltipDateFont').disable(); + this.barChartWidgetSettingsForm.get('tooltipDateColor').disable(); + } + } else { + this.barChartWidgetSettingsForm.get('tooltipValueFont').disable(); + this.barChartWidgetSettingsForm.get('tooltipValueColor').disable(); + this.barChartWidgetSettingsForm.get('tooltipShowDate').disable({emitEvent: false}); + this.barChartWidgetSettingsForm.get('tooltipDateFormat').disable(); + this.barChartWidgetSettingsForm.get('tooltipDateFont').disable(); + this.barChartWidgetSettingsForm.get('tooltipDateColor').disable(); + this.barChartWidgetSettingsForm.get('tooltipBackgroundColor').disable(); + this.barChartWidgetSettingsForm.get('tooltipBackgroundBlur').disable(); + } + } + + private _tooltipValuePreviewFn(): string { + const units: string = this.widgetConfig.config.units; + const decimals: number = this.widgetConfig.config.decimals; + return formatValue(22, decimals, units, false); + } + + private _tooltipDatePreviewFn(): string { + const dateFormat: DateFormatSettings = this.barChartWidgetSettingsForm.get('tooltipDateFormat').value; + const processor = DateFormatProcessor.fromSettings(this.$injector, dateFormat); + processor.update(Date.now()); + return processor.formatted; + } + +} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/chart-widget-settings.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/chart-widget-settings.component.html index d30182f73d..3922858711 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/chart-widget-settings.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/chart-widget-settings.component.html @@ -1,6 +1,6 @@ + +
+
widgets.range-chart.range-chart-card-style
+
+ + {{ 'widgets.range-chart.data-zoom' | translate }} + +
+
+
{{ 'widgets.range-chart.range-colors' | translate }}
+ + +
+
+
{{ 'widgets.range-chart.out-of-range-color' | translate }}
+ + +
+
+ + {{ 'widgets.range-chart.fill-area' | translate }} + +
+
+ + + + + {{ 'widget-config.legend' | translate }} + + + + +
+
{{ 'legend.position' | translate }}
+ + + + {{ legendPositionTranslationMap.get(pos) | translate }} + + + +
+
+
{{ 'legend.label' | translate }}
+
+ + + + +
+
+
+
+
+
+ + + + + {{ 'widget-config.tooltip' | translate }} + + + + +
+
{{ 'tooltip.value' | translate }}
+
+ + + + +
+
+
+ + {{ 'tooltip.date' | translate }} + +
+ + + + + +
+
+
+
{{ 'tooltip.background-color' | translate }}
+ + +
+
+
{{ 'tooltip.background-blur' | translate }}
+ + +
px
+
+
+
+
+
+
+
{{ 'widgets.background.background' | translate }}
+ + +
+
+
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/range-chart-widget-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/range-chart-widget-settings.component.ts new file mode 100644 index 0000000000..c0e043995d --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/range-chart-widget-settings.component.ts @@ -0,0 +1,147 @@ +/// +/// Copyright © 2016-2024 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, Injector } from '@angular/core'; +import { + legendPositions, + legendPositionTranslationMap, + WidgetSettings, + WidgetSettingsComponent +} from '@shared/models/widget.models'; +import { UntypedFormBuilder, UntypedFormGroup } from '@angular/forms'; +import { Store } from '@ngrx/store'; +import { AppState } from '@core/core.state'; +import { formatValue } from '@core/utils'; +import { rangeChartDefaultSettings } from '@home/components/widget/lib/chart/range-chart-widget.models'; +import { DateFormatProcessor, DateFormatSettings } from '@shared/models/widget-settings.models'; + +@Component({ + selector: 'tb-range-chart-widget-settings', + templateUrl: './range-chart-widget-settings.component.html', + styleUrls: [] +}) +export class RangeChartWidgetSettingsComponent extends WidgetSettingsComponent { + + legendPositions = legendPositions; + + legendPositionTranslationMap = legendPositionTranslationMap; + + rangeChartWidgetSettingsForm: UntypedFormGroup; + + tooltipValuePreviewFn = this._tooltipValuePreviewFn.bind(this); + + tooltipDatePreviewFn = this._tooltipDatePreviewFn.bind(this); + + constructor(protected store: Store, + private $injector: Injector, + private fb: UntypedFormBuilder) { + super(store); + } + + protected settingsForm(): UntypedFormGroup { + return this.rangeChartWidgetSettingsForm; + } + + protected defaultSettings(): WidgetSettings { + return {...rangeChartDefaultSettings}; + } + + protected onSettingsSet(settings: WidgetSettings) { + this.rangeChartWidgetSettingsForm = this.fb.group({ + dataZoom: [settings.dataZoom, []], + rangeColors: [settings.rangeColors, []], + outOfRangeColor: [settings.outOfRangeColor, []], + fillArea: [settings.fillArea, []], + + showLegend: [settings.showLegend, []], + legendPosition: [settings.legendPosition, []], + legendLabelFont: [settings.legendLabelFont, []], + legendLabelColor: [settings.legendLabelColor, []], + + showTooltip: [settings.showTooltip, []], + tooltipValueFont: [settings.tooltipValueFont, []], + tooltipValueColor: [settings.tooltipValueColor, []], + tooltipShowDate: [settings.tooltipShowDate, []], + tooltipDateFormat: [settings.tooltipDateFormat, []], + tooltipDateFont: [settings.tooltipDateFont, []], + tooltipDateColor: [settings.tooltipDateColor, []], + tooltipBackgroundColor: [settings.tooltipBackgroundColor, []], + tooltipBackgroundBlur: [settings.tooltipBackgroundBlur, []], + + background: [settings.background, []] + }); + } + + protected validatorTriggers(): string[] { + return ['showLegend', 'showTooltip', 'tooltipShowDate']; + } + + protected updateValidators(emitEvent: boolean) { + const showLegend: boolean = this.rangeChartWidgetSettingsForm.get('showLegend').value; + const showTooltip: boolean = this.rangeChartWidgetSettingsForm.get('showTooltip').value; + const tooltipShowDate: boolean = this.rangeChartWidgetSettingsForm.get('tooltipShowDate').value; + + if (showLegend) { + this.rangeChartWidgetSettingsForm.get('legendPosition').enable(); + this.rangeChartWidgetSettingsForm.get('legendLabelFont').enable(); + this.rangeChartWidgetSettingsForm.get('legendLabelColor').enable(); + } else { + this.rangeChartWidgetSettingsForm.get('legendPosition').disable(); + this.rangeChartWidgetSettingsForm.get('legendLabelFont').disable(); + this.rangeChartWidgetSettingsForm.get('legendLabelColor').disable(); + } + + if (showTooltip) { + this.rangeChartWidgetSettingsForm.get('tooltipValueFont').enable(); + this.rangeChartWidgetSettingsForm.get('tooltipValueColor').enable(); + this.rangeChartWidgetSettingsForm.get('tooltipShowDate').enable({emitEvent: false}); + this.rangeChartWidgetSettingsForm.get('tooltipBackgroundColor').enable(); + this.rangeChartWidgetSettingsForm.get('tooltipBackgroundBlur').enable(); + if (tooltipShowDate) { + this.rangeChartWidgetSettingsForm.get('tooltipDateFormat').enable(); + this.rangeChartWidgetSettingsForm.get('tooltipDateFont').enable(); + this.rangeChartWidgetSettingsForm.get('tooltipDateColor').enable(); + } else { + this.rangeChartWidgetSettingsForm.get('tooltipDateFormat').disable(); + this.rangeChartWidgetSettingsForm.get('tooltipDateFont').disable(); + this.rangeChartWidgetSettingsForm.get('tooltipDateColor').disable(); + } + } else { + this.rangeChartWidgetSettingsForm.get('tooltipValueFont').disable(); + this.rangeChartWidgetSettingsForm.get('tooltipValueColor').disable(); + this.rangeChartWidgetSettingsForm.get('tooltipShowDate').disable({emitEvent: false}); + this.rangeChartWidgetSettingsForm.get('tooltipDateFormat').disable(); + this.rangeChartWidgetSettingsForm.get('tooltipDateFont').disable(); + this.rangeChartWidgetSettingsForm.get('tooltipDateColor').disable(); + this.rangeChartWidgetSettingsForm.get('tooltipBackgroundColor').disable(); + this.rangeChartWidgetSettingsForm.get('tooltipBackgroundBlur').disable(); + } + } + + private _tooltipValuePreviewFn(): string { + const units: string = this.widgetConfig.config.units; + const decimals: number = this.widgetConfig.config.decimals; + return formatValue(22, decimals, units, false); + } + + private _tooltipDatePreviewFn(): string { + const dateFormat: DateFormatSettings = this.rangeChartWidgetSettingsForm.get('tooltipDateFormat').value; + const processor = DateFormatProcessor.fromSettings(this.$injector, dateFormat); + processor.update(Date.now()); + return processor.formatted; + } + +} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/background-settings-panel.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/background-settings-panel.component.html index 42c4472cca..6cca169f5a 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/background-settings-panel.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/background-settings-panel.component.html @@ -1,6 +1,6 @@
widgets.background.background-settings
-
+
widgets.background.background
@@ -27,14 +27,8 @@
- -
-
widgets.background.image-url
- - - -
-
+ +
widgets.color.color
@@ -64,7 +58,7 @@
widgets.background.preview
-
+
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/background-settings-panel.component.scss b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/background-settings-panel.component.scss index 258117512a..01297b9d12 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/background-settings-panel.component.scss +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/background-settings-panel.component.scss @@ -1,5 +1,5 @@ /** - * Copyright © 2016-2023 The Thingsboard Authors + * Copyright © 2016-2024 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. @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - @import '../../../../../../../../scss/constants'; .tb-background-settings-panel { @@ -31,6 +30,12 @@ letter-spacing: 0.25px; color: rgba(0, 0, 0, 0.87); } + .tb-background-form-panel { + height: 192px; + .tb-background-color-field { + height: auto; + } + } .tb-background-settings-preview { flex: 1; background: rgba(0, 0, 0, 0.04); diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/background-settings-panel.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/background-settings-panel.component.ts index ab94b95800..c1c85a05e1 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/background-settings-panel.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/background-settings-panel.component.ts @@ -1,5 +1,5 @@ /// -/// Copyright © 2016-2023 The Thingsboard Authors +/// Copyright © 2016-2024 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. @@ -14,7 +14,7 @@ /// limitations under the License. /// -import { Component, EventEmitter, Input, OnInit, Output, ViewEncapsulation } from '@angular/core'; +import { ChangeDetectorRef, Component, EventEmitter, Input, OnInit, Output, ViewEncapsulation } from '@angular/core'; import { PageComponent } from '@shared/components/page.component'; import { backgroundStyle, @@ -27,6 +27,9 @@ import { TbPopoverComponent } from '@shared/components/popover.component'; import { UntypedFormBuilder, UntypedFormGroup } from '@angular/forms'; import { Store } from '@ngrx/store'; import { AppState } from '@core/core.state'; +import { Observable } from 'rxjs'; +import { ImagePipe } from '@shared/pipe/image.pipe'; +import { DomSanitizer } from '@angular/platform-browser'; @Component({ selector: 'tb-background-settings-panel', @@ -54,11 +57,14 @@ export class BackgroundSettingsPanelComponent extends PageComponent implements O backgroundSettingsFormGroup: UntypedFormGroup; - backgroundStyle: ComponentStyle = {}; + backgroundStyle$: Observable; overlayStyle: ComponentStyle = {}; constructor(private fb: UntypedFormBuilder, - protected store: Store) { + private imagePipe: ImagePipe, + private sanitizer: DomSanitizer, + protected store: Store, + private cd: ChangeDetectorRef) { super(store); } @@ -66,7 +72,6 @@ export class BackgroundSettingsPanelComponent extends PageComponent implements O this.backgroundSettingsFormGroup = this.fb.group( { type: [this.backgroundSettings?.type, []], - imageBase64: [this.backgroundSettings?.imageBase64, []], imageUrl: [this.backgroundSettings?.imageUrl, []], color: [this.backgroundSettings?.color, []], overlay: this.fb.group({ @@ -101,11 +106,11 @@ export class BackgroundSettingsPanelComponent extends PageComponent implements O private updateValidators() { const overlayEnabled: boolean = this.backgroundSettingsFormGroup.get('overlay').get('enabled').value; if (overlayEnabled) { - this.backgroundSettingsFormGroup.get('overlay').get('color').enable(); - this.backgroundSettingsFormGroup.get('overlay').get('blur').enable(); + this.backgroundSettingsFormGroup.get('overlay').get('color').enable({emitEvent: false}); + this.backgroundSettingsFormGroup.get('overlay').get('blur').enable({emitEvent: false}); } else { - this.backgroundSettingsFormGroup.get('overlay').get('color').disable(); - this.backgroundSettingsFormGroup.get('overlay').get('blur').disable(); + this.backgroundSettingsFormGroup.get('overlay').get('color').disable({emitEvent: false}); + this.backgroundSettingsFormGroup.get('overlay').get('blur').disable({emitEvent: false}); } this.backgroundSettingsFormGroup.get('overlay').get('color').updateValueAndValidity({emitEvent: false}); this.backgroundSettingsFormGroup.get('overlay').get('blur').updateValueAndValidity({emitEvent: false}); @@ -113,8 +118,9 @@ export class BackgroundSettingsPanelComponent extends PageComponent implements O private updateBackgroundStyle() { const background: BackgroundSettings = this.backgroundSettingsFormGroup.value; - this.backgroundStyle = backgroundStyle(background); + this.backgroundStyle$ = backgroundStyle(background, this.imagePipe, this.sanitizer, true); this.overlayStyle = overlayStyle(background.overlay); + this.cd.markForCheck(); } } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/background-settings.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/background-settings.component.html index e9e1b99b0e..ea685bd85f 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/background-settings.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/background-settings.component.html @@ -1,6 +1,6 @@
- - +
widgets.maps.image-map-background-from-entity-attribute
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/map/image-map-provider-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/map/image-map-provider-settings.component.ts index e79735e70d..51cc5ae6d7 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/map/image-map-provider-settings.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/map/image-map-provider-settings.component.ts @@ -1,5 +1,5 @@ /// -/// Copyright © 2016-2023 The Thingsboard Authors +/// Copyright © 2016-2024 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. diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/map/map-editor-settings.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/map/map-editor-settings.component.html index 8c0eb5e6b2..edea61f456 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/map/map-editor-settings.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/map/map-editor-settings.component.html @@ -1,6 +1,6 @@ -
+
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/weather/wind-speed-direction-widget.component.scss b/ui-ngx/src/app/modules/home/components/widget/lib/weather/wind-speed-direction-widget.component.scss index eda98fe6ba..5f3b18a041 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/weather/wind-speed-direction-widget.component.scss +++ b/ui-ngx/src/app/modules/home/components/widget/lib/weather/wind-speed-direction-widget.component.scss @@ -1,5 +1,5 @@ /** - * Copyright © 2016-2023 The Thingsboard Authors + * Copyright © 2016-2024 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. diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/weather/wind-speed-direction-widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/weather/wind-speed-direction-widget.component.ts index bf43218f82..4ce5cf21d7 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/weather/wind-speed-direction-widget.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/weather/wind-speed-direction-widget.component.ts @@ -1,5 +1,5 @@ /// -/// Copyright © 2016-2023 The Thingsboard Authors +/// Copyright © 2016-2024 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. @@ -47,6 +47,9 @@ import { formatValue, isDefinedAndNotNull, isNumeric } from '@core/utils'; import { ResizeObserver } from '@juggle/resize-observer'; import { Path, Svg, SVG, Text } from '@svgdotjs/svg.js'; import { DataKey } from '@shared/models/widget.models'; +import { Observable } from 'rxjs'; +import { ImagePipe } from '@shared/pipe/image.pipe'; +import { DomSanitizer } from '@angular/platform-browser'; const shapeSize = 180; const cx = shapeSize / 2; @@ -87,7 +90,7 @@ export class WindSpeedDirectionWidgetComponent implements OnInit, OnDestroy, Aft centerValueColor: ColorProcessor; - backgroundStyle: ComponentStyle = {}; + backgroundStyle$: Observable; overlayStyle: ComponentStyle = {}; shapeResize$: ResizeObserver; @@ -109,6 +112,8 @@ export class WindSpeedDirectionWidgetComponent implements OnInit, OnDestroy, Aft private centerValueText = 'N/A'; constructor(private widgetComponent: WidgetComponent, + private imagePipe: ImagePipe, + private sanitizer: DomSanitizer, private renderer: Renderer2, private cd: ChangeDetectorRef) { } @@ -135,7 +140,7 @@ export class WindSpeedDirectionWidgetComponent implements OnInit, OnDestroy, Aft this.centerValueColor = ColorProcessor.fromSettings(this.settings.centerValueColor); - this.backgroundStyle = backgroundStyle(this.settings.background); + this.backgroundStyle$ = backgroundStyle(this.settings.background, this.imagePipe, this.sanitizer); this.overlayStyle = overlayStyle(this.settings.background.overlay); this.hasCardClickAction = this.ctx.actionsApi.getActionDescriptors('cardClick').length > 0; diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/weather/wind-speed-direction-widget.models.ts b/ui-ngx/src/app/modules/home/components/widget/lib/weather/wind-speed-direction-widget.models.ts index 6359696f25..7801f80a17 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/weather/wind-speed-direction-widget.models.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/weather/wind-speed-direction-widget.models.ts @@ -1,5 +1,5 @@ /// -/// Copyright © 2016-2023 The Thingsboard Authors +/// Copyright © 2016-2024 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. diff --git a/ui-ngx/src/app/modules/home/components/widget/widget-component.service.ts b/ui-ngx/src/app/modules/home/components/widget/widget-component.service.ts index c29df7f243..56a1868227 100644 --- a/ui-ngx/src/app/modules/home/components/widget/widget-component.service.ts +++ b/ui-ngx/src/app/modules/home/components/widget/widget-component.service.ts @@ -1,5 +1,5 @@ /// -/// Copyright © 2016-2023 The Thingsboard Authors +/// Copyright © 2016-2024 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. diff --git a/ui-ngx/src/app/modules/home/components/widget/widget-components.module.ts b/ui-ngx/src/app/modules/home/components/widget/widget-components.module.ts index d4828a0190..851a469642 100644 --- a/ui-ngx/src/app/modules/home/components/widget/widget-components.module.ts +++ b/ui-ngx/src/app/modules/home/components/widget/widget-components.module.ts @@ -1,5 +1,5 @@ /// -/// Copyright © 2016-2023 The Thingsboard Authors +/// Copyright © 2016-2024 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. @@ -74,6 +74,10 @@ import { ValueChartCardWidgetComponent } from '@home/components/widget/lib/cards import { ProgressBarWidgetComponent } from '@home/components/widget/lib/cards/progress-bar-widget.component'; import { LiquidLevelWidgetComponent } from '@home/components/widget/lib/indicator/liquid-level-widget.component'; import { DoughnutWidgetComponent } from '@home/components/widget/lib/chart/doughnut-widget.component'; +import { RangeChartWidgetComponent } from '@home/components/widget/lib/chart/range-chart-widget.component'; +import { + BarChartWithLabelsWidgetComponent +} from '@home/components/widget/lib/chart/bar-chart-with-labels-widget.component'; import { GatewayServiceRPCConnectorTemplateDialogComponent } from '@home/components/widget/lib/gateway/gateway-service-rpc-connector-template-dialog'; @@ -120,7 +124,9 @@ import { ValueChartCardWidgetComponent, ProgressBarWidgetComponent, LiquidLevelWidgetComponent, - DoughnutWidgetComponent + DoughnutWidgetComponent, + RangeChartWidgetComponent, + BarChartWithLabelsWidgetComponent ], imports: [ CommonModule, @@ -129,47 +135,49 @@ import { HomePageWidgetsModule, SharedHomeComponentsModule ], - exports: [ - EntitiesTableWidgetComponent, - AlarmsTableWidgetComponent, - TimeseriesTableWidgetComponent, - EntitiesHierarchyWidgetComponent, - EdgesOverviewWidgetComponent, - RpcWidgetsModule, - HomePageWidgetsModule, - DateRangeNavigatorWidgetComponent, - JsonInputWidgetComponent, - MultipleInputWidgetComponent, - TripAnimationComponent, - PhotoCameraInputWidgetComponent, - GatewayFormComponent, - NavigationCardsWidgetComponent, - NavigationCardWidgetComponent, - QrCodeWidgetComponent, - MarkdownWidgetComponent, - LegendComponent, - FlotWidgetComponent, - GatewayConnectorComponent, - GatewayLogsComponent, - GatewayServiceRPCConnectorComponent, - GatewayServiceRPCConnectorTemplatesComponent, - GatewayStatisticsComponent, - GatewayServiceRPCComponent, - DeviceGatewayCommandComponent, - GatewayConfigurationComponent, - GatewayRemoteConfigurationDialogComponent, - GatewayServiceRPCConnectorTemplateDialogComponent, - ValueCardWidgetComponent, - AggregatedValueCardWidgetComponent, - CountWidgetComponent, - BatteryLevelWidgetComponent, - WindSpeedDirectionWidgetComponent, - SignalStrengthWidgetComponent, - ValueChartCardWidgetComponent, - ProgressBarWidgetComponent, - LiquidLevelWidgetComponent, - DoughnutWidgetComponent - ], + exports: [ + EntitiesTableWidgetComponent, + AlarmsTableWidgetComponent, + TimeseriesTableWidgetComponent, + EntitiesHierarchyWidgetComponent, + EdgesOverviewWidgetComponent, + RpcWidgetsModule, + HomePageWidgetsModule, + DateRangeNavigatorWidgetComponent, + JsonInputWidgetComponent, + MultipleInputWidgetComponent, + TripAnimationComponent, + PhotoCameraInputWidgetComponent, + GatewayFormComponent, + NavigationCardsWidgetComponent, + NavigationCardWidgetComponent, + QrCodeWidgetComponent, + MarkdownWidgetComponent, + LegendComponent, + FlotWidgetComponent, + GatewayConnectorComponent, + GatewayLogsComponent, + GatewayServiceRPCConnectorComponent, + GatewayServiceRPCConnectorTemplatesComponent, + GatewayStatisticsComponent, + GatewayServiceRPCComponent, + DeviceGatewayCommandComponent, + GatewayConfigurationComponent, + GatewayRemoteConfigurationDialogComponent, + GatewayServiceRPCConnectorTemplateDialogComponent, + ValueCardWidgetComponent, + AggregatedValueCardWidgetComponent, + CountWidgetComponent, + BatteryLevelWidgetComponent, + WindSpeedDirectionWidgetComponent, + SignalStrengthWidgetComponent, + ValueChartCardWidgetComponent, + ProgressBarWidgetComponent, + LiquidLevelWidgetComponent, + DoughnutWidgetComponent, + RangeChartWidgetComponent, + BarChartWithLabelsWidgetComponent + ], providers: [ {provide: WIDGET_COMPONENTS_MODULE_TOKEN, useValue: WidgetComponentsModule} ] diff --git a/ui-ngx/src/app/modules/home/components/widget/widget-config.component.html b/ui-ngx/src/app/modules/home/components/widget/widget-config.component.html index cdd1d8e2da..e49b769fee 100644 --- a/ui-ngx/src/app/modules/home/components/widget/widget-config.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/widget-config.component.html @@ -1,6 +1,6 @@
-
-
- -
{{ noFileText }}
-
{{ fileName }}
+
+ +
{{ noFileText }}
+
{{ fileName }}
+
dashboard.maximum-upload-file-size
+
diff --git a/ui-ngx/src/app/shared/components/file-input.component.scss b/ui-ngx/src/app/shared/components/file-input.component.scss index e172abd6e9..2aa4190823 100644 --- a/ui-ngx/src/app/shared/components/file-input.component.scss +++ b/ui-ngx/src/app/shared/components/file-input.component.scss @@ -1,5 +1,5 @@ /** - * Copyright © 2016-2023 The Thingsboard Authors + * Copyright © 2016-2024 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. @@ -21,9 +21,13 @@ $previewSize: 100px !default; .tb-container { margin-top: 0; + padding: 0 0 16px; + display: flex; + flex-direction: column; + gap: 8px; label.tb-title { display: flex; - padding-bottom: 8px; + padding-bottom: 0; } } @@ -78,19 +82,46 @@ $previewSize: 100px !default; text-align: center; .mat-icon { margin-right: 17px; + color: rgba(0,0,0,0.12); } } } + + .tb-file-info-container { + display: flex; + flex-direction: column; + gap: 8px; + font-size: 13px; + font-style: normal; + line-height: 16px; + letter-spacing: normal; + } + + .tb-file-name { + color: rgba(0, 0, 0, 0.54); + font-weight: 500; + overflow: hidden; + text-overflow: ellipsis; + } + + .tb-file-hint { + color: rgba(0, 0, 0, 0.38); + font-weight: 400; + overflow: hidden; + text-overflow: ellipsis; + } } :host ::ng-deep { - button.browse-file { + button.mat-mdc-button.mat-mdc-button-base.browse-file { padding: 0; + min-width: 0; + height: 24px; font-size: 16px; label { display: block; cursor: pointer; - padding: 0 16px; + padding: 0 8px; } } diff --git a/ui-ngx/src/app/shared/components/file-input.component.ts b/ui-ngx/src/app/shared/components/file-input.component.ts index 8e70ca88ba..b385cf109a 100644 --- a/ui-ngx/src/app/shared/components/file-input.component.ts +++ b/ui-ngx/src/app/shared/components/file-input.component.ts @@ -1,5 +1,5 @@ /// -/// Copyright © 2016-2023 The Thingsboard Authors +/// Copyright © 2016-2024 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. @@ -32,10 +32,12 @@ import { Store } from '@ngrx/store'; import { AppState } from '@core/core.state'; import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'; import { Subscription } from 'rxjs'; -import { coerceBooleanProperty } from '@angular/cdk/coercion'; import { FlowDirective } from '@flowjs/ngx-flow'; import { TranslateService } from '@ngx-translate/core'; import { UtilsService } from '@core/services/utils.service'; +import { DialogService } from '@core/services/dialog.service'; +import { FileSizePipe } from '@shared/pipe/file-size.pipe'; +import { coerceBoolean } from '@shared/decorators/coercion'; @Component({ selector: 'tb-file-input', @@ -73,43 +75,28 @@ export class FileInputComponent extends PageComponent implements AfterViewInit, dropLabel: string; @Input() - contentConvertFunction: (content: string) => any; - - private requiredValue: boolean; - - get required(): boolean { - return this.requiredValue; - } + maxSizeByte: number; @Input() - set required(value: boolean) { - const newVal = coerceBooleanProperty(value); - if (this.requiredValue !== newVal) { - this.requiredValue = newVal; - } - } - - private requiredAsErrorValue: boolean; + contentConvertFunction: (content: string) => any; - get requiredAsError(): boolean { - return this.requiredAsErrorValue; - } + @Input() + @coerceBoolean() + required: boolean; @Input() - set requiredAsError(value: boolean) { - const newVal = coerceBooleanProperty(value); - if (this.requiredAsErrorValue !== newVal) { - this.requiredAsErrorValue = newVal; - } - } + @coerceBoolean() + requiredAsError: boolean; @Input() + @coerceBoolean() disabled: boolean; @Input() existingFileName: string; @Input() + @coerceBoolean() readAsBinary = false; @Input() @@ -148,7 +135,9 @@ export class FileInputComponent extends PageComponent implements AfterViewInit, constructor(protected store: Store, private utils: UtilsService, - public translate: TranslateService) { + private translate: TranslateService, + private dialog: DialogService, + private fileSize: FileSizePipe) { super(store); } @@ -156,11 +145,24 @@ export class FileInputComponent extends PageComponent implements AfterViewInit, this.autoUploadSubscription = this.flow.events$.subscribe(event => { if (event.type === 'filesAdded') { const readers = []; + let showMaxSizeAlert = false; (event.event[0] as flowjs.FlowFile[]).forEach(file => { if (this.filterFile(file)) { - readers.push(this.readerAsFile(file)); + if (this.checkMaxSize(file)) { + readers.push(this.readerAsFile(file)); + } else { + showMaxSizeAlert = true; + } } }); + + if (showMaxSizeAlert) { + this.dialog.alert( + this.translate.instant('dashboard.cannot-upload-file'), + this.translate.instant('dashboard.maximum-upload-file-size', {size: this.fileSize.transform(this.maxSizeByte)}) + ).subscribe(() => { }); + } + if (readers.length) { Promise.all(readers).then((files) => { files = files.filter(file => file.fileContent != null || file.files != null); @@ -218,6 +220,10 @@ export class FileInputComponent extends PageComponent implements AfterViewInit, }); } + private checkMaxSize(file: flowjs.FlowFile): boolean { + return !this.maxSizeByte || file.size <= this.maxSizeByte; + } + private filterFile(file: flowjs.FlowFile): boolean { if (this.allowedExtensions) { return this.allowedExtensions.split(',').indexOf(file.getExtension()) > -1; diff --git a/ui-ngx/src/app/shared/components/footer-fab-buttons.component.html b/ui-ngx/src/app/shared/components/footer-fab-buttons.component.html index 20820ac320..7d9c0c33d5 100644 --- a/ui-ngx/src/app/shared/components/footer-fab-buttons.component.html +++ b/ui-ngx/src/app/shared/components/footer-fab-buttons.component.html @@ -1,6 +1,6 @@ - - + +
-
+
- +
diff --git a/ui-ngx/src/app/modules/home/components/grid/scroll-grid.component.scss b/ui-ngx/src/app/shared/components/grid/scroll-grid.component.scss similarity index 93% rename from ui-ngx/src/app/modules/home/components/grid/scroll-grid.component.scss rename to ui-ngx/src/app/shared/components/grid/scroll-grid.component.scss index 8787e24eb5..47d7629f7a 100644 --- a/ui-ngx/src/app/modules/home/components/grid/scroll-grid.component.scss +++ b/ui-ngx/src/app/shared/components/grid/scroll-grid.component.scss @@ -1,5 +1,5 @@ /** - * Copyright © 2016-2023 The Thingsboard Authors + * Copyright © 2016-2024 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. @@ -18,6 +18,7 @@ .cdk-virtual-scroll-content-wrapper { display: flex; flex-direction: column; + width: 100%; } .cdk-virtual-scroll-spacer { height: auto !important; diff --git a/ui-ngx/src/app/modules/home/components/grid/scroll-grid.component.ts b/ui-ngx/src/app/shared/components/grid/scroll-grid.component.ts similarity index 54% rename from ui-ngx/src/app/modules/home/components/grid/scroll-grid.component.ts rename to ui-ngx/src/app/shared/components/grid/scroll-grid.component.ts index e0eea202ff..e876b06694 100644 --- a/ui-ngx/src/app/modules/home/components/grid/scroll-grid.component.ts +++ b/ui-ngx/src/app/shared/components/grid/scroll-grid.component.ts @@ -1,5 +1,5 @@ /// -/// Copyright © 2016-2023 The Thingsboard Authors +/// Copyright © 2016-2024 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. @@ -15,10 +15,10 @@ /// import { - AfterViewInit, + AfterViewInit, ChangeDetectorRef, Component, Input, - OnChanges, + OnChanges, OnDestroy, OnInit, Renderer2, SimpleChanges, @@ -30,10 +30,18 @@ import { GridEntitiesFetchFunction, ScrollGridColumns, ScrollGridDatasource -} from '@home/models/datasource/scroll-grid-datasource'; +} from '@shared/components/grid/scroll-grid-datasource'; import { BreakpointObserver } from '@angular/cdk/layout'; import { isObject } from '@app/core/utils'; import { CdkVirtualScrollViewport } from '@angular/cdk/scrolling'; +import { ResizeObserver } from '@juggle/resize-observer'; + +export type ItemSizeFunction = (itemWidth: number) => number; + +export interface ItemSizeStrategy { + defaultItemSize: number; + itemSizeFunction: ItemSizeFunction; +} @Component({ selector: 'tb-scroll-grid', @@ -41,7 +49,7 @@ import { CdkVirtualScrollViewport } from '@angular/cdk/scrolling'; styleUrls: ['./scroll-grid.component.scss'], encapsulation: ViewEncapsulation.None }) -export class ScrollGridComponent implements OnInit, AfterViewInit, OnChanges { +export class ScrollGridComponent implements OnInit, AfterViewInit, OnChanges, OnDestroy { @ViewChild('viewport') viewport: CdkVirtualScrollViewport; @@ -56,7 +64,7 @@ export class ScrollGridComponent implements OnInit, AfterViewInit, OnChang filter: F; @Input() - itemSize = 200; + itemSize: number | ItemSizeStrategy = 200; @Input() gap = 12; @@ -75,17 +83,37 @@ export class ScrollGridComponent implements OnInit, AfterViewInit, OnChang dataSource: ScrollGridDatasource; + calculatedItemSize: number; + minBuffer: number; + maxBuffer: number; + + private contentResize$: ResizeObserver; + constructor(private breakpointObserver: BreakpointObserver, + private cd: ChangeDetectorRef, private renderer: Renderer2) { } ngOnInit(): void { + if (typeof this.itemSize === 'number') { + this.calculatedItemSize = this.itemSize; + } else { + this.calculatedItemSize = this.itemSize.defaultItemSize; + } + this.minBuffer = this.calculatedItemSize; + this.maxBuffer = this.calculatedItemSize * 2; this.dataSource = new ScrollGridDatasource(this.breakpointObserver, this.columns, this.fetchFunction, this.filter); } ngAfterViewInit() { this.renderer.setStyle(this.viewport._contentWrapper.nativeElement, 'gap', this.gap + 'px'); this.renderer.setStyle(this.viewport._contentWrapper.nativeElement, 'padding', this.gap + 'px'); + if (!(typeof this.itemSize === 'number')) { + this.contentResize$ = new ResizeObserver(() => { + this.onContentResize(); + }); + this.contentResize$.observe(this.viewport._contentWrapper.nativeElement); + } } ngOnChanges(changes: SimpleChanges): void { @@ -97,7 +125,43 @@ export class ScrollGridComponent implements OnInit, AfterViewInit, OnChang } } + ngOnDestroy() { + if (this.contentResize$) { + this.contentResize$.disconnect(); + } + } + isObject(value: any): boolean { return isObject(value); } + + trackByItemsRow(index: number, itemsRow: T[]): number { + return index; + } + + trackByItem(index: number, item: T): T { + return item; + } + + public update() { + this.dataSource.update(); + } + + public updateItem(index: number, item: T) { + this.dataSource.updateItem(index, item); + } + + public deleteItem(index: number) { + this.dataSource.deleteItem(index); + } + + private onContentResize() { + const contentWidth = this.viewport._contentWrapper.nativeElement.getBoundingClientRect().width; + const columns = this.dataSource.currentColumns; + const itemWidth = (contentWidth - this.gap * (columns + 1)) / columns; + this.calculatedItemSize = (this.itemSize as ItemSizeStrategy).itemSizeFunction(itemWidth); + this.minBuffer = this.calculatedItemSize; + this.maxBuffer = this.calculatedItemSize * 2; + this.cd.markForCheck(); + } } diff --git a/ui-ngx/src/app/shared/components/help-markdown.component.html b/ui-ngx/src/app/shared/components/help-markdown.component.html index cba58b60f4..55a8786d0e 100644 --- a/ui-ngx/src/app/shared/components/help-markdown.component.html +++ b/ui-ngx/src/app/shared/components/help-markdown.component.html @@ -1,6 +1,6 @@ + +

{{ 'image.embed-image' | translate }}

+ + +
+ + +
+
+
+ + + +
+ +
{{ 'image.embed-to-html' | translate }}
+
+
+
image.embed-to-html
+
+
+ +
+ +
+
+
+
+
image.embed-to-angular-template
+
+ +
+
diff --git a/ui-ngx/src/app/shared/components/image/embed-image-dialog.component.scss b/ui-ngx/src/app/shared/components/image/embed-image-dialog.component.scss new file mode 100644 index 0000000000..eeaff6e83c --- /dev/null +++ b/ui-ngx/src/app/shared/components/image/embed-image-dialog.component.scss @@ -0,0 +1,71 @@ +/** + * Copyright © 2016-2024 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 { + .mat-mdc-dialog-content { + display: flex; + flex-direction: column; + gap: 16px; + .tb-embed-image-text { + font-size: 14px; + font-weight: 400; + line-height: 20px; + color: rgba(0,0,0,0.54); + letter-spacing: 0.2px; + } + .tb-form-panel-title { + color: rgba(0, 0, 0, 0.87); + } + } +} + +:host ::ng-deep { + .tb-markdown-view { + max-width: 700px; + .tb-embed-image-code { + .code-wrapper { + padding: 0; + pre[class*=language-] { + margin: 0; + padding: 9px 38px 9px 16px; + } + code[class*="language-"], pre[class*="language-"] { + font-size: 12px; + overflow: hidden; + white-space: normal; + word-break: break-word; + } + button.clipboard-btn { + right: 0; + height: 36px; + p, div { + background: transparent; + } + p { + margin: 0; + padding: 6px; + font-size: 14px; + } + div { + top: 0; + padding: 8px; + height: 38px; + width: 38px; + } + } + } + } + } +} diff --git a/ui-ngx/src/app/shared/components/image/embed-image-dialog.component.ts b/ui-ngx/src/app/shared/components/image/embed-image-dialog.component.ts new file mode 100644 index 0000000000..f4d3e6d989 --- /dev/null +++ b/ui-ngx/src/app/shared/components/image/embed-image-dialog.component.ts @@ -0,0 +1,94 @@ +/// +/// Copyright © 2016-2024 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 { ImageResourceInfo } from '@shared/models/resource.models'; +import { Component, Inject, OnInit } from '@angular/core'; +import { DialogComponent } from '@shared/components/dialog.component'; +import { Store } from '@ngrx/store'; +import { AppState } from '@core/core.state'; +import { Router } from '@angular/router'; +import { ImageService } from '@core/http/image.service'; +import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; +import { FormControl, UntypedFormBuilder } from '@angular/forms'; + +export interface EmbedImageDialogData { + readonly: boolean; + image: ImageResourceInfo; +} + +@Component({ + selector: 'tb-embed-image-dialog', + templateUrl: './embed-image-dialog.component.html', + styleUrls: ['./embed-image-dialog.component.scss'] +}) +export class EmbedImageDialogComponent extends + DialogComponent implements OnInit { + + image = this.data.image; + + readonly = this.data.readonly; + + imageChanged = false; + + publicStatusControl = new FormControl(this.image.public); + + constructor(protected store: Store, + protected router: Router, + private imageService: ImageService, + @Inject(MAT_DIALOG_DATA) private data: EmbedImageDialogData, + public dialogRef: MatDialogRef, + public fb: UntypedFormBuilder) { + super(store, router, dialogRef); + } + + ngOnInit(): void { + if (!this.readonly) { + this.publicStatusControl.valueChanges.subscribe( + (isPublic) => { + this.updateImagePublicStatus(isPublic); + } + ); + } + } + + cancel(): void { + this.dialogRef.close(this.imageChanged ? this.image : null); + } + + embedToHtmlCode(): string { + return '```html\n' + + ''+this.image.title.replace(/' + + '{:copy-code}\n' + + '```'; + } + + embedToAngularTemplateCode(): string { + return '```html\n' + + '' + + '{:copy-code}\n' + + '```'; + } + + private updateImagePublicStatus(isPublic: boolean): void { + this.imageService.updateImagePublicStatus(this.image, isPublic).subscribe( + (image) => { + this.image = image; + this.imageChanged = true; + } + ); + } + +} diff --git a/ui-ngx/src/app/shared/components/image/gallery-image-input.component.html b/ui-ngx/src/app/shared/components/image/gallery-image-input.component.html new file mode 100644 index 0000000000..d97035c048 --- /dev/null +++ b/ui-ngx/src/app/shared/components/image/gallery-image-input.component.html @@ -0,0 +1,94 @@ + +
+ +
+
+ +
+
+
+
+
+ +
+ {{ imageResource.title }} +
+
+
{{ imageResource.descriptor.width }}x{{ imageResource.descriptor.height }}
+ +
{{ imageResource.descriptor.size | fileSize }}
+
+
+
+
+ + +
+ +
+
+ + +
+
+
+ + +
{{ (disabled ? 'image.no-image' : 'image.no-image-selected') | translate }}
+
+ + + diff --git a/ui-ngx/src/app/shared/components/image/gallery-image-input.component.scss b/ui-ngx/src/app/shared/components/image/gallery-image-input.component.scss new file mode 100644 index 0000000000..d1c9e953a7 --- /dev/null +++ b/ui-ngx/src/app/shared/components/image/gallery-image-input.component.scss @@ -0,0 +1,190 @@ +/** + * Copyright © 2016-2024 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 "../../../../scss/constants"; + +$containerHeight: 96px !default; + +:host { + .tb-container { + margin-top: 0; + padding: 0 0 16px; + display: flex; + flex-direction: column; + gap: 8px; + label.tb-title { + display: block; + padding-bottom: 0; + } + } + + .tb-image-select-container { + width: 100%; + height: $containerHeight; + border-radius: 4px; + border: 1px solid rgba(0, 0, 0, 0.12); + display: flex; + align-items: center; + &.disabled { + width: $containerHeight; + .tb-image-container { + width: $containerHeight - 2px; + border-right: none; + } + } + } + + .tb-image-container { + width: $containerHeight - 1px; + height: $containerHeight - 2px; + display: flex; + justify-content: center; + align-items: center; + border-radius: 4px; + border-right: 1px solid rgba(0, 0, 0, 0.12); + background: #fff; + overflow: hidden; + } + + .tb-image-preview { + width: auto; + max-width: $containerHeight - 2px; + height: auto; + max-height: $containerHeight - 2px; + } + + .tb-no-image { + text-align: center; + color: rgba(0, 0, 0, 0.38); + font-size: 12px; + font-style: normal; + font-weight: 400; + line-height: 16px; + letter-spacing: 0.4px; + } + + .tb-image-info-container { + display: flex; + flex: 1; + align-self: stretch; + padding: 0 8px; + justify-content: flex-end; + align-items: center; + gap: 4px; + .tb-base64-image-container, .tb-resource-image-container, .tb-external-image-container { + display: flex; + flex: 1; + align-self: stretch; + } + .tb-resource-image-container { + padding: 8px; + justify-content: center; + align-items: flex-start; + flex-direction: column; + gap: 4px; + .tb-resource-image-name { + color: rgba(0, 0, 0, 0.54); + overflow: hidden; + text-overflow: ellipsis; + -webkit-line-clamp: 2; + display: -webkit-box; + -webkit-box-orient: vertical; + font-size: 12px; + font-style: normal; + font-weight: 500; + line-height: 16px; + letter-spacing: 0.25px; + } + .tb-resource-image-details { + display: flex; + align-items: center; + gap: 8px; + color: rgba(0, 0, 0, 0.38); + font-size: 11px; + font-style: normal; + font-weight: 400; + line-height: 16px; + letter-spacing: 0.017px; + .mat-divider.mat-divider-vertical { + height: 16px; + } + } + &.loading { + align-items: center; + } + } + + .tb-external-image-container { + padding: 16px 8px 0 16px; + flex-direction: column; + align-items: flex-start; + gap: 4px; + .tb-external-link-label { + color: rgba(0, 0, 0, 0.54); + font-size: 12px; + font-style: normal; + font-weight: 400; + line-height: 16px; + letter-spacing: 0.4px; + } + .tb-external-link-input-container { + display: flex; + justify-content: flex-end; + align-items: center; + gap: 4px; + align-self: stretch; + .tb-inline-field { + width: 100%; + } + } + } + + .tb-image-clear-btn { + color: rgba(0,0,0,0.38); + } + } + + .tb-image-select-buttons-container { + display: flex; + flex: 1; + align-self: stretch; + padding: 8px; + gap: 8px; + justify-content: center; + align-items: flex-start; + .tb-image-select-button { + width: 100%; + height: 100%; + align-self: stretch; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + gap: 4px; + padding: 8px; + line-height: normal; + font-size: 12px; + @media #{$mat-gt-xs} { + padding: 16px; + } + .mat-icon { + width: 24px; + height: 24px; + font-size: 24px; + margin: 0; + } + } + } +} diff --git a/ui-ngx/src/app/shared/components/image/gallery-image-input.component.ts b/ui-ngx/src/app/shared/components/image/gallery-image-input.component.ts new file mode 100644 index 0000000000..9b81a0eaba --- /dev/null +++ b/ui-ngx/src/app/shared/components/image/gallery-image-input.component.ts @@ -0,0 +1,205 @@ +/// +/// Copyright © 2016-2024 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 { ChangeDetectorRef, Component, forwardRef, Input, OnDestroy, OnInit } from '@angular/core'; +import { PageComponent } from '@shared/components/page.component'; +import { Store } from '@ngrx/store'; +import { AppState } from '@core/core.state'; +import { ControlValueAccessor, FormControl, NG_VALUE_ACCESSOR, } from '@angular/forms'; +import { coerceBoolean } from '@shared/decorators/coercion'; +import { + extractParamsFromImageResourceUrl, + ImageResourceInfo, + isBase64DataImageUrl, + isImageResourceUrl, + prependTbImagePrefix, + removeTbImagePrefix +} from '@shared/models/resource.models'; +import { ImageService } from '@core/http/image.service'; +import { MatDialog } from '@angular/material/dialog'; +import { ImageGalleryDialogComponent } from '@shared/components/image/image-gallery-dialog.component'; + +export enum ImageLinkType { + none = 'none', + base64 = 'base64', + external = 'external', + resource = 'resource' +} + +@Component({ + selector: 'tb-gallery-image-input', + templateUrl: './gallery-image-input.component.html', + styleUrls: ['./gallery-image-input.component.scss'], + providers: [ + { + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => GalleryImageInputComponent), + multi: true + } + ] +}) +export class GalleryImageInputComponent extends PageComponent implements OnInit, OnDestroy, ControlValueAccessor { + + @Input() + label: string; + + @Input() + @coerceBoolean() + required = false; + + @Input() + disabled: boolean; + + imageUrl: string; + + imageResource: ImageResourceInfo; + + loadingImageResource = false; + + ImageLinkType = ImageLinkType; + + linkType: ImageLinkType = ImageLinkType.none; + + externalLinkControl = new FormControl(null); + + private propagateChange = null; + + constructor(protected store: Store, + private imageService: ImageService, + private dialog: MatDialog, + private cd: ChangeDetectorRef) { + super(store); + } + + ngOnInit() { + this.externalLinkControl.valueChanges.subscribe((value) => { + if (this.linkType === ImageLinkType.external) { + this.updateModel(value); + } + }); + } + + ngOnDestroy() { + } + + registerOnChange(fn: any): void { + this.propagateChange = fn; + } + + registerOnTouched(fn: any): void { + } + + setDisabledState(isDisabled: boolean): void { + this.disabled = isDisabled; + if (this.disabled) { + this.detectLinkType(); + this.externalLinkControl.disable({emitEvent: false}); + } else { + this.externalLinkControl.enable({emitEvent: false}); + } + } + + writeValue(value: string): void { + value = removeTbImagePrefix(value); + if (this.imageUrl !== value) { + this.reset(); + this.imageUrl = value; + this.detectLinkType(); + if (this.linkType === ImageLinkType.resource) { + const params = extractParamsFromImageResourceUrl(this.imageUrl); + this.loadingImageResource = true; + this.imageService.getImageInfo(params.type, params.key, {ignoreLoading: true, ignoreErrors: true}).subscribe( + { + next: (res) => { + this.imageResource = res; + this.loadingImageResource = false; + this.cd.markForCheck(); + }, + error: () => { + this.reset(); + this.loadingImageResource = false; + this.cd.markForCheck(); + } + } + ); + } else if (this.linkType === ImageLinkType.base64) { + this.cd.markForCheck(); + } else if (this.linkType === ImageLinkType.external) { + this.externalLinkControl.setValue(this.imageUrl, {emitEvent: false}); + this.cd.markForCheck(); + } + } + } + + private detectLinkType() { + if (this.imageUrl) { + if (isImageResourceUrl(this.imageUrl)) { + this.linkType = ImageLinkType.resource; + } else if (isBase64DataImageUrl(this.imageUrl)) { + this.linkType = ImageLinkType.base64; + } else { + this.linkType = ImageLinkType.external; + } + } else { + this.linkType = ImageLinkType.none; + } + } + + private updateModel(value: string) { + this.cd.markForCheck(); + if (this.imageUrl !== value) { + this.imageUrl = value; + this.propagateChange(prependTbImagePrefix(this.imageUrl)); + } + } + + private reset() { + this.linkType = ImageLinkType.none; + this.imageResource = null; + this.externalLinkControl.setValue(null, {emitEvent: false}); + } + + clearImage() { + this.reset(); + this.updateModel(null); + } + + setLink($event: Event) { + if ($event) { + $event.stopPropagation(); + } + this.linkType = ImageLinkType.external; + } + + openGallery($event: Event): void { + if ($event) { + $event.stopPropagation(); + } + this.dialog.open(ImageGalleryDialogComponent, { + autoFocus: false, + disableClose: false, + panelClass: ['tb-dialog', 'tb-fullscreen-dialog'] + }).afterClosed().subscribe((image) => { + if (image) { + this.linkType = ImageLinkType.resource; + this.imageResource = image; + this.updateModel(image.link); + } + }); + } + +} diff --git a/ui-ngx/src/app/shared/components/image/image-dialog.component.html b/ui-ngx/src/app/shared/components/image/image-dialog.component.html new file mode 100644 index 0000000000..dc2043097a --- /dev/null +++ b/ui-ngx/src/app/shared/components/image/image-dialog.component.html @@ -0,0 +1,107 @@ + + + +

{{ (readonly ? 'image.image-details' : 'image.edit-image') | translate }}

+ + +
+ + +
+
+
+ + image.name + + + {{ 'image.name-required' | translate }} + + + + +
+
+
+
+ + + +
+ +
+
+
+ +
+
+
{{ image.descriptor.width }}x{{ image.descriptor.height }}
+ +
{{ image.descriptor.size | fileSize }}
+
+
+
+
+
+ diff --git a/ui-ngx/src/app/shared/components/image/image-dialog.component.scss b/ui-ngx/src/app/shared/components/image/image-dialog.component.scss new file mode 100644 index 0000000000..86ec3b2486 --- /dev/null +++ b/ui-ngx/src/app/shared/components/image/image-dialog.component.scss @@ -0,0 +1,96 @@ +/** + * Copyright © 2016-2024 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 '../../../../scss/constants'; + +:host { + .tb-image-dialog { + @media #{$mat-gt-xs} { + width: 50vh; + } + .mat-mdc-dialog-content { + max-height: 100%; + } + fieldset { + height: 100%; + display: flex; + flex-direction: column; + } + } + .tb-image-container { + height: 100%; + border-radius: 4px; + border: 1px solid rgba(0, 0, 0, 0.05); + padding: 12px; + display: flex; + flex-direction: column; + align-items: flex-start; + gap: 12px; + + .tb-image-content { + height: 100%; + width: 100%; + display: flex; + flex-direction: column; + align-items: flex-start; + gap: 8px; + .tb-image-preview-container { + position: relative; + width: 100%; + height: 100%; + border: 1px solid rgba(0, 0, 0, 0.12); + border-radius: 4px; + background: #fff; + display: flex; + align-items: center; + justify-content: center; + z-index: 1; + .tb-image-preview-spacer { + @media #{$mat-gt-xs} { + margin-top: 100%; + } + } + .tb-image-preview { + position: absolute; + inset: 0; + width: 100%; + height: 100%; + object-fit: contain; + } + } + .tb-image-preview-details { + display: flex; + align-items: center; + gap: 8px; + color: rgba(0, 0, 0, 0.38); + font-size: 14px; + font-style: normal; + font-weight: 400; + line-height: 20px; + .mat-divider.mat-divider-vertical { + height: 20px; + } + } + .tb-image-actions { + display: flex; + align-items: center; + align-self: stretch; + justify-content: space-between; + gap: 8px; + color: rgba(0,0,0,0.54); + } + } + } +} diff --git a/ui-ngx/src/app/shared/components/image/image-dialog.component.ts b/ui-ngx/src/app/shared/components/image/image-dialog.component.ts new file mode 100644 index 0000000000..434d76d74d --- /dev/null +++ b/ui-ngx/src/app/shared/components/image/image-dialog.component.ts @@ -0,0 +1,163 @@ +/// +/// Copyright © 2016-2024 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, Inject, OnInit, SkipSelf } from '@angular/core'; +import { ErrorStateMatcher } from '@angular/material/core'; +import { MAT_DIALOG_DATA, MatDialog, MatDialogRef } from '@angular/material/dialog'; +import { Store } from '@ngrx/store'; +import { AppState } from '@core/core.state'; +import { UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms'; +import { DialogComponent } from '@shared/components/dialog.component'; +import { Router } from '@angular/router'; +import { ImageService } from '@core/http/image.service'; +import { ImageResourceInfo, imageResourceType } from '@shared/models/resource.models'; +import { + UploadImageDialogComponent, + UploadImageDialogData +} from '@shared/components/image/upload-image-dialog.component'; +import { UrlHolder } from '@shared/pipe/image.pipe'; +import { ImportExportService } from '@shared/import-export/import-export.service'; +import { EmbedImageDialogComponent, EmbedImageDialogData } from '@shared/components/image/embed-image-dialog.component'; + +export interface ImageDialogData { + readonly: boolean; + image: ImageResourceInfo; +} + +@Component({ + selector: 'tb-image-dialog', + templateUrl: './image-dialog.component.html', + styleUrls: ['./image-dialog.component.scss'] +}) +export class ImageDialogComponent extends + DialogComponent implements OnInit { + + image: ImageResourceInfo; + + readonly: boolean; + + imageFormGroup: UntypedFormGroup; + + imageChanged = false; + + imagePreviewData: UrlHolder; + + constructor(protected store: Store, + protected router: Router, + private imageService: ImageService, + private dialog: MatDialog, + private importExportService: ImportExportService, + @Inject(MAT_DIALOG_DATA) private data: ImageDialogData, + public dialogRef: MatDialogRef, + public fb: UntypedFormBuilder) { + super(store, router, dialogRef); + this.image = data.image; + this.readonly = data.readonly; + this.imagePreviewData = { + url: this.image.public ? this.image.publicLink : this.image.link + }; + } + + ngOnInit(): void { + this.imageFormGroup = this.fb.group({ + title: [this.image.title, [Validators.required]] + }); + if (this.data.readonly) { + this.imageFormGroup.disable(); + } + } + + cancel(): void { + this.dialogRef.close(this.imageChanged ? this.image : null); + } + + revertInfo(): void { + this.imageFormGroup.get('title').setValue(this.image.title); + this.imageFormGroup.markAsPristine(); + } + + saveInfo(): void { + const title: string = this.imageFormGroup.get('title').value; + const image = {...this.image, ...{title}}; + this.imageService.updateImageInfo(image).subscribe( + (saved) => { + this.image = saved; + this.imageChanged = true; + this.imageFormGroup.markAsPristine(); + } + ); + } + + downloadImage($event) { + if ($event) { + $event.stopPropagation(); + } + this.imageService.downloadImage(imageResourceType(this.image), this.image.resourceKey).subscribe(); + } + + exportImage($event) { + if ($event) { + $event.stopPropagation(); + } + this.importExportService.exportImage(imageResourceType(this.image), this.image.resourceKey); + } + + embedImage($event: Event) { + if ($event) { + $event.stopPropagation(); + } + this.dialog.open(EmbedImageDialogComponent, { + disableClose: true, + panelClass: ['tb-dialog', 'tb-fullscreen-dialog'], + data: { + image: this.image, + readonly: this.readonly + } + }).afterClosed().subscribe((result) => { + if (result) { + this.imageChanged = true; + this.image = result; + this.imagePreviewData = { + url: this.image.public ? this.image.publicLink : this.image.link + }; + } + }); + } + + updateImage($event): void { + if ($event) { + $event.stopPropagation(); + } + this.dialog.open(UploadImageDialogComponent, { + disableClose: true, + panelClass: ['tb-dialog', 'tb-fullscreen-dialog'], + data: { + image: this.image + } + }).afterClosed().subscribe((result) => { + if (result) { + this.imageChanged = true; + this.image = result; + this.imagePreviewData = { + url: this.image.public ? this.image.publicLink : this.image.link + }; + } + }); + } + +} diff --git a/ui-ngx/src/app/shared/components/image/image-gallery-dialog.component.html b/ui-ngx/src/app/shared/components/image/image-gallery-dialog.component.html new file mode 100644 index 0000000000..8e24e2ffb2 --- /dev/null +++ b/ui-ngx/src/app/shared/components/image/image-gallery-dialog.component.html @@ -0,0 +1,32 @@ + + diff --git a/ui-ngx/src/app/shared/components/image/image-gallery-dialog.component.scss b/ui-ngx/src/app/shared/components/image/image-gallery-dialog.component.scss new file mode 100644 index 0000000000..6ebda09fb5 --- /dev/null +++ b/ui-ngx/src/app/shared/components/image/image-gallery-dialog.component.scss @@ -0,0 +1,47 @@ +/** + * Copyright © 2016-2024 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 '../../../../scss/constants'; + +:host { + .tb-image-gallery-dialog { + position: relative; + padding: 24px 32px 16px 32px; + width: 100vw; + height: 100vh; + max-height: 100vh; + @media #{$mat-gt-xs} { + width: 80vw; + height: 80vh; + max-height: 80vh; + } + @media #{$mat-gt-sm} { + width: 700px; + } + @media #{$mat-gt-md} { + width: 900px; + } + @media #{$mat-gt-xl} { + width: 900px; + } + .tb-image-gallery-close { + position: absolute; + top: 12px; + right: 12px; + z-index: 1; + color: rgba(0, 0, 0, 0.38); + } + } +} diff --git a/ui-ngx/src/app/shared/components/image/image-gallery-dialog.component.ts b/ui-ngx/src/app/shared/components/image/image-gallery-dialog.component.ts new file mode 100644 index 0000000000..482fbe76a5 --- /dev/null +++ b/ui-ngx/src/app/shared/components/image/image-gallery-dialog.component.ts @@ -0,0 +1,62 @@ +/// +/// Copyright © 2016-2024 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, Inject, OnInit, SkipSelf } from '@angular/core'; +import { ErrorStateMatcher } from '@angular/material/core'; +import { MAT_DIALOG_DATA, MatDialog, MatDialogRef } from '@angular/material/dialog'; +import { Store } from '@ngrx/store'; +import { AppState } from '@core/core.state'; +import { UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms'; +import { DialogComponent } from '@shared/components/dialog.component'; +import { Router } from '@angular/router'; +import { ImageService } from '@core/http/image.service'; +import { ImageResourceInfo, imageResourceType } from '@shared/models/resource.models'; +import { + UploadImageDialogComponent, + UploadImageDialogData +} from '@shared/components/image/upload-image-dialog.component'; +import { UrlHolder } from '@shared/pipe/image.pipe'; +import { ImportExportService } from '@shared/import-export/import-export.service'; +import { EmbedImageDialogComponent, EmbedImageDialogData } from '@shared/components/image/embed-image-dialog.component'; + +@Component({ + selector: 'tb-image-gallery-dialog', + templateUrl: './image-gallery-dialog.component.html', + styleUrls: ['./image-gallery-dialog.component.scss'] +}) +export class ImageGalleryDialogComponent extends + DialogComponent implements OnInit { + + constructor(protected store: Store, + protected router: Router, + private imageService: ImageService, + private dialog: MatDialog, + public dialogRef: MatDialogRef) { + super(store, router, dialogRef); + } + + ngOnInit(): void { + } + + cancel(): void { + this.dialogRef.close(null); + } + + imageSelected(image: ImageResourceInfo): void { + this.dialogRef.close(image); + } + +} diff --git a/ui-ngx/src/app/shared/components/image/image-gallery.component.html b/ui-ngx/src/app/shared/components/image/image-gallery.component.html new file mode 100644 index 0000000000..21b10e8c66 --- /dev/null +++ b/ui-ngx/src/app/shared/components/image/image-gallery.component.html @@ -0,0 +1,397 @@ + +
+
+ +
+
+ image.gallery +
+
+ +
+
+ +
+
+ {{ 'image.include-system-images' | translate }} +
+
+ +
+ + + + +
+ +
+
+ {{ 'image.include-system-images' | translate }} +
+ +
+ + +   + + + +
+
+ +
+ + {{ translate.get('image.selected-images', {count: dataSource?.selection.selected.length}) | async }} + + + +
+
+
+
+ + + + + + + + + + + + + + +
+ {{ image.title }} +
+
+
+ + {{ 'image.name' | translate }} + + {{ image.title }} + + + + {{ 'image.created-time' | translate }} + + {{ image.createdTime | date:'yyyy-MM-dd HH:mm:ss' }} + + + + {{ 'image.resolution' | translate }} + + {{ image.descriptor.width }}x{{ image.descriptor.height }} + + + + {{ 'image.size' | translate }} + + {{ image.descriptor.size | fileSize }} + + + + {{ 'image.system' | translate }} + + {{isSystem(image) ? 'check_box' : 'check_box_outline_blank'}} + + + + + + +
+ + + + + +
+
+ + + + + + + + +
+
+
+ + + + + + + + +
+ + + + {{ 'common.loading' | translate }} +
+ + +
+
+ + +
+
+
+ +
+ + {{ 'common.loading' | translate }} + +
+
+ +
+
+
image.no-images
+
+
+ +
+
+
+ + + + +
+
+
+
+ + +
+
+ {{ item.title }} +
+
+
+
+ {{ item.title }} +
+
sys
+
+
+
{{ item.descriptor.width }}x{{ item.descriptor.height }}
+ +
{{ item.descriptor.size | fileSize }}
+
+
+
+
+ +
+
+
+
+
+
+
+
diff --git a/ui-ngx/src/app/shared/components/image/image-gallery.component.scss b/ui-ngx/src/app/shared/components/image/image-gallery.component.scss new file mode 100644 index 0000000000..cd81199053 --- /dev/null +++ b/ui-ngx/src/app/shared/components/image/image-gallery.component.scss @@ -0,0 +1,274 @@ +/** + * Copyright © 2016-2024 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 "../../../../scss/constants"; + +$tb-button-selected-color: rgb(255, 110, 64) !default; + +.tb-images { + + &.tb-dialog-mode { + position: relative; + width: 100%; + height: 100%; + .mat-toolbar.mat-mdc-table-toolbar { + padding: 0; + } + } + + .tb-images-content { + width: 100%; + height: 100%; + background: #fff; + overflow: hidden; + + &.tb-outlined-border { + box-shadow: 0 0 0 0 rgb(0 0 0 / 20%), 0 0 0 0 rgb(0 0 0 / 14%), 0 0 0 0 rgb(0 0 0 / 12%); + border: solid 1px #e0e0e0; + border-radius: 4px; + } + + .mat-mdc-table-toolbar { + &.multi-row { + &.mat-toolbar-single-row { + height: 112px; + } + .mat-mdc-slide-toggle { + display: flex; + min-height: 48px; + } + } + } + + .tb-images-title { + padding-right: 20px; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + } + + .tb-images-view-type-toolbar { + height: 55px; + min-height: 55px; + padding-right: 16px; + background-color: transparent; + box-shadow: none; + + .tb-toolbar-button { + height: 48px; + button.mat-mdc-icon-button { + margin: 0; + } + &.tb-selected { + background-color: rgba(255, 255, 255, .15); + border-bottom: $tb-button-selected-color solid 4px; + + button.mat-mdc-icon-button { + margin-bottom: -4px; + + .mat-icon { + color: $tb-button-selected-color; + fill: $tb-button-selected-color; + } + } + } + } + } + + .table-container, tb-scroll-grid { + position: relative; + } + + .tb-no-images { + position: absolute; + inset: 0; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + } + + .tb-image-card { + position: relative; + height: 100%; + border-radius: 4px; + box-shadow: 0 1px 4px 0 rgba(0, 0, 0, 0.24); + padding: 8px; + display: flex; + gap: 8px; + flex-direction: column; + cursor: pointer; + + .tb-image-card-overlay { + position: absolute; + pointer-events: none; + inset: 0; + border-radius: 4px; + z-index: 2; + display: flex; + flex-direction: column; + .tb-image-card-overlay-buttons { + width: 100%; + display: flex; + justify-content: flex-end; + align-items: center; + color: rgba(0,0,0,0.78); + opacity: 0; + transition: opacity 0.5s; + } + } + + &:hover { + .tb-image-card-overlay { + .tb-image-card-overlay-buttons { + opacity: 1; + } + } + .tb-image-preview-container { + .tb-image-preview-overlay { + background: rgba(245,245,245,0.6); + backdrop-filter: blur(4px); + .mdc-button { + opacity: 1; + } + } + } + } + + .tb-image-preview-container { + position: relative; + .tb-image-preview-overlay { + position: absolute; + inset: 0; + z-index: 1; + background: rgba(245,245,245,0); + backdrop-filter: none; + transition: all 0.5s; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + .mdc-button { + opacity: 0; + transition: opacity 0.5s; + } + } + .tb-image-preview-spacer { + margin-top: 100%; + } + .tb-image-preview { + position: absolute; + inset: 0; + width: 100%; + height: 100%; + } + } + + .tb-image-details { + min-height: 52px; + flex: 1; + display: flex; + flex-direction: column; + align-items: flex-start; + justify-content: space-between; + gap: 4px; + align-self: stretch; + .tb-image-title-container { + display: flex; + align-items: center; + gap: 8px; + align-self: stretch; + .tb-image-title { + flex: 1; + overflow: hidden; + text-overflow: ellipsis; + -webkit-line-clamp: 2; + display: -webkit-box; + -webkit-box-orient: vertical; + color: rgba(0, 0, 0, 0.76); + font-size: 12px; + font-style: normal; + font-weight: 500; + line-height: 16px; + } + .tb-image-sys { + padding: 1px 4px; + border-radius: 4px; + background: rgba(236, 236, 236, 0.64); + color: rgba(0, 0, 0, 0.54); + font-size: 11px; + font-style: normal; + font-weight: 500; + line-height: 16px; + letter-spacing: 0.017px; + } + } + .tb-image-info-container { + display: flex; + align-items: center; + gap: 8px; + align-self: stretch; + color: rgba(0, 0, 0, 0.38); + font-size: 10px; + font-style: normal; + font-weight: 400; + line-height: 16px; + .mat-divider.mat-divider-vertical { + height: 16px; + } + } + } + &.loading-cell { + .tb-image-preview-container, .tb-image-details { + background: linear-gradient(110deg, #ececec 8%, #f5f5f5 18%, #ececec 33%); + border-radius: 5px; + background-size: 200% 100%; + animation: 1s shine linear infinite; + } + } + } + + .table-container { + overflow: auto; + + .mat-sort-header-sorted .mat-sort-header-arrow { + opacity: 1 !important; + } + .mat-mdc-cell.mat-column-preview { + width: 50px; + height: 50px; + padding: 2px 12px; + } + } + + .tb-image-preview-cell { + width: 50px; + height: 50px; + } + + .tb-image-preview { + width: 50px; + height: 50px; + object-fit: contain; + border-radius: 4px; + } + } +} + +@keyframes shine { + to { + background-position-x: -200%; + } +} diff --git a/ui-ngx/src/app/shared/components/image/image-gallery.component.ts b/ui-ngx/src/app/shared/components/image/image-gallery.component.ts new file mode 100644 index 0000000000..d0451cebcd --- /dev/null +++ b/ui-ngx/src/app/shared/components/image/image-gallery.component.ts @@ -0,0 +1,702 @@ +/// +/// Copyright © 2016-2024 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 { + ImageResourceInfo, + ImageResourceInfoWithReferences, + imageResourceType, + toImageDeleteResult +} from '@shared/models/resource.models'; +import { forkJoin, merge, Observable, of, Subject, Subscription } from 'rxjs'; +import { ImageService } from '@core/http/image.service'; +import { TranslateService } from '@ngx-translate/core'; +import { PageLink, PageQueryParam } from '@shared/models/page/page-link'; +import { catchError, debounceTime, distinctUntilChanged, map, skip, takeUntil } from 'rxjs/operators'; +import { + AfterViewInit, + ChangeDetectorRef, + Component, + ElementRef, EventEmitter, HostBinding, + Input, + OnDestroy, + OnInit, Output, + ViewChild, + ViewEncapsulation +} from '@angular/core'; +import { PageComponent } from '@shared/components/page.component'; +import { MatPaginator } from '@angular/material/paginator'; +import { MatSort, SortDirection } from '@angular/material/sort'; +import { Store } from '@ngrx/store'; +import { AppState } from '@core/core.state'; +import { DialogService } from '@core/services/dialog.service'; +import { FormBuilder } from '@angular/forms'; +import { Direction, SortOrder } from '@shared/models/page/sort-order'; +import { ResizeObserver } from '@juggle/resize-observer'; +import { hidePageSizePixelValue } from '@shared/models/constants'; +import { coerceBoolean } from '@shared/decorators/coercion'; +import { ActivatedRoute, QueryParamsHandling, Router } from '@angular/router'; +import { isEqual, isNotEmptyStr, parseHttpErrorMessage } from '@core/utils'; +import { BaseData, HasId } from '@shared/models/base-data'; +import { NULL_UUID } from '@shared/models/id/has-uuid'; +import { getCurrentAuthUser } from '@core/auth/auth.selectors'; +import { Authority } from '@shared/models/authority.enum'; +import { GridEntitiesFetchFunction, ScrollGridColumns } from '@shared/components/grid/scroll-grid-datasource'; +import { ItemSizeStrategy, ScrollGridComponent } from '@shared/components/grid/scroll-grid.component'; +import { MatDialog } from '@angular/material/dialog'; +import { + UploadImageDialogComponent, + UploadImageDialogData +} from '@shared/components/image/upload-image-dialog.component'; +import { ImageDialogComponent, ImageDialogData } from '@shared/components/image/image-dialog.component'; +import { ImportExportService } from '@shared/import-export/import-export.service'; +import { ActionNotificationShow } from '@core/notification/notification.actions'; +import { + ImagesInUseDialogComponent, + ImagesInUseDialogData +} from '@shared/components/image/images-in-use-dialog.component'; +import { ImagesDatasource } from '@shared/components/image/images-datasource'; +import { EmbedImageDialogComponent, EmbedImageDialogData } from '@shared/components/image/embed-image-dialog.component'; + +interface GridImagesFilter { + search: string; + includeSystemImages: boolean; +} + +const pageGridColumns: ScrollGridColumns = { + columns: 2, + breakpoints: { + 'screen and (min-width: 2320px)': 10, + 'screen and (min-width: 2000px)': 8, + 'gt-lg': 7, + 'screen and (min-width: 1600px)': 6, + 'gt-md': 5, + 'screen and (min-width: 1120px)': 4, + 'gt-xs': 3 + } +}; + +const dialogGridColumns: ScrollGridColumns = { + columns: 2, + breakpoints: { + 'gt-md': 4, + 'gt-xs': 3 + } +}; + +@Component({ + selector: 'tb-image-gallery', + templateUrl: './image-gallery.component.html', + styleUrls: ['./image-gallery.component.scss'], + encapsulation: ViewEncapsulation.None +}) +export class ImageGalleryComponent extends PageComponent implements OnInit, OnDestroy, AfterViewInit { + + @HostBinding('style.display') + private display = 'block'; + + @HostBinding('style.width') + private width = '100%'; + + @HostBinding('style.height') + private height = '100%'; + + @Input() + @coerceBoolean() + pageMode = true; + + @Input() + @coerceBoolean() + dialogMode = false; + + @Input() + mode: 'list' | 'grid' = 'list'; + + @Input() + @coerceBoolean() + selectionMode = false; + + @Output() + imageSelected = new EventEmitter(); + + @ViewChild('searchInput') searchInputField: ElementRef; + + @ViewChild(MatPaginator) paginator: MatPaginator; + @ViewChild(MatSort) sort: MatSort; + + @ViewChild(ScrollGridComponent) gridComponent: ScrollGridComponent; + + defaultPageSize = 10; + defaultSortOrder: SortOrder = { property: 'createdTime', direction: Direction.DESC }; + hidePageSize = false; + + displayedColumns: string[]; + pageSizeOptions: number[]; + pageLink: PageLink; + + textSearchMode = false; + + dataSource: ImagesDatasource; + + textSearch = this.fb.control('', {nonNullable: true}); + includeSystemImages = false; + + gridColumns: ScrollGridColumns; + + gridImagesFetchFunction: GridEntitiesFetchFunction; + gridImagesFilter: GridImagesFilter = { + search: '', + includeSystemImages: false + }; + + gridImagesItemSizeStrategy: ItemSizeStrategy = { + defaultItemSize: 200, + itemSizeFunction: itemWidth => itemWidth + 72 + }; + + authUser = getCurrentAuthUser(this.store); + + private updateDataSubscription: Subscription; + + private widgetResize$: ResizeObserver; + private destroy$ = new Subject(); + private destroyListMode$: Subject; + + constructor(protected store: Store, + private route: ActivatedRoute, + private router: Router, + private dialog: MatDialog, + public translate: TranslateService, + private imageService: ImageService, + private dialogService: DialogService, + private importExportService: ImportExportService, + private elementRef: ElementRef, + private cd: ChangeDetectorRef, + private fb: FormBuilder) { + super(store); + + this.gridImagesFetchFunction = (pageSize, page, filter) => { + const pageLink = new PageLink(pageSize, page, filter.search, { + property: 'createdTime', + direction: Direction.DESC + }); + return this.imageService.getImages(pageLink, filter.includeSystemImages); + }; + } + + ngOnInit(): void { + this.gridColumns = this.dialogMode ? dialogGridColumns : pageGridColumns; + this.displayedColumns = this.computeDisplayedColumns(); + let sortOrder: SortOrder = this.defaultSortOrder; + this.pageSizeOptions = [this.defaultPageSize, this.defaultPageSize * 2, this.defaultPageSize * 3]; + const routerQueryParams: PageQueryParam = this.route.snapshot.queryParams; + if (this.pageMode) { + if (routerQueryParams.hasOwnProperty('direction') + || routerQueryParams.hasOwnProperty('property')) { + sortOrder = { + property: routerQueryParams?.property || this.defaultSortOrder.property, + direction: routerQueryParams?.direction || this.defaultSortOrder.direction + }; + } + } + this.pageLink = new PageLink(this.defaultPageSize, 0, null, sortOrder); + if (this.pageMode) { + if (routerQueryParams.hasOwnProperty('page')) { + this.pageLink.page = Number(routerQueryParams.page); + } + if (routerQueryParams.hasOwnProperty('pageSize')) { + this.pageLink.pageSize = Number(routerQueryParams.pageSize); + } + const textSearchParam = routerQueryParams.textSearch; + if (isNotEmptyStr(textSearchParam)) { + const decodedTextSearch = decodeURI(textSearchParam); + this.textSearchMode = true; + this.pageLink.textSearch = decodedTextSearch.trim(); + this.textSearch.setValue(decodedTextSearch, {emitEvent: false}); + } + } + if (this.mode === 'list') { + this.dataSource = new ImagesDatasource(this.imageService, null, + entity => this.deleteEnabled(entity)); + } + } + + ngOnDestroy(): void { + if (this.widgetResize$) { + this.widgetResize$.disconnect(); + } + if (this.destroyListMode$) { + this.destroyListMode$.next(); + this.destroyListMode$.complete(); + } + this.destroy$.next(); + this.destroy$.complete(); + } + + ngAfterViewInit() { + this.textSearch.valueChanges.pipe( + debounceTime(150), + distinctUntilChanged((prev, current) => + ((this.mode === 'list' ? this.pageLink.textSearch : this.gridImagesFilter.search) ?? '') === current.trim()), + takeUntil(this.destroy$) + ).subscribe(value => { + if (this.mode === 'list') { + if (this.pageMode) { + const queryParams: PageQueryParam = { + textSearch: isNotEmptyStr(value) ? encodeURI(value) : null, + page: null + }; + this.updatedRouterParamsAndData(queryParams); + } else { + this.pageLink.textSearch = isNotEmptyStr(value) ? value.trim() : null; + this.paginator.pageIndex = 0; + this.updateData(); + } + } else { + this.gridImagesFilter = { + search: isNotEmptyStr(value) ? value.trim() : null, + includeSystemImages: this.includeSystemImages + }; + this.cd.markForCheck(); + } + }); + this.updateMode(); + } + + public includeSystemImagesChanged(value: boolean) { + this.includeSystemImages = value; + this.displayedColumns = this.computeDisplayedColumns(); + this.gridImagesFilter = { + search: this.gridImagesFilter.search, + includeSystemImages: this.includeSystemImages + }; + if (this.mode === 'list') { + this.paginator.pageIndex = 0; + this.updateData(); + } else { + this.cd.markForCheck(); + } + } + + public setMode(targetMode: 'list' | 'grid') { + if (this.mode !== targetMode) { + if (this.widgetResize$) { + this.widgetResize$.disconnect(); + this.widgetResize$ = null; + } + if (this.destroyListMode$) { + this.destroyListMode$.next(); + this.destroyListMode$.complete(); + this.destroyListMode$ = null; + } + this.mode = targetMode; + if (this.mode === 'list') { + this.dataSource = new ImagesDatasource(this.imageService, null, + entity => this.deleteEnabled(entity)); + } + setTimeout(() => { + this.updateMode(); + }); + } + } + + public get isSysAdmin(): boolean { + return this.authUser.authority === Authority.SYS_ADMIN; + } + + private computeDisplayedColumns(): string[] { + let columns: string[]; + if (this.selectionMode) { + columns = ['preview', 'title']; + if (!this.isSysAdmin && this.includeSystemImages) { + columns.push('system'); + } + columns.push('imageSelect'); + } else { + columns = ['select', 'preview', 'title', 'createdTime', 'resolution', 'size']; + if (!this.isSysAdmin && this.includeSystemImages) { + columns.push('system'); + } + columns.push('actions'); + } + return columns; + } + + private updateMode() { + if (this.mode === 'list') { + this.initListMode(); + } else { + this.initGridMode(); + } + } + + private initListMode() { + this.destroyListMode$ = new Subject(); + this.widgetResize$ = new ResizeObserver(() => { + const showHidePageSize = this.elementRef.nativeElement.offsetWidth < hidePageSizePixelValue; + if (showHidePageSize !== this.hidePageSize) { + this.hidePageSize = showHidePageSize; + this.cd.markForCheck(); + } + }); + this.widgetResize$.observe(this.elementRef.nativeElement); + if (this.pageMode) { + this.route.queryParams.pipe( + skip(1), + takeUntil(this.destroyListMode$) + ).subscribe((params: PageQueryParam) => { + this.paginator.pageIndex = Number(params.page) || 0; + this.paginator.pageSize = Number(params.pageSize) || this.defaultPageSize; + this.sort.active = params.property || this.defaultSortOrder.property; + this.sort.direction = (params.direction || this.defaultSortOrder.direction).toLowerCase() as SortDirection; + const textSearchParam = params.textSearch; + if (isNotEmptyStr(textSearchParam)) { + const decodedTextSearch = decodeURI(textSearchParam); + this.textSearchMode = true; + this.pageLink.textSearch = decodedTextSearch.trim(); + this.textSearch.setValue(decodedTextSearch, {emitEvent: false}); + } else { + this.pageLink.textSearch = null; + this.textSearch.reset('', {emitEvent: false}); + } + this.updateData(); + }); + } + this.updatePaginationSubscriptions(); + this.updateData(); + } + + private initGridMode() { + + } + + private updatePaginationSubscriptions() { + if (this.updateDataSubscription) { + this.updateDataSubscription.unsubscribe(); + this.updateDataSubscription = null; + } + const sortSubscription$: Observable = this.sort.sortChange.asObservable().pipe( + map((data) => { + const direction = data.direction.toUpperCase(); + const queryParams: PageQueryParam = { + direction: (this.defaultSortOrder.direction === direction ? null : direction) as Direction, + property: this.defaultSortOrder.property === data.active ? null : data.active + }; + queryParams.page = null; + this.paginator.pageIndex = 0; + return queryParams; + }) + ); + const paginatorSubscription$ = this.paginator.page.asObservable().pipe( + map((data) => ({ + page: data.pageIndex === 0 ? null : data.pageIndex, + pageSize: data.pageSize === this.defaultPageSize ? null : data.pageSize + })) + ); + this.updateDataSubscription = (merge(sortSubscription$, paginatorSubscription$) as Observable).pipe( + takeUntil(this.destroyListMode$) + ).subscribe(queryParams => this.updatedRouterParamsAndData(queryParams)); + } + + clearSelection() { + this.dataSource.selection.clear(); + this.cd.detectChanges(); + } + + updateData() { + if (this.mode === 'list') { + this.pageLink.page = this.paginator.pageIndex; + this.pageLink.pageSize = this.paginator.pageSize; + if (this.sort.active) { + this.pageLink.sortOrder = { + property: this.sort.active, + direction: Direction[this.sort.direction.toUpperCase()] + }; + } else { + this.pageLink.sortOrder = null; + } + this.dataSource.loadEntities(this.pageLink, this.includeSystemImages); + } else { + this.gridComponent.update(); + } + } + + private imageUpdated(image: ImageResourceInfo, index = -1) { + if (this.mode === 'list') { + this.updateData(); + } else { + this.gridComponent.updateItem(index, image); + } + } + + private imageDeleted(index = -1) { + if (this.mode === 'list') { + this.updateData(); + } else { + this.gridComponent.deleteItem(index); + } + } + + enterFilterMode() { + this.textSearchMode = true; + setTimeout(() => { + this.searchInputField.nativeElement.focus(); + this.searchInputField.nativeElement.setSelectionRange(0, 0); + }, 10); + } + + exitFilterMode() { + this.textSearchMode = false; + this.textSearch.reset(); + } + + trackByEntity(index: number, entity: BaseData) { + return entity; + } + + isSystem(image?: ImageResourceInfo): boolean { + return !this.isSysAdmin && image?.tenantId?.id === NULL_UUID; + } + + readonly(image?: ImageResourceInfo): boolean { + return this.authUser.authority !== Authority.SYS_ADMIN && this.isSystem(image); + } + + deleteEnabled(image?: ImageResourceInfo): boolean { + return this.authUser.authority === Authority.SYS_ADMIN || !this.isSystem(image); + } + + deleteImage($event: Event, image: ImageResourceInfo, itemIndex = -1) { + if ($event) { + $event.stopPropagation(); + } + const title = this.translate.instant('image.delete-image-title', {imageTitle: image.title}); + const content = this.translate.instant('image.delete-image-text'); + this.dialogService.confirm(title, content, + this.translate.instant('action.no'), + this.translate.instant('action.yes')).subscribe((result) => { + if (result) { + this.imageService.deleteImage(imageResourceType(image), image.resourceKey, false, {ignoreErrors: true}).pipe( + map(() => toImageDeleteResult(image)), + catchError((err) => of(toImageDeleteResult(image, err))) + ).subscribe( + (deleteResult) => { + if (deleteResult.success) { + this.imageDeleted(itemIndex); + } else if (deleteResult.imageIsReferencedError) { + this.dialog.open(ImagesInUseDialogComponent, { + disableClose: true, + panelClass: ['tb-dialog', 'tb-fullscreen-dialog'], + data: { + multiple: false, + images: [{...image, ...{references: deleteResult.references}}] + } + }).afterClosed().subscribe((images) => { + if (images) { + this.imageService.deleteImage(imageResourceType(image), image.resourceKey, true).subscribe( + () => { + this.imageDeleted(itemIndex); + } + ); + } + }); + } else { + const errorMessageWithTimeout = parseHttpErrorMessage(deleteResult.error, this.translate); + setTimeout(() => { + this.store.dispatch(new ActionNotificationShow({message: errorMessageWithTimeout.message, type: 'error'})); + }, errorMessageWithTimeout.timeout); + } + }); + } + }); + } + + deleteImages($event: Event) { + if ($event) { + $event.stopPropagation(); + } + const selectedImages = this.dataSource.selection.selected; + if (selectedImages && selectedImages.length) { + const title = this.translate.instant('image.delete-images-title', {count: selectedImages.length}); + const content = this.translate.instant('image.delete-images-text'); + this.dialogService.confirm(title, content, + this.translate.instant('action.no'), + this.translate.instant('action.yes')).subscribe((result) => { + if (result) { + const tasks = selectedImages.map((image) => + this.imageService.deleteImage(imageResourceType(image), image.resourceKey, false, {ignoreErrors: true}).pipe( + map(() => toImageDeleteResult(image)), + catchError((err) => of(toImageDeleteResult(image, err))) + ) + ); + forkJoin(tasks).subscribe( + (deleteResults) => { + const anySuccess = deleteResults.some(res => res.success); + const referenceErrors = deleteResults.filter(res => res.imageIsReferencedError); + const otherError = deleteResults.find(res => !res.success); + if (anySuccess) { + this.updateData(); + } + if (referenceErrors?.length) { + const imagesWithReferences: ImageResourceInfoWithReferences[] = + referenceErrors.map(ref => ({...ref.image, ...{references: ref.references}})); + this.dialog.open(ImagesInUseDialogComponent, { + disableClose: true, + panelClass: ['tb-dialog', 'tb-fullscreen-dialog'], + data: { + multiple: true, + images: imagesWithReferences + } + }).afterClosed().subscribe((forceDeleteImages) => { + if (forceDeleteImages && forceDeleteImages.length) { + const forceDeleteTasks = forceDeleteImages.map((image) => + this.imageService.deleteImage(imageResourceType(image), image.resourceKey, true) + ); + forkJoin(forceDeleteTasks).subscribe( + () => { + this.updateData(); + } + ); + } + }); + } else if (otherError) { + const errorMessageWithTimeout = parseHttpErrorMessage(otherError.error, this.translate); + setTimeout(() => { + this.store.dispatch(new ActionNotificationShow({message: errorMessageWithTimeout.message, type: 'error'})); + }, errorMessageWithTimeout.timeout); + } + } + ); + } + }); + } + } + + downloadImage($event, image: ImageResourceInfo) { + if ($event) { + $event.stopPropagation(); + } + this.imageService.downloadImage(imageResourceType(image), image.resourceKey).subscribe(); + } + + exportImage($event, image: ImageResourceInfo) { + if ($event) { + $event.stopPropagation(); + } + this.importExportService.exportImage(imageResourceType(image), image.resourceKey); + } + + importImage(): void { + this.importExportService.importImage().subscribe((image) => { + if (image) { + if (this.selectionMode) { + this.imageSelected.next(image); + } else { + this.updateData(); + } + } + }); + } + + selectImage($event, image: ImageResourceInfo) { + if ($event) { + $event.stopPropagation(); + } + this.imageSelected.next(image); + } + + rowClick($event, image: ImageResourceInfo) { + if (this.selectionMode) { + this.selectImage($event, image); + } else { + if (this.deleteEnabled(image)) { + this.dataSource.selection.toggle(image); + } + } + } + + uploadImage(): void { + this.dialog.open(UploadImageDialogComponent, { + disableClose: true, + panelClass: ['tb-dialog', 'tb-fullscreen-dialog'], + data: {} + }).afterClosed().subscribe((result) => { + if (result) { + if (this.selectionMode) { + this.imageSelected.next(result); + } else { + this.updateData(); + } + } + }); + } + + editImage($event: Event, image: ImageResourceInfo, itemIndex = -1) { + if ($event) { + $event.stopPropagation(); + } + this.dialog.open(ImageDialogComponent, { + disableClose: true, + panelClass: ['tb-dialog', 'tb-fullscreen-dialog'], + data: { + image, + readonly: this.readonly(image) + } + }).afterClosed().subscribe((result) => { + if (result) { + this.imageUpdated(result, itemIndex); + } + }); + } + + embedImage($event: Event, image: ImageResourceInfo, itemIndex = -1) { + if ($event) { + $event.stopPropagation(); + } + this.dialog.open(EmbedImageDialogComponent, { + disableClose: true, + panelClass: ['tb-dialog', 'tb-fullscreen-dialog'], + data: { + image, + readonly: this.readonly(image) + } + }).afterClosed().subscribe((result) => { + if (result) { + this.imageUpdated(result, itemIndex); + } + }); + } + + protected updatedRouterParamsAndData(queryParams: object, queryParamsHandling: QueryParamsHandling = 'merge') { + if (this.pageMode) { + this.router.navigate([], { + relativeTo: this.route, + queryParams, + queryParamsHandling + }); + if (queryParamsHandling === '' && isEqual(this.route.snapshot.queryParams, queryParams)) { + this.updateData(); + } + } else { + this.updateData(); + } + } + +} diff --git a/ui-ngx/src/app/shared/components/image/image-references.component.html b/ui-ngx/src/app/shared/components/image/image-references.component.html new file mode 100644 index 0000000000..a9b6943bea --- /dev/null +++ b/ui-ngx/src/app/shared/components/image/image-references.component.html @@ -0,0 +1,54 @@ + + + + + + +
    + +
  • +
    {{ 'image.system-entities' | translate }}
    + +
  • + +
  • +
    + {{ 'tenant.tenant' | translate }} {{ entry[1].tenantName }} {{ 'image.entities' | translate }} +
    + +
  • +
    +
    +
+
+
+ + + + + + +
{{ referencedEntity.typeName }} + {{ referencedEntity.entity.name }} + {{ referencedEntity.entity.name }} +
+
+ + + diff --git a/ui-ngx/src/app/shared/components/image/image-references.component.scss b/ui-ngx/src/app/shared/components/image/image-references.component.scss new file mode 100644 index 0000000000..bef9cc61ea --- /dev/null +++ b/ui-ngx/src/app/shared/components/image/image-references.component.scss @@ -0,0 +1,92 @@ +/** + * Copyright © 2016-2024 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 "../../../../scss/constants"; + +:host { + ul.tb-references { + padding: 0; + margin: 0; + display: flex; + flex-direction: column; + gap: 12px; + } + li.tb-entities-container { + padding: 8px 12px 12px 12px; + display: flex; + flex-direction: column; + align-items: flex-start; + gap: 8px; + border-radius: 8px; + } + a.tb-reference { + color: $tb-primary-color; + font-weight: inherit; + } + .tb-entities-title { + display: flex; + gap: 8px; + color: rgba(0, 0, 0, 0.87); + font-size: 16px; + font-style: normal; + font-weight: 500; + line-height: 24px; + letter-spacing: 0.25px; + } + table.tb-entities-list-table { + position: relative; + overflow: hidden; + padding: 8px 10px 8px 4px; + border-radius: 4px; + background: #fff; + align-self: stretch; + z-index: 1; + color: rgba(0, 0, 0, 0.76); + &:before { + display: block; + height: auto; + content: ""; + position: absolute; + inset: 0; + border-radius: 4px; + border: 1px solid $tb-primary-color; + background: transparent; + opacity: 0.4; + pointer-events: none; + } + td.tb-entity-type { + white-space: nowrap; + padding-right: 20px; + font-size: 14px; + font-style: normal; + font-weight: 500; + line-height: 20px; + letter-spacing: 0.25px; + &:before { + content: "•"; + padding-left: 8px; + padding-right: 8px; + } + } + td.tb-entity-name { + width: 100%; + font-size: 14px; + font-style: normal; + font-weight: 400; + line-height: 20px; + letter-spacing: 0.2px; + } + } +} diff --git a/ui-ngx/src/app/shared/components/image/image-references.component.ts b/ui-ngx/src/app/shared/components/image/image-references.component.ts new file mode 100644 index 0000000000..e7ae17d50d --- /dev/null +++ b/ui-ngx/src/app/shared/components/image/image-references.component.ts @@ -0,0 +1,171 @@ +/// +/// Copyright © 2016-2024 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 { ChangeDetectorRef, Component, Input, OnInit } from '@angular/core'; +import { Store } from '@ngrx/store'; +import { AppState } from '@core/core.state'; +import { ImageReferences } from '@shared/models/resource.models'; +import { EntityType, entityTypeTranslations } from '@shared/models/entity-type.models'; +import { TranslateService } from '@ngx-translate/core'; +import { getEntityDetailsPageURL } from '@core/utils'; +import { getCurrentAuthUser } from '@core/auth/auth.selectors'; +import { NULL_UUID } from '@shared/models/id/has-uuid'; +import { Authority } from '@shared/models/authority.enum'; +import { Observable } from 'rxjs'; +import { EntityService } from '@core/http/entity.service'; +import { BaseData, HasId } from '@shared/models/base-data'; +import { HasTenantId } from '@shared/models/entity.models'; +import { map } from 'rxjs/operators'; +import { TbPopoverComponent } from '@shared/components/popover.component'; + +interface ReferencedEntityInfo { + entity: BaseData & HasTenantId; + typeName: string; + detailsUrl: string; +} + +interface TenantReferencedEntities { + tenantName?: string; + tenantDetailsUrl?: string; + entities: ReferencedEntityInfo[]; +} + +type ReferencedEntities = {[tenantId: string]: TenantReferencedEntities}; +type ReferencedEntitiesEntry = [string, TenantReferencedEntities]; + +@Component({ + selector: 'tb-image-references', + templateUrl: './image-references.component.html', + styleUrls: ['./image-references.component.scss'] +}) +export class ImageReferencesComponent implements OnInit { + + @Input() + references: ImageReferences; + + popoverComponent: TbPopoverComponent; + + contentReady = false; + + authUser = getCurrentAuthUser(this.store); + + simpleList = true; + + referencedEntitiesList: ReferencedEntityInfo[]; + + referencedEntitiesEntries: ReferencedEntitiesEntry[]; + + constructor(protected store: Store, + private entityService: EntityService, + private cd: ChangeDetectorRef, + private translate: TranslateService) { + } + + ngOnInit(): void { + if (this.authUser.authority === Authority.SYS_ADMIN && this.hasNonSystemEntities(this.references)) { + this.simpleList = false; + this.toReferencedEntitiesEntries(this.references).subscribe( + (entries) => { + this.referencedEntitiesEntries = entries; + this.contentReady = true; + this.cd.detectChanges(); + if (this.popoverComponent) { + Promise.resolve().then(() => { + this.popoverComponent.updatePosition(); + }); + } + } + ); + } else { + this.referencedEntitiesList = this.toReferencedEntitiesList(this.references); + this.contentReady = true; + } + } + + isSystem(tenantId: string): boolean { + return tenantId === NULL_UUID; + } + + private hasNonSystemEntities(references: ImageReferences): boolean { + for (const entityTypeStr of Object.keys(references)) { + const entities = this.references[entityTypeStr]; + if (entities.some(e => e.tenantId && e.tenantId.id && e.tenantId.id !== NULL_UUID)) { + return true; + } + } + return false; + } + + private toReferencedEntitiesList(references: ImageReferences): ReferencedEntityInfo[] { + const result: ReferencedEntityInfo[] = []; + for (const entityTypeStr of Object.keys(references)) { + const entityType = entityTypeStr as EntityType; + const entityTypeName = this.translate.instant(entityTypeTranslations.get(entityType).type); + const entities = references[entityTypeStr]; + for (const entity of entities) { + const detailsUrl = getEntityDetailsPageURL(entity.id.id, entityType); + result.push({ + entity, + typeName: entityTypeName, + detailsUrl + }); + } + } + return result; + } + + private toReferencedEntitiesEntries(references: ImageReferences): Observable { + let referencedEntities: ReferencedEntities = {}; + const referencedEntitiesList = this.toReferencedEntitiesList(references); + for (const referencedEntityInfo of referencedEntitiesList) { + const tenantId = referencedEntityInfo.entity.tenantId?.id || NULL_UUID; + let tenantEntitiesInfo = referencedEntities[tenantId]; + if (!tenantEntitiesInfo) { + tenantEntitiesInfo = { + entities: [] + }; + referencedEntities[tenantId] = tenantEntitiesInfo; + } + tenantEntitiesInfo.entities.push(referencedEntityInfo); + } + referencedEntities = Object.keys(referencedEntities).sort((tenantId1, tenantId2) => { + if (tenantId1 === NULL_UUID) { + return -1; + } else if (tenantId2 === NULL_UUID) { + return 1; + } + return 0; + }).reduce( + (obj, key) => { + obj[key] = referencedEntities[key]; + return obj; + }, + {} + ); + const tenantIds = Object.keys(referencedEntities).filter(id => id !== NULL_UUID); + return this.entityService.getEntities(EntityType.TENANT, tenantIds).pipe( + map((tenants) => { + for (const tenant of tenants) { + const tenantEntitiesInfo = referencedEntities[tenant.id.id]; + tenantEntitiesInfo.tenantName = tenant.name; + tenantEntitiesInfo.tenantDetailsUrl = getEntityDetailsPageURL(tenant.id.id, EntityType.TENANT); + } + return Object.entries(referencedEntities); + }) + ); + } + +} diff --git a/ui-ngx/src/app/shared/components/image/images-datasource.ts b/ui-ngx/src/app/shared/components/image/images-datasource.ts new file mode 100644 index 0000000000..fd92cae367 --- /dev/null +++ b/ui-ngx/src/app/shared/components/image/images-datasource.ts @@ -0,0 +1,130 @@ +/// +/// Copyright © 2016-2024 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 { CollectionViewer, DataSource, SelectionModel } from '@angular/cdk/collections'; +import { ImageResourceInfo } from '@shared/models/resource.models'; +import { BehaviorSubject, Observable, of, ReplaySubject, Subject } from 'rxjs'; +import { emptyPageData, PageData } from '@shared/models/page/page-data'; +import { ImageService } from '@core/http/image.service'; +import { EntityBooleanFunction } from '@home/models/entity/entities-table-config.models'; +import { PageLink } from '@shared/models/page/page-link'; +import { catchError, map, take, tap } from 'rxjs/operators'; + +export class ImagesDatasource implements DataSource { + private entitiesSubject: Subject; + private readonly pageDataSubject: Subject>; + + public pageData$: Observable>; + + public selection = new SelectionModel(true, []); + + public dataLoading = true; + + constructor(private imageService: ImageService, + private images: ImageResourceInfo[], + private selectionEnabledFunction: EntityBooleanFunction) { + if (this.images && this.images.length) { + this.entitiesSubject = new BehaviorSubject(this.images); + } else { + this.entitiesSubject = new BehaviorSubject([]); + this.pageDataSubject = new BehaviorSubject>(emptyPageData()); + this.pageData$ = this.pageDataSubject.asObservable(); + } + } + + connect(collectionViewer: CollectionViewer): + Observable> { + return this.entitiesSubject.asObservable(); + } + + disconnect(collectionViewer: CollectionViewer): void { + this.entitiesSubject.complete(); + if (this.pageDataSubject) { + this.pageDataSubject.complete(); + } + } + + reset() { + this.entitiesSubject.next([]); + if (this.pageDataSubject) { + this.pageDataSubject.next(emptyPageData()); + } + } + + loadEntities(pageLink: PageLink, includeSystemImages = false): Observable> { + this.dataLoading = true; + const result = new ReplaySubject>(); + this.fetchEntities(pageLink, includeSystemImages).pipe( + tap(() => { + this.selection.clear(); + }), + catchError(() => of(emptyPageData())), + ).subscribe( + (pageData) => { + this.entitiesSubject.next(pageData.data); + this.pageDataSubject.next(pageData); + result.next(pageData); + this.dataLoading = false; + } + ); + return result; + } + + fetchEntities(pageLink: PageLink, includeSystemImages = false): Observable> { + return this.imageService.getImages(pageLink, includeSystemImages); + } + + isAllSelected(): Observable { + const numSelected = this.selection.selected.length; + return this.entitiesSubject.pipe( + map((entities) => numSelected === entities.length) + ); + } + + isEmpty(): Observable { + return this.entitiesSubject.pipe( + map((entities) => !entities.length) + ); + } + + total(): Observable { + return this.pageDataSubject.pipe( + map((pageData) => pageData.totalElements) + ); + } + + masterToggle() { + this.entitiesSubject.pipe( + tap((entities) => { + const numSelected = this.selection.selected.length; + if (numSelected === this.selectableEntitiesCount(entities)) { + this.selection.clear(); + } else { + entities.forEach(row => { + if (this.selectionEnabledFunction(row)) { + this.selection.select(row); + } + }); + } + }), + take(1) + ).subscribe(); + } + + private selectableEntitiesCount(entities: Array): number { + return entities.filter((entity) => this.selectionEnabledFunction(entity)).length; + } +} diff --git a/ui-ngx/src/app/shared/components/image/images-in-use-dialog.component.html b/ui-ngx/src/app/shared/components/image/images-in-use-dialog.component.html new file mode 100644 index 0000000000..6bbc62ade2 --- /dev/null +++ b/ui-ngx/src/app/shared/components/image/images-in-use-dialog.component.html @@ -0,0 +1,82 @@ + +

{{title}}

+
+
+ +
+ + + + + + + + + + + + + + + {{ image.title }} + + + + + + {{ 'image.name' | translate }} + + + {{ translate.get('image.selected-images', {count: dataSource.selection.selected.length}) | async }} + + + + {{ image.title }} + + + + + + + + + + +
+
+
+
+
+ + +
+ + +
+
diff --git a/ui-ngx/src/app/shared/components/image/images-in-use-dialog.component.scss b/ui-ngx/src/app/shared/components/image/images-in-use-dialog.component.scss new file mode 100644 index 0000000000..682f3a1d0c --- /dev/null +++ b/ui-ngx/src/app/shared/components/image/images-in-use-dialog.component.scss @@ -0,0 +1,40 @@ +/** + * Copyright © 2016-2024 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 { + .tb-images-in-use-content { + display: flex; + flex-direction: column; + gap: 24px; + &.multiple { + gap: 16px; + } + .table-container { + overflow: auto; + .mat-mdc-cell.mat-column-preview { + width: 50px; + height: 50px; + padding: 2px 12px; + display: block; + } + } + .tb-image-preview { + width: 50px; + height: 50px; + object-fit: contain; + border-radius: 4px; + } + } +} diff --git a/ui-ngx/src/app/shared/components/image/images-in-use-dialog.component.ts b/ui-ngx/src/app/shared/components/image/images-in-use-dialog.component.ts new file mode 100644 index 0000000000..20b551c872 --- /dev/null +++ b/ui-ngx/src/app/shared/components/image/images-in-use-dialog.component.ts @@ -0,0 +1,114 @@ +/// +/// Copyright © 2016-2024 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, Inject, OnInit, Renderer2, ViewContainerRef } from '@angular/core'; +import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; +import { Store } from '@ngrx/store'; +import { AppState } from '@core/core.state'; +import { DialogComponent } from '@shared/components/dialog.component'; +import { Router } from '@angular/router'; +import { ImageReferences, ImageResourceInfo, ImageResourceInfoWithReferences } from '@shared/models/resource.models'; +import { ImagesDatasource } from '@shared/components/image/images-datasource'; +import { MatButton } from '@angular/material/button'; +import { TbPopoverService } from '@shared/components/popover.service'; +import { ImageReferencesComponent } from '@shared/components/image/image-references.component'; +import { TranslateService } from '@ngx-translate/core'; + +export interface ImagesInUseDialogData { + multiple: boolean; + images: ImageResourceInfoWithReferences[]; +} + +@Component({ + selector: 'tb-images-in-use-dialog', + templateUrl: './images-in-use-dialog.component.html', + styleUrls: ['./images-in-use-dialog.component.scss'] +}) +export class ImagesInUseDialogComponent extends + DialogComponent implements OnInit { + + title: string; + message: string; + + references: ImageReferences; + + dataSource: ImagesDatasource; + + constructor(protected store: Store, + protected router: Router, + @Inject(MAT_DIALOG_DATA) public data: ImagesInUseDialogData, + public dialogRef: MatDialogRef, + public translate: TranslateService, + private renderer: Renderer2, + private viewContainerRef: ViewContainerRef, + private popoverService: TbPopoverService) { + super(store, router, dialogRef); + } + + ngOnInit(): void { + if (this.data.multiple) { + this.title = this.translate.instant('image.images-are-in-use'); + this.message = this.translate.instant('image.images-are-in-use-text'); + this.dataSource = new ImagesDatasource(null, this.data.images, entity => true); + } else { + this.title = this.translate.instant('image.image-is-in-use'); + this.message = this.translate.instant('image.image-is-in-use-text', {title: this.data.images[0].title}); + this.references = this.data.images[0].references; + } + } + + cancel() { + this.dialogRef.close(null); + } + + delete() { + if (this.data.multiple) { + this.dialogRef.close(this.dataSource.selection.selected); + } else { + this.dialogRef.close(this.data.images); + } + } + + toggleShowReferences($event: Event, image: ImageResourceInfoWithReferences, referencesButton: MatButton) { + if ($event) { + $event.stopPropagation(); + } + const trigger = referencesButton._elementRef.nativeElement; + if (this.popoverService.hasPopover(trigger)) { + this.popoverService.hidePopover(trigger); + } else { + const referencesPopover = this.popoverService.displayPopover(trigger, this.renderer, + this.viewContainerRef, ImageReferencesComponent, 'top', true, null, + { + references: image.references + }, {}, {}, {}, + false, + visible => { + const addClasses = + visible ? 'mdc-button--unelevated mat-mdc-unelevated-button' : 'mdc-button--outlined mat-mdc-outlined-button'; + const removeClasses = + visible ? 'mdc-button--outlined mat-mdc-outlined-button' : 'mdc-button--unelevated mat-mdc-unelevated-button'; + addClasses.split(' ').forEach(clazz => { + this.renderer.addClass(trigger, clazz); + }); + removeClasses.split(' ').forEach(clazz => { + this.renderer.removeClass(trigger, clazz); + }); + }); + referencesPopover.tbComponentRef.instance.popoverComponent = referencesPopover; + } + } +} diff --git a/ui-ngx/src/app/shared/components/image/multiple-gallery-image-input.component.html b/ui-ngx/src/app/shared/components/image/multiple-gallery-image-input.component.html new file mode 100644 index 0000000000..4a60b29ba9 --- /dev/null +++ b/ui-ngx/src/app/shared/components/image/multiple-gallery-image-input.component.html @@ -0,0 +1,111 @@ + +
+ +
+
+
+ {{ 'image-input.images' | translate }} [{{ $index }}] +
+
+ drag_indicator +
+
+ +
+
+ +
+
+
+
{{ 'image-input.no-images' | translate }}
+
+
+
+ +
+
+
+ + +
+
+
+ + +
+
+
+ + +
{{ 'image.no-image-selected' | translate }}
+
diff --git a/ui-ngx/src/app/shared/components/image/multiple-gallery-image-input.component.scss b/ui-ngx/src/app/shared/components/image/multiple-gallery-image-input.component.scss new file mode 100644 index 0000000000..f6e05ca2d9 --- /dev/null +++ b/ui-ngx/src/app/shared/components/image/multiple-gallery-image-input.component.scss @@ -0,0 +1,225 @@ +/** + * Copyright © 2016-2024 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 "../../../../scss/constants"; + +$imagesContainerHeight: 106px !default; +$selectContainerHeight: 96px !default; +$previewSize: 64px !default; + +.image-card { + margin-bottom: 8px; + &.image-dnd-placeholder { + height: 82px; + width: 146px; + border: 2px dashed rgba(0, 0, 0, 0.2); + background: rgba(0, 0, 0, 0.1); + border-radius: 4px; + } + &.image-dragging { + display: none !important; + } + .image-title { + font-size: 11px; + font-weight: 400; + line-height: 14px; + color: rgba(0, 0, 0, 0.6); + padding-bottom: 4px; + } + + .image-content-container { + background: #FFFFFF; + border: 1px solid rgba(0, 0, 0, 0.2); + border-radius: 4px; + height: $previewSize; + } + + .tb-image-preview { + width: auto; + max-width: $previewSize - 2px; + height: auto; + max-height: $previewSize - 2px; + } + + .tb-image-preview-container { + position: relative; + width: $previewSize; + height: $previewSize; + margin-top: -1px; + margin-bottom: -1px; + border: 1px solid rgba(0, 0, 0, 0.54); + + .tb-image-preview { + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + } + } + + .tb-image-action-container { + position: relative; + height: $previewSize - 2px; + display: flex; + align-items: center; + justify-content: center; + min-width: 40px; + } +} + +:host { + .tb-container { + margin-top: 0; + padding: 0 0 16px; + display: flex; + flex-direction: column; + gap: 8px; + label.tb-title { + display: block; + padding-bottom: 0; + } + } + + .images-container { + padding: 12px 12px 4px; + background: rgba(0, 0, 0, 0.03); + border-radius: 4px; + flex-wrap: wrap; + margin-bottom: 8px; + &.no-images { + height: $imagesContainerHeight; + padding-bottom: 12px; + align-items: center; + justify-content: center; + } + } + + .no-images-prompt { + font-size: 18px; + color: rgba(0, 0, 0, 0.54); + } + + .tb-image-select-container { + width: 100%; + height: $selectContainerHeight; + border-radius: 4px; + border: 1px solid rgba(0, 0, 0, 0.12); + display: flex; + align-items: center; + + .tb-image-container { + width: $selectContainerHeight - 1px; + height: $selectContainerHeight - 2px; + display: flex; + justify-content: center; + align-items: center; + border-radius: 4px; + border-right: 1px solid rgba(0, 0, 0, 0.12); + background: #fff; + overflow: hidden; + + .tb-image-preview { + width: auto; + max-width: $selectContainerHeight - 2px; + height: auto; + max-height: $selectContainerHeight - 2px; + } + + .tb-no-image { + text-align: center; + color: rgba(0, 0, 0, 0.38); + font-size: 12px; + font-style: normal; + font-weight: 400; + line-height: 16px; + letter-spacing: 0.4px; + } + } + + .tb-image-info-container { + display: flex; + flex: 1; + align-self: stretch; + padding: 0 8px; + justify-content: flex-end; + align-items: center; + gap: 4px; + + .tb-external-image-container { + display: flex; + flex: 1; + align-self: stretch; + padding: 16px 8px 0 16px; + flex-direction: column; + align-items: flex-start; + gap: 4px; + .tb-external-link-label { + color: rgba(0, 0, 0, 0.54); + font-size: 12px; + font-style: normal; + font-weight: 400; + line-height: 16px; + letter-spacing: 0.4px; + } + .tb-external-link-input-container { + display: flex; + justify-content: flex-end; + align-items: center; + gap: 4px; + align-self: stretch; + .tb-inline-field { + width: 100%; + } + .tb-image-decline-btn { + color: rgba(0,0,0,0.38); + } + } + } + + } + + .tb-image-select-buttons-container { + display: flex; + flex: 1; + align-self: stretch; + padding: 8px; + gap: 8px; + justify-content: center; + align-items: flex-start; + .tb-image-select-button { + width: 100%; + height: 100%; + align-self: stretch; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + gap: 4px; + padding: 8px; + line-height: normal; + font-size: 12px; + @media #{$mat-gt-xs} { + padding: 16px; + } + .mat-icon { + width: 24px; + height: 24px; + font-size: 24px; + margin: 0; + } + } + } + } +} diff --git a/ui-ngx/src/app/shared/components/image/multiple-gallery-image-input.component.ts b/ui-ngx/src/app/shared/components/image/multiple-gallery-image-input.component.ts new file mode 100644 index 0000000000..260a7667f8 --- /dev/null +++ b/ui-ngx/src/app/shared/components/image/multiple-gallery-image-input.component.ts @@ -0,0 +1,181 @@ +/// +/// Copyright © 2016-2024 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 { ChangeDetectorRef, Component, forwardRef, Input, OnDestroy, Renderer2, ViewContainerRef } from '@angular/core'; +import { PageComponent } from '@shared/components/page.component'; +import { Store } from '@ngrx/store'; +import { AppState } from '@core/core.state'; +import { ControlValueAccessor, FormControl, NG_VALUE_ACCESSOR, } from '@angular/forms'; +import { moveItemInArray } from '@angular/cdk/drag-drop'; +import { DndDropEvent } from 'ngx-drag-drop'; +import { isUndefined } from '@core/utils'; +import { coerceBoolean } from '@shared/decorators/coercion'; +import { ImageLinkType } from '@shared/components/image/gallery-image-input.component'; +import { TbPopoverService } from '@shared/components/popover.service'; +import { MatButton } from '@angular/material/button'; +import { ImageGalleryComponent } from '@shared/components/image/image-gallery.component'; +import { prependTbImagePrefixToUrls, removeTbImagePrefixFromUrls } from '@shared/models/resource.models'; + +@Component({ + selector: 'tb-multiple-gallery-image-input', + templateUrl: './multiple-gallery-image-input.component.html', + styleUrls: ['./multiple-gallery-image-input.component.scss'], + providers: [ + { + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => MultipleGalleryImageInputComponent), + multi: true + } + ] +}) +export class MultipleGalleryImageInputComponent extends PageComponent implements OnDestroy, ControlValueAccessor { + + @Input() + label: string; + + @Input() + @coerceBoolean() + required = false; + + @Input() + disabled: boolean; + + imageUrls: string[]; + + ImageLinkType = ImageLinkType; + + linkType: ImageLinkType = ImageLinkType.none; + + externalLinkControl = new FormControl(null); + + dragIndex: number; + + private propagateChange = null; + + constructor(protected store: Store, + private cd: ChangeDetectorRef, + private renderer: Renderer2, + private viewContainerRef: ViewContainerRef, + private popoverService: TbPopoverService) { + super(store); + } + + ngOnDestroy() { + } + + registerOnChange(fn: any): void { + this.propagateChange = fn; + } + + registerOnTouched(fn: any): void { + } + + setDisabledState(isDisabled: boolean): void { + this.disabled = isDisabled; + } + + writeValue(value: string[]): void { + this.reset(); + this.imageUrls = removeTbImagePrefixFromUrls(value); + } + + private updateModel() { + this.cd.markForCheck(); + this.propagateChange(prependTbImagePrefixToUrls(this.imageUrls)); + } + + private reset() { + this.linkType = ImageLinkType.none; + this.externalLinkControl.setValue(null, {emitEvent: false}); + } + + clearImage(index: number) { + this.imageUrls.splice(index, 1); + this.updateModel(); + } + + setLink($event: Event) { + if ($event) { + $event.stopPropagation(); + } + this.linkType = ImageLinkType.external; + } + + declineLink($event: Event) { + if ($event) { + $event.stopPropagation(); + } + this.reset(); + } + + applyLink($event: Event) { + if ($event) { + $event.stopPropagation(); + } + this.imageUrls.push(this.externalLinkControl.value); + this.reset(); + this.updateModel(); + } + + toggleGallery($event: Event, browseGalleryButton: MatButton) { + if ($event) { + $event.stopPropagation(); + } + const trigger = browseGalleryButton._elementRef.nativeElement; + if (this.popoverService.hasPopover(trigger)) { + this.popoverService.hidePopover(trigger); + } else { + const ctx: any = { + pageMode: false, + popoverMode: true, + mode: 'grid', + selectionMode: true + }; + const imageGalleryPopover = this.popoverService.displayPopover(trigger, this.renderer, + this.viewContainerRef, ImageGalleryComponent, 'top', true, null, + ctx, + {}, + {}, {}, true); + imageGalleryPopover.tbComponentRef.instance.imageSelected.subscribe((image) => { + imageGalleryPopover.hide(); + this.imageUrls.push(image.link); + this.updateModel(); + }); + } + } + + imageDragStart(index: number) { + setTimeout(() => { + this.dragIndex = index; + this.cd.markForCheck(); + }); + } + + imageDragEnd() { + this.dragIndex = -1; + this.cd.markForCheck(); + } + + imageDrop(event: DndDropEvent) { + let index = event.index; + if (isUndefined(index)) { + index = this.imageUrls.length; + } + moveItemInArray(this.imageUrls, this.dragIndex, index); + this.dragIndex = -1; + this.updateModel(); + } +} diff --git a/ui-ngx/src/app/shared/components/image/upload-image-dialog.component.html b/ui-ngx/src/app/shared/components/image/upload-image-dialog.component.html new file mode 100644 index 0000000000..5255234ba8 --- /dev/null +++ b/ui-ngx/src/app/shared/components/image/upload-image-dialog.component.html @@ -0,0 +1,65 @@ + +
+ +

{{ ( uploadImage ? 'image.upload-image' : 'image.update-image' ) | translate }}

+ + +
+ + +
+
+
+ + + + image.name + + + {{ 'image.name-required' | translate }} + + +
+
+
+ + +
+
diff --git a/ui-ngx/src/app/shared/components/image/upload-image-dialog.component.ts b/ui-ngx/src/app/shared/components/image/upload-image-dialog.component.ts new file mode 100644 index 0000000000..ae022615a1 --- /dev/null +++ b/ui-ngx/src/app/shared/components/image/upload-image-dialog.component.ts @@ -0,0 +1,115 @@ +/// +/// Copyright © 2016-2024 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, Inject, OnInit, SkipSelf } from '@angular/core'; +import { ErrorStateMatcher } from '@angular/material/core'; +import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; +import { Store } from '@ngrx/store'; +import { AppState } from '@core/core.state'; +import { + FormGroupDirective, + NgForm, + UntypedFormBuilder, + UntypedFormControl, + UntypedFormGroup, + Validators +} from '@angular/forms'; +import { DialogComponent } from '@shared/components/dialog.component'; +import { Router } from '@angular/router'; +import { ImageService } from '@core/http/image.service'; +import { ImageResourceInfo, imageResourceType } from '@shared/models/resource.models'; +import { getCurrentAuthState } from '@core/auth/auth.selectors'; + +export interface UploadImageDialogData { + image?: ImageResourceInfo; +} + +@Component({ + selector: 'tb-upload-image-dialog', + templateUrl: './upload-image-dialog.component.html', + providers: [{provide: ErrorStateMatcher, useExisting: UploadImageDialogComponent}], + styleUrls: [] +}) +export class UploadImageDialogComponent extends + DialogComponent implements OnInit, ErrorStateMatcher { + + uploadImageFormGroup: UntypedFormGroup; + + uploadImage = true; + + submitted = false; + + maxResourceSize = getCurrentAuthState(this.store).maxResourceSize; + + constructor(protected store: Store, + protected router: Router, + private imageService: ImageService, + @Inject(MAT_DIALOG_DATA) public data: UploadImageDialogData, + @SkipSelf() private errorStateMatcher: ErrorStateMatcher, + public dialogRef: MatDialogRef, + public fb: UntypedFormBuilder) { + super(store, router, dialogRef); + } + + ngOnInit(): void { + this.uploadImage = !this.data?.image; + this.uploadImageFormGroup = this.fb.group({ + file: [this.data?.image?.link, [Validators.required]] + }); + if (this.uploadImage) { + this.uploadImageFormGroup.addControl('title', this.fb.control(null, [Validators.required])); + } + } + + imageFileNameChanged(fileName: string) { + if (this.uploadImage) { + const titleControl = this.uploadImageFormGroup.get('title'); + if (!titleControl.value || !titleControl.touched) { + titleControl.setValue(fileName); + } + } + } + + isErrorState(control: UntypedFormControl | null, form: FormGroupDirective | NgForm | null): boolean { + const originalErrorState = this.errorStateMatcher.isErrorState(control, form); + const customErrorState = !!(control && control.invalid && this.submitted); + return originalErrorState || customErrorState; + } + + cancel(): void { + this.dialogRef.close(null); + } + + upload(): void { + this.submitted = true; + const file: File = this.uploadImageFormGroup.get('file').value; + if (this.uploadImage) { + const title: string = this.uploadImageFormGroup.get('title').value; + this.imageService.uploadImage(file, title).subscribe( + (res) => { + this.dialogRef.close(res); + } + ); + } else { + const image = this.data.image; + this.imageService.updateImage(imageResourceType(image), image.resourceKey, file).subscribe( + (res) => { + this.dialogRef.close(res); + } + ); + } + } +} diff --git a/ui-ngx/src/app/shared/components/js-func.component.html b/ui-ngx/src/app/shared/components/js-func.component.html index 41e834668e..e072759213 100644 --- a/ui-ngx/src/app/shared/components/js-func.component.html +++ b/ui-ngx/src/app/shared/components/js-func.component.html @@ -1,6 +1,6 @@
+ (selectedTabChange)="onTimewindowTypeChange()" [(selectedIndex)]="timewindow.selectedTab">
@@ -215,6 +216,7 @@ [(hideFlag)]="timewindow.hideAggInterval" (hideFlagChange)="onHideAggIntervalChanged()" [min]="minHistoryAggInterval()" [max]="maxHistoryAggInterval()" + useCalendarIntervals predefinedName="aggregation.group-interval"> diff --git a/ui-ngx/src/app/shared/components/time/timewindow-panel.component.scss b/ui-ngx/src/app/shared/components/time/timewindow-panel.component.scss index 70f43f410c..25d11f510f 100644 --- a/ui-ngx/src/app/shared/components/time/timewindow-panel.component.scss +++ b/ui-ngx/src/app/shared/components/time/timewindow-panel.component.scss @@ -1,5 +1,5 @@ /** - * Copyright © 2016-2023 The Thingsboard Authors + * Copyright © 2016-2024 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. diff --git a/ui-ngx/src/app/shared/components/time/timewindow-panel.component.ts b/ui-ngx/src/app/shared/components/time/timewindow-panel.component.ts index f4a2e8b916..0c0dd4294c 100644 --- a/ui-ngx/src/app/shared/components/time/timewindow-panel.component.ts +++ b/ui-ngx/src/app/shared/components/time/timewindow-panel.component.ts @@ -1,5 +1,5 @@ /// -/// Copyright © 2016-2023 The Thingsboard Authors +/// Copyright © 2016-2024 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. @@ -20,6 +20,7 @@ import { AggregationType, DAY, HistoryWindowType, + QuickTimeInterval, quickTimeIntervalPeriod, RealtimeWindowType, Timewindow, @@ -186,6 +187,38 @@ export class TimewindowPanelComponent extends PageComponent implements OnInit { this.timewindowForm.get('aggregation.limit').updateValueAndValidity({emitEvent: false}); } + onTimewindowTypeChange() { + this.timewindowForm.markAsDirty(); + const timewindowFormValue = this.timewindowForm.getRawValue(); + if (this.timewindow.selectedTab === TimewindowType.REALTIME) { + if (timewindowFormValue.history.historyType !== HistoryWindowType.FIXED) { + this.timewindowForm.get('realtime').patchValue({ + realtimeType: Object.keys(RealtimeWindowType).includes(HistoryWindowType[timewindowFormValue.history.historyType]) ? + RealtimeWindowType[HistoryWindowType[timewindowFormValue.history.historyType]] : + timewindowFormValue.realtime.realtimeType, + timewindowMs: timewindowFormValue.history.timewindowMs, + quickInterval: timewindowFormValue.history.quickInterval.startsWith('CURRENT') ? + timewindowFormValue.history.quickInterval : timewindowFormValue.realtime.quickInterval + }); + setTimeout(() => this.timewindowForm.get('realtime.interval').patchValue(timewindowFormValue.history.interval)); + } + } else { + this.timewindowForm.get('history').patchValue({ + historyType: HistoryWindowType[RealtimeWindowType[timewindowFormValue.realtime.realtimeType]], + timewindowMs: timewindowFormValue.realtime.timewindowMs, + quickInterval: timewindowFormValue.realtime.quickInterval + }); + setTimeout(() => this.timewindowForm.get('history.interval').patchValue(timewindowFormValue.realtime.interval)); + } + this.timewindowForm.patchValue({ + aggregation: { + type: timewindowFormValue.aggregation.type, + limit: timewindowFormValue.aggregation.limit + }, + timezone: timewindowFormValue.timezone + }); + } + update() { const timewindowFormValue = this.timewindowForm.getRawValue(); this.timewindow.realtime = { diff --git a/ui-ngx/src/app/shared/components/time/timewindow.component.html b/ui-ngx/src/app/shared/components/time/timewindow.component.html index a53ea656fc..622f5654d9 100644 --- a/ui-ngx/src/app/shared/components/time/timewindow.component.html +++ b/ui-ngx/src/app/shared/components/time/timewindow.component.html @@ -1,6 +1,6 @@ }-~*nx2?$h0TM zWPW9-SJy4nHOtK0m~EInRlSLk<7{48W^DLN`qHy8Z+ zh2ws*41(5uUqC0twVRono12=Zw22!T4S^{P1RK@Ju;$RoIFM;JP(S${VDsc9G1_D3oKlHT2=p-RC1Ioh?3k(ZY((4P>v}k|No=wK|l#4XGR(4LqyBWT>a~p zFb9WKO$ZzE+Z>=7aoX>AA7-Tn=n(q*`kps1)!$7&3!&`<#q0;gHOE8>6P zx85TdJ^`6SpM%dci&ub-yFTsEkt3}rPSF4Xf_aUAhS4bsOkiTzfLCTFpmO^!&~pfq zEt~q=X!nhEl$^#P+y5(2Ut1+`_3BkZ=)_|N>3AE;*CT8<&fhG3j7PZ3qm)aHBkMbE zCwLm^=z_5%FI~E%pB3hXER7QM1Ub2$fq{~``d9NLyQ{jo-N@|_+4G$`b>9mJIg#=} zblS1!a3`*JqQk~r4mJzX%S=i^_*7S=q{vA;KiO@-ZFMxC33T%z>#0ZarbWJR(sIvyf#%d@Jk#k8% zNYvESK%$051TO%(hL2_=UXO=|2T2%6M}QROf23jKU&-btH9@+qW^+Bdk1%0_juU z<>p3Wz67l{fWG*6dWJpQwp@JH(`>g*WLszrdP@)wuDG}qB_=W+fD*Z)vJ#SgUAlw2 zw?9P1ua*$`>eVao6F5WN-ds-(4OOG3{xm#?dl6nKAt7<#zyW$v$|xN;!k}j?Kg4CB z_ajg`9$Vg~zy)imJWsvLe}8tnIT#&%9VxZHfh%I%j-pZ=U?*K@&5}!TLIT5!7G`#h z*!$q^AQTuHzL8~sDiYF)bVp;1@lzggT{%YdEY1LZ^!58tLV7WwO~T&6>VUAY&~42b z1!T^iez{S?4bxIKl=ibOw~jk zr=!sg;OE=Td7C`ZkpO-MoASWZY8DMKuzm4<(C9h|bzv4z9Q_#)Pgg#io%2Azf3`3J z+ya5%Aj4tC#tB;o)7Q~veRK0wI1pgu$fB0PbQl;Hw#PN1+bSiBX)Fz!F-$7?VVD8T z8{rGx2?(CE1rvZ=>%M+{E**bMBsD$V!o>_n^M%`YlYb|1)&B< zP=@pcf};Par;)anOR>93+c)FrA`%s@{bhI#f>LE>S4=WwW%nwb5*01!+hb3}Zkejs zy_=;f#!Y(b1j=ydjyl#3GAHx`GLnx`*`w}VgD6(5)`&h9k?v)9I2;8)tXcv+Y1TFc zb*-6+NdYu4hgeh{@7?1wZ=1I5n3|Yy#RL!yW2l;5bCM#mHB<}T`POk5v&>LOGso59 zW8|Q0Lbi*-5K&)076|&qQ>S7v78iA%zl}YJWd5VEQ9p$_`wgbzc&e}XZM~8ZAMuFL zaTmKRy?gP3qNxl8JtjblodlnIQ6G%tiXhC)z({6J1|?>T8y)J0AalY*WlQvh|8r^r zb*SJD`-16|n!<~>UOWdjJtR1;f7CRBdTj~-xTlyBtZT8d!osg>22D*&P=cC% zKZWEHKVAaF>Z!my*IB0`#lzLZa$h||X z2fw;y&|}l1Wy}A+KHmQ!%CJr;k`RgFpd^JFPK!Nrwi+L?XQfgryg9%UEB4uz*h(>OJ0tl@JM;eg;m$h;Evb2 ze_b!5B`iE#rJEteJYz4^s5S*(3Dre(bX*)pQcEswe=K6FW1lK8H8(b<{D(L(8qt!H zG&OUb*_R8srm|l}#R9)GZO}90h)Y}ko%xOlHV)?+j^J;l^|DfI^es(bAB3;|zdM}& z$DR4_^sDOoB*Wn-puSO7UJmCNcEH@B(($@ly}>MMuU^02e?manI%{BH;6KV5Up|6{ z-~9-FLKUs8dB7Uc3?o^q=ilj_0)wJlWpH@&&)}enRvO?YCQ5*vE;CQOl29)~P7aVt zSBcQMxa`~1JtCzNszz~23W_E)#OQv|O#k}!ZF*12Z=&YSwZNKUVK=&YlTg*qITmr4 z5TXGWzG7d+V>^H}AuSeYousC&VFl;A3Ii~t8ceH>larqckO~_FeFWPaQ(PNs>tpbV zLDdyDh>@I~wKb~7Z3iIlfHo7tK3fnpFgHLD?aDEsP#Q<|fXoff$941N|F@b)Oky!X zNlQ9%*%YDwfy&z7hL#QbI4dnB-H5XRv3QHX+y05_r_jdXv1d0Yj|iR`Dkgs#s+SRK!*~NfDamru>Djjsz zANEHmaxexie*QlMjm1UtYjUzS*Tr8Q3}M&C=*k%%5sT91!Yh0pcCCB`Ny$X6eMHXS zn1hTG^(@eQLNNQ&dv}nh4yvJH0(>655qN|E_-?>gJ-icdy`^P9 z@Fh$Co`t#zJe5Z5V10fgeQ>=BA*wAub(boRB_`0Rs!_)IGN-H!PsJqX^M!ByS zh;Id`iQx<8M7enMFsFeZ9j-PKyK;1QDLwHZoMsI{y8*3@FbnbYtV9@=@H;+=H^KCK z`S0;l#8r}Ye}`Ov2P+Kw6+9P!r1Y^s7(jviR8vE+W3axU>=trae2c0M1`zOp0qQu1 zb`~+d;KK)y;J#K=B-9FYTKI8EPbqtSBLB3JMYz2fToeasc-Vw1$9S!XYaSXqT(DJFfB*{Q0AZy(7FQqqY%Iv2VA(1W@7RO(U@^1Qf z{+~G#((!W51wxKJW)?-N6O6;uZ$=d*|`qImn?a8k-rz>b|eyO4FWRj&epM+H4P zh=6?!a=%#nHQ$S;z~Iuq+nhFyc#Pog7GV*5mVv>jDv%z`t7XF~Bx~*bJ278Mu?kU6 zt4Njw1@yU7^ho|;KUZfkLgTONo;3P|X&)qZ2fYW7M8O&h#~MK(0s+_T!ayT@y^&QzJR}9 zdtnf855a=Dz0(20P_6tsmq0O8*Ev&Z>RqAiBCb;O0iOe2XzHx%%c{iZEpk$t8ODB) zCQ(fyqs=n>^MGZ7A>E4CxjgK?t5yGXQ{uWJ-`=sB{)JOJ&TV+zZWZ-+f0OjaP;m&z z7ZNY_t~Tgjp!(sH;Ky6UKrpRY%F4ie3R}^&e<4Wq(w-6tz)N*?bv5^R(NcoI_aYd5 z9n4FF-B$Ahso&@3PBzBN{QH5z0s?M=HPL&=D+x&wJ2x$`uI0keQS@*?p@O92=_Atv z4Bm?yFpI=8>p*dC3m$_=4Zh1;7z&&_Bc`%fHe}b zI3knw}LfmjxQ-2}lJ76jh6@o-_e(A(P!gG&?* zz+zBp;0XhvGXEC6l?c7#zX~y4{Ql*OA)FWy%Gtla0hj`h1Vz@vg@uJgA6I8oWB3j& zIf5U0LTI!)s;a!bz)zYO9bJOF&*(BcJG(etfE4;j^mp6{TPKB`9UUDx>0iHkg~h-N z`k<@p+QA*5tDiV{@VYuto0dZVN1=$Hl9KY0WtjW($AYl60}_Nu>j;uAiYK8e5sY42+yvCIs1~`xpK7QVc|e>WPyHOcY+!&G zjc(ia2cUz-=DCu^PYU;?CS@vK?&dw-qy$C&|kw*V;F}GAz|m3DA7Wopn}x^K@Qjv1zMAU;=ty-k!xOc zeh9@YE+12CtR$5CNc@Gp7mL2c!jw#4iW;VM(8=VP(beI{*-a>rr@jEEjv5%#(tgyk~6e9u(q3?Zo1BbWGDKX#CfDg#IU-Ziuu1 zCNYXru=r;%#So{YqIwDW0-8gR*T*ryg;M6Mxt<;;hQIj!R7ak_2B^*LP-g=Zbh8j(5Wx|7qkIny3arLP8}zJLyJ#JK27L~P zwBN@74yY|kHI%bhiXR8>DwpF1y$TD?!osdl8L*+oMoY7U|A`myZ%fp+ zkPCoIj*TsEne@1}R#sT}BW8Vsr77kSwPNrX>+jFD8@-O%5_VHao~0ApD;~2D2nHVS zrVzkj%Ec-CW8yR_KDdgYaFY$=JbmWOBMo(Hc{f#2@F?oRk_3#3$`0MfzHH7jXACd{ zLnD0HTO8Ywo+!!S}*Po6lT{rNXYD1gY3hu4AJ zg7tx=6+Q^UAYvS%zcmsCa^sE@Ith)H{0Fc|GSTUxGzX(1smJkA^|W=~GshDpg9CLz zX+qSt{c_wpfBxX98rs8{DQI-lC`VtbA%7sPg(UOfcg$+*yYHQ|Qm?#Lr+s96m!EtU zyN>**vG(tXJgdI^KLd3&e|3wOp9|g9)1+NKGqO6CAH>E@!t0Q$k zmhKqCwU9A?k77T$bpvyU6Z_uple~QBkD1AIZo|>r(dqogH74c55*4-2Dx0$BRQ;w@ zYA)WZNT9f$%sRVP`KMCM9krB=OT(DIE=|$msG71ziEd@x>R5C2?vFy|V<|4yd2a4O zXRFcl0%{M^i9|RC@(zVCSFg!Mvnvw!tM6BcRQ6Wb{egMc8?oHCtRlaG*$t2lB6W_c+{UH~| z`2fbmi_LQa>DzHY*nOQaIRY&hd!u$l*&59!_@1endF-BL)^>J=@2=U| z<$!7c7Bqg-zhR@aP=V>GxA!PW98aD|fI02+wr(J`4;HL^;-G+^?*x z)3L})l@%3SG?OJd#BKqu0oe=!n53?530jugQlERX*~{(VgO~M!p~q{|C_YmG4NG!* zdR^}w)Hk}tE?33D4>847LY{=)7y&L}?onjHRgl8UQ zQ38t1<7D8|GD6~+;+MCPaQbyb-Lap&rN556cI)7D8~ps&dsLiqVIcjj!g&Yv%8_kv3y%`DEq~7-g;O-wxfeoqEWrykN4iU z9TSJ#!Zcg#MO z^!gm!(hZb)+3h|Wrywnaq7Z@G=kyCWn!y+S;CD=3Fp&Y1%of9P1Rp17=Y^5)kG#-j zAhy-P3LeEkh?^iRPmGM-K#7N92(qe!2tbOX$&68~&%xL~bf~;G4NQGZxCm4Z7g0TS z8LH*Sj~}Bl^A)FkaPd>o<1qwnZUe1GBOhOo1=ay zVR*%;hVDWKtD84tN=n@EBO(Q)2QUx=Pyt{d)C)QTKy<`}acCnpkkX^w+D zd-uT0kgGtQxrT!>et4Jv6A=-oIV&(IrJ8KE`%n=qpN1d2jTXNR4=v1VH@KH>_q|eM z?^)y{f5`ibINjRcn`yD7477*HBE0g=bCqw*p5kk6p^Y6Eiiup<5D`c)p7Xw4|D!3* zeNtAcp~`I3Qg9;i$4Y&-rt63)%l;0JxDTocGz70wKVgginquQq4EW#y9isrkVtG-5 z6kQ-{enOxDx}T`1F6&`#ig{vLm5{h>4VTSD#gAGT4?`5nK@7LW5eyj1cie-p4-zE6 zFfj^WI~T^MrU2Y>gWAE8YQu3Eh8mEfk$(r3gO!a9J3!2J`6DKLDaBEf(M0* z{xIqGhm9Tt?G3DNY~Yrb7P#vhnVYj7z^@1CpbAX{sg*gHxl50^{XW`8)Y+I8kKu}m zehAeTps7(m=FDs8#-1Qx0wI!?u125%L2e9l_ZepKdEntP@r`|dg(M{thW{-0mRvlZUk}dFYt*{fn%uSLwhJgvL)#co0^$X1VHN!Gg|$a zmoI;Y%00rYlqJqiutq4X1_m-{$GYPr_m}U|#WWp7J|^q6{WEA66lZ=wLk4??aFgq( z&*Sf<>7#Hg-{3O!MB%{jJzX%Y{=gO)8dxMipaUOg}J}W zH>gP1pWJKLJotTe!WbuR<>%Y?RpyMZ&(##O#6N60cNX-b`S(17^Ce;x%L3x(jnzr` zIyOFTc}aDKG(09kPR(QHgIZB zvJ=(y_4N%6qTsh;N5dWsn;N44Sg?b%kKz&HA5E9Z-$y8X%WJ<`g1&*#taJ$tWZfY6 zpJrtAtn9~mAl!U+(3qmb*4doeVj-OE+6ijW*IFq#d3j?I5w0j_j9yVNY6ALOcFn5& z2NS7=VeUAkTJfHsAW8^RF>f8>)x(Vc?ORURXuWu$v|Ntxz{y7wA0H1SAuKr?6d+XY zAamOktU@0rdleM{%&~Eq6h!A(eSDBTdn+nigPj>5u)_ud2Q6gBG25fzK|y&K1&E0W zoIQ;Wo%9dI))Be}qfHqZmaHELdjP5nM`&=(x*645P*T<4V@@AxmjlSu?<(aVP;~6#=l3WLgEJgyt40 z(#vaC`TZ{#J0U+J!$ay?U#o5f4@oFluV258UIM^BHIJ#Xv*adw7cyBU>%H!?>gi93 zGIUOlJ@XtwFknuYzvHkrSi~ww1NFydvwawv=L~u&iYjnZqQGN5d|1^;loJ}&?vE@^ zWnNJA;a$KiS5Q`-M@fL*9eas+>;mLm@7})MMMf4PMTd$7H!sysbH@gRIk^EDL%Nk# zk$YW_FVH#vEhxmfTq+h6y8b&~nx;HB?V!YEn<3(O%x;n_qWpJfwxrdFzULBqKP211Ej+c5pg19eV2~WRxB}~;YdpvfWd$K z$OYPhVIO2T_V)I*HD+MW;g@pY90`oU=$f7N!sZ_Y>ZaCK2UL@d_dk4CM&d_;mlH3q z8Oue@30WncFfyNtq@*#(52z<@*(;Z$`nrQ7B+#Q^;agc* zVU9=(BOHirbug6z%10yQcq&-hSNHN&T&J`&vs;uc-Wu7W8*5$OGD9Dj0!AYIcY5x_ zvKxp)mruRO}4@l6#PIi!Hix*AwYc*FA25|GGs7%hO# zi(1&H6hj7J=LbkVy1KfE8z2S@3EL0HvOt>p-l8MK3lfwMIAOphJjbP#6*RNpPkllW zfl4>LO~>U=Umh9$e$V!Y#9+;7d~{Sp=aHz(A|SIJOlgwANU%8{tzCY4x^2O*%{BpcDt`O+BRicj7=IAL7?yfuS<2wW&KC?UjkK05Q`+{h_ zewM1-??U~CrS80_7Uh029Py^~y0ySV#@uG;o$wJ~x#< zurubf_(@4lt^iwYX>1naxs9uN01Ss=gBy@Jo|crxYIDX<{*Mcetu*`Srkhf$O0GGT zmMX>g@1dt>v`MyBc3!z>V&c}-O0t@|vujw}Z2jSL1t+-X5mU0@H|fc|X=c7JEw8*+ zN+=-Q8@JH+Y+6Rc4CVJf6q|#S|9%n>c3mPIRmG7F+g|v~tSxAI>(;FW)BbVC z%}(+DR0T2jh52t&I+!F;fmc8l!clMxRT0hxZXCv1#9`Y8vEcM2{Ex!APuN!!UF@ZyExg|%_HZS zzP;I90k{PE7BkbaZtS;8Vlvs3et+XUh6M;n&OnP$=38MXfcfQ1%X;HoyLa>3jgZe> z5EQ%zEXJQkbp0i1xGrDX0LKxx8UZ4SE_AbP=7PUZvjbaXh^pvTuewaCdX&V(oXCvZfMFC zxUplJ?W_`JJA;UdI40)~ig|<^mkqaql7E(kF>fPA6NnEVi;9X9P9`hEKjBJp&H#s* zveWA*K`J|3+)E!WR7${Vzk`jGy|M8rBk((p)7YFBxC(C^fbTFyz7q)0(63^zQ;OyR zDltH3k4~2(H5V5Mo*w>G2dzG|%>}+pfX-tZBJv%-Zy$nJ;yZw4%*jlAd}{LYQ`xEk zQn#X1BFptbK7b(TGn^n$5CxSe6TErd)1csx6#9RUHo0|RjW zMxlf%8FYj@!}TYGg@uPIec+7&s19KrpvNCf!B<;e-cYDJ90GSL@5maPA*nKMd z&la~SvWMc4cK`UH3W5s$KZ38}^XE&Nnkx`bgH4`qKk-t53F0EgSlDVqfDAO^OC>QG z{?X9jPmn(_7Fo zj!{#O4GpOpZPdb2m+l~L?G%7ca8j{jh*=-<8$(e}7(97N#M|`4-R$qIg49*Z~_Dj8O0y@vMnn2c%}yOPIiLsfAVJ_2C6p7N+H^$WBJ$?&Vzn6F{3P$YSBbkfA!zbc*V3I3@O;{v&o)n z-!jFee@#y1!MyfL!cZ0K1EptuO^q#%!Z@^Y&WuaRAuXZeu!m* z*E*Zd0qROT0z7gYS$M4;Mj0UdfJadZuF6p3Ivx!S z)WD_KNp?IRDT{FLz^_!nv>5;Z_9E(lPdPEQ>6{qDYA7gh-u`x~JP`N_M2cqRK9DG! z#Jde_Qk=2a8DsJEam%^Br#!|f6r9KGfRm%mu4`yOzjP1P9S#=*ISRHqDt+7T3va=!LKYt>7|^@g!Dt)M_^e zqBgDy(IJ#glOb3dVfV&rJ1SH_CQXn~o;r0=MJ3n^Ey&KjM>$d0kuFQp9jrrUL$1Vb zgVhAQRxnh8f`nZMO0B=oPhW=P$Dz48aNZ%Pg&{Z9`P+Bki!Y!1%nQe#A$XQxIzdex zfn|#giD;<>Y~uX+oT3)Y!TzUdfnWGNYp}eq&xo^Yu;dWJZc$}pae$T1s+lWGcMy^N zkrx6u#o@!e;J70g0n$=U*jAI~=>?ESW}KCx9~GkrVglDjA`HrdUcAT#)JY(dh~@y; zYi*L1t0DCXeXaIwDLw*QCGnkK)hw0jhXEAU{|+i@Fh5h`H|FanBwT07tY8}fS^U6& zxHx))FBd9@BXiLn1L+{9cU*>Fu}9Dlnzf{~Ahq=L^nhA}s+>sTc6lz7CYm31K0!Re zj1qgso0z~9m5xM!tv+|7AR)4C=q~xhw}y%97>o5w+I+|->m1wQ;z7wA;o}v z1k^R`M<6YQg@W1D=%)bKu{5z^0bx=$Gd~X^DWWb;4`e>q`mUA%?jkU>FhlzTkhhkk z`XI7C=A1xMyl!I@g>Z?m0MJo(5T6q3z#OC+&oUDX_>q{fKda4R^b?T~;PCH_SZ#_= zflUVB9kfaGrtl&_3Me%JMfb?+P1m<(-j^S_u-u$0Gh|M@? z@TOk~DZKiY78jFJQV@z^9;TXLfe@;rql4B4mxHzh9hcC_1~dxos^O`aEkHbFXlRJr zXNFp`_Ubf%{F&hZl`!Xu$Xbb~H-MIU&aF$&| zEZmq+W%(7{M0|aHk*v^(<>urVK8ePzBgWOAw+G2b=7Q6JJNO!(7+mmz0{$1ws8kja zM^Jg75Yxs`+wQ%J<4+(noHVJ#eeLWViFlQ}MfYO(&SgWcaAjstGw{a`RxrT*c4Q0s zHiQ6s#;l(Jl;K_!wiJOcc9Wva*iS~L1A`~nq9YGOm4RoA;QW7sp`n{bZVum{4;PEt zVMd%qbktvk$(BVNXSs0!K14`EI<5q0neg5~SYomDKB*HMYW3{MDcuDm7aFXNpB+^7I&9;j@xzL_h0YFuQLl5hk7 zwi%Wm&Nc)Y!CML(OIRvl#r~^Q3oh8o2Fn>J_%X8+hoVA8SDdARamADW1{4-yl~J#Z zqmPm)yUb>|bP#{B@7y0wNu%)8LeTA&R*_z?)|OXR@(8au;^X60(AZ-&;kK)xfmTuB zIeoepg$%fir^rFCCWpB>(+PPNOT*0t;UZE}`&rB*HkS6Jf9r?4W;hM1WPN!Ip$Ewt z9}(dU9_Y-9`L*?#vhE=;5Ho{;7=4hFy;6LG20&lf(jlzDSMHj%&3m{?p~ymf;h0)Y zsWmCQ_t!FEBmVl?xo~MPn{XHle2$ZAI~SxQbHSglZ9#&86t*kovM0ib(Yu8_A&afd z^5L0AV7n_ zOXN%@N|dvxx+=T7H@*g(K@7tx#L*YECRfF=gYmgB*o*2UJ%D2^si>*3c3qHLv3XJO z;_z7r+A#!WI$7lPwW|xf(i)s2vMAX`3QMld;UMdaD&&>029GH7MpV9lq;bk87tWy| z{f&AIdFlil8o}qq9m+FrFKrHwisA^C4(E%3c_41tY{ohVvTFXjv#jETkh)r;tK)GI{aB!FtXeQi4ZS0H+rGt$TZ@#$O!xp z*`c+AwH$C$6du*GM|__>yTyzX&6d(6LNw%^(hu$0erUWNur^|EjSG2RZZ2GnXk$^R zz}!Lr=bhTUOg8kSRQnHA@n#5ct>>@NGVpo!49yZn_5ccF6aY95hQ;cLh?Dy7kr5nf z_Ey}1@cQ^&i!F+yU20N`icWCM<*;Qw0e1yu2cE1T>d(QFL6bcSPSth~st~RD`2M0) zKy`qcAp7mx#Wa|RAzz@V0reKN92l+`T9ymhk00gMy@aYBEz966S}M@BFuk946oSQ< zkyltjOwQZ4)1Xm;A5eP?-jfKADi1D_Q&XpgQ78?mQlhnRUKlSxT0{e6q^h@Rn|W1E zP8hE|XZ;OwJ0YQ>zEl}dR_lyliSU&G+g1=+Py<|zZv^QQW;YQL5$-mX7$icEiAJEm zzdxM5e2lgDgE}ia6O*36rI}|U1lAT3f*R>Xl_7RVTb>ooTwexGX$lY5Shm~+vj)^e zTxHF~xNB40gC@!E*)z6tnRl4FymwoWtqIjTwh-9u{2Kb2d1a*l#@84 zpT%g7WAb@lrEz$rVfa3lY`Ozr|Dt&&t+({3ewB@whhhPRw$JW1p;{v2?+@;Ts;b~VNgzhTjyVig1!wP49rIX5+DIj zOc3WG*#m(=>fV2pGny#Io{0f$UlCoH^v5Da9 zaA!wgb^sIsGbZZ`#{n!tr?G;JjXZD83ty4z7)y6{3bC_KVj;mZ200%gy0f#WI_{gp zH@+hE)W!ZQw=BO2m?Dhg+tZKuT%0aML#Ln4O#7dQ`K zFwC3ag>x-`y)2H9zz>}TrKZ?`IO>9rFVu1`Dy!--+lik%0FNO$3XsasDiD)D#dP*; z0T5b`ldN!|z_^U)Y5;8i^WdWMEzBNuO5Eg1zVI}sM@NG+MbfB^CS^oW5J)0G4ea`q z&R>W_P$dFpMUpZ>E3pa{&h!BO!w%ReC}e9~5JEbdd;gqYygG zKjLIycv9K_eP7&=ukJ0CTOCEHZ3cO-HZWx>Wc|Lu0a*v)8Tu*Wa$Ou+M}<>kW8p6Z zyIm$%(|V)`M8R8AdMRTa(A{xCeuL>gEp2IS?bAqjDQx_#ijJ(z6{Mw^Q%*BUoz9 zS2h5rN7_S`udZElA9WW;kX)FXdr@)W{?yZV z2mdxvS1mq$u5eG5N-q}EgZAT>cPT0;pj>~XRs0Cj^WVtRP||^=diLy90i{_P2y;<@ zX$xGC+XeQsDx&hBV8hmw7m<<0$N`}8K(U0vp^AR{Up#lQcUC{r+HoI8JEDsj^|KaH z3c$psvC0Bte~>EY4b-;um>K9~%02?M^(eL_4NYc3!Ve5;N5!9WWT8C=LV!LmhWfBb z1kQH?CIDn*WJY{cOSu3HFgetLAKkMbyJ&xO=E2dLn2Izqa%mOX*R`~$0B8#OLQVtEYGCzt*nCbmf&>a1Fwv13a0AeU z`Nt9`UEiJf+0xM=h*><=A`44RX{kPX>-oQhV8)d-G;jzA++aP7Q?D5zHKV0{2v3gV z7ZjFvH-wjX7N|M^8!D@+GCam<&G<1z+5q^g5C)IA zmQW1>cD6^tfIVSU0}beWXpyiCEcErc^uO#{9=pgguG1U+_&MY+@SX;d5g`;w=&{HM zR%>ZlnUhdtc=)j^is*qeZE8?XJtTxp&___ocxj@FT!wbo~73N5$h)X9Qy;G>%d-K+5>IxT?Q?#hJ3~ zr|A$IVOohzj9ibRo87k@E{pO~Qb6v*&zoGwnn1C83(9OnDYh5{c~;gm5XMlSuHb@D z^TBzRIP4Cv7CI?VcvZX5^J*_dgP4gQ0`@Th#s)^aXuV;vibzPHUb11|(9h#&@RR<- zz&!^;u-yDWDnsQ52Hft`cw19A)uQ@F@JI6oZ-X(rWUOP;PrXddCMylQcE7KDyETFI zC7%_f?Qnbq(CQ8F|eLC01Gg3=-g3pIO*iDl6OB*uaY-rN9sw zAHXo|9dKNp)oRb@ZP-OXA&~-rEW(+xsFWR*K9qR)aSYVZ5}?9|VLSTk_nq2`iq_z` z0mB5%3spXL{^RGk3*g$rtr9)@)shF9)od(B&)+6LF$76wd?@x}&q`TIDk-}0>u#Jnz^dYhY@Q5SLuuq!MR2Zo3Dcr4amg9tg& zl~GXwNgrf``38hK4i1nOTBnHJg=wvz-N`WWe-;VhqkI1h)X1epAyMi3b6d<74^w z`lfb#s;is8Z=qZfi{TU!TE*_V%Un|Z>(+i|@?8kwOw4D_^rL~a(v8pRwoA5tE<^@|;J=;hwm>T60W);A=l+fM&{Mnd|Lj#FRF-4j)Hb(2k1z!gY z%$IXbVNeA-GsxUg&PY|(q;v+7_d(|lQ-S~~%o4xh$s>ZpI+BKlhMqni&jbGkVh%YL zDzTR2A>t+-d-3ln2v4Ff{d&6gdM|NK!6*OSiiBSK=-&S=|B;PUe4<^+kx9H{f!S@E zZkuOZ<4^9g;me*ER6i^8gyQyk#(n!1NSrX&e7{cL`U2@}M)}6`IW6EqkIrL$`Dqu# zQ8j~K3lATvDiC8mtf&lMbA9i}feJw`EW~_M1xBjo_K(K=V|cvGTR1szGTfH)F8RlZ z)5!ieeT@I^W;{L9T_!`PT%bS~qCk12Dvx3M1U3t)c?fMNtSCeb9CEHN?))Yl)4Nit zy8P#BwweTOjCA$7>s(b9)%348CTTjXo!#_-0(s~0lf0Wh8K}CfQpH^zwC9Rr|7X6- zigOR zd49ZJ1@U@jx8=wjh^M>d(WZ#||KUGXOC}|E4;Hz1gV(t0^g-{(bw(6oc6a|UZ14j2 zOs}2*2Gg3MA#5z4aZ|J6^w{CIC3!}XC0i{T> zD~Z@w3^ohxCQNTye(tq#6w(Q%W-PiVsfY$2AnRGSvpih9644K=F47&;E_CKOH{;sv zwpMVw9>I5gZ2~9mX+d^YecW-0GobVr6xlV_;`W;`=4??CCQ;i_YgS z1NB?-tu-{-@pcEhOIlm`re_x#o0|h2Zf)ICO!72}1#T|+IDHn#**y}^kwOPQnmsWz zznY4i_Uw_75z)oz^m%d-xh;3QwlrsAtNFy9KhHC&yX3Oo=`@#4#mDeit9ZV3&RG6e z=Pz5EcMVa3YBz2$H~9Rs#f9T24amEZshelGHKv7EepQUalp`YWmFzAQK>Y3P2JUM- z0M&TtuXMFMrn%yz!5^BM6dkQ_)5+R;27Sv1`-#c%@y0mg=fw{mNHxDL{<3|`{TRF~ zdL&u7x)F^}IOzsePl1!uV{+)b@7qrxEk1Jo)A-|ifGu0E=jYx#;1PexP}*{TYI}d&Q;&l3mA|{E zx{3j@qtiL;pNP7gc1rrQzi)#Y_xbZaK2K}EE`ou1?4(Bz3rAUOg~#F#eJA-<cUngJJhzzG#5uS7gbjh4;ZqtExA#9l9k1x@EU?B6^)rr~ z=FH=)5WlR)0IQGtH1++G{yHCh;Byn}&c@2><+}6^`w1lA+4Q5Ij4z@pUL=lJB(eW3 zzAM0sKG`I>(*Fdv(<~h)x#G?+5(MNP$uGT3BV*LxM5(EcX)lj)EGv%Yz>uY_Efk5! zoL3V`p*|yd-fSEbZgho6NWnotvU0Lmg%y_rFBTKZR5yirgXAl;ijAK8>FMbk3%FqwF6q+?$fx}?iepAC`4yuz`aAK*ztRUoMvHy+@KTHbQw{= zFCI8_n3P@jgZQok-jAv~OP> zrhS;)E=)F6e);m|P5!`C35TbLHePLs=nNJQ!0+qfLl-feUJ=8DgKmRE*H-8`!I?lw zZ_-jNdG)F{d0+R3yG~98>Z}Zph4S4qQKsVn`uPxxj-4=EzC6XAIJZS_-1ZhIdMPXV zy(o*Z99{aCImJM6>>O)FirK$CJ!e7RzyN`3P}`Tr7c<_(`qvw4t;sU@8TGci&MFcW zlET8;0+r-qC`knGPR3?rTvAkq*SU9cat?WF#j_5F5hl-{+rH|V2917CAA3admxaT9 zaXN}@;-_@?^HVH5^tZlnl&P}n-q7`TeDX3T_(xY2MU1wp#!No?S?j}1moPS5Pw0~NV8Uo6R%YjbZ-62Lq5u-p4tD=W5@C!CX z@@(VR)Pak@`2aAKG3N;h-4N_j*3tsC^ci+2_IO-eM953#U-;DYw6w=FslFa5i+!rj z8p&_q>`AtDX$JtWh7;dP?VAVoExQS!U< zc=@Ee=K>OE1)~m~R$3ob2FJ-PR&YU?duBMiF?N;NI{Ei(S zSA0WVZ2B7{Xs-DEdW#|u{RDYzTxvwXjG|7<;sKXus>^KO<;t6DWp4~Sv*te8hq$}@ zG!3^1)iLVUe(M+kAiMJ?WFMnzqlH=v=W~85;RSv2&!1;b>#R685obJ8Qs&Igz~qkh zF@ZsFpXtB0X;mvudzPJj!Rpt}ZL+6y_l^Zag%g!vFNYMH5*yn$+Wt;$N+i$fid5_M zzzy#`cA1M=&*L7E>@)A}{gLJRshvA9o;q(~E*!^bzKwbGOY5~xiL;8T>d=VZ5u5p4 zAMKZ?lqCJBvJ6&o@AIyotkc350pa1+OO5f@PIU17y+bW@yC=0x-9*uQs(XXiDb}H8 zh)wf6HNU>2ivWw4f^3X9 zg@bvwL^q?@uJH5Lt38*t#YaqZ6juJK(^$CJ%V%Xj^|QUMC0Vyy2e@JgduB{>P)JC| zje??QC7H&ye*?}uk%>4btbcdhTKiIx6@8!SWf19GnJ<4urzB`d@HF=|`z*gvGfpoW)C)vr7<83jxw9Lp~ z@iaiyA66_`2NqX!c9+XkMMTnX zEPdm69ui`&mw1gmBLhbYCKwrE%4_8#n02Y^=ns~-goH?(Oo-eo>hKQKO?YHCzW4Ch z@t7QyhdpBBLcQ)=1vRy)k$^I^swRe(lauRH*%X*)a63*v-zvHpB*|!~xb0tQ#7WF& zx`=F)d4Bn+YnzlR@V=36W(J4q;*|0gE2V_;VwVD^If($N3)YQR@A}f-yn%HN%=v zs@_U2n?Z%&m}pO;?~!^Ab)PGd>L>vKQ`S| zavH?VM09MR%pLzUhmvAwFXB^$fllA`Ne5)?Ek!(|Q1c zW5;L^r@*dDNJ(KXtZD8}Tv=W|AafbCUJU`QC_ zGmn+@dl4AuN3)+FhG`U_RCfm1ijoUj=P-^`wLZ95=HMU1RRn2|Qhgsm{@sLWj@{?cJv_l9(H+zbY%+ z{No4q`kh(Bk=3O=BaY3@874qiGIW+S1*i>vPH`{KPcX7owzh&h!XFTj2VSGuliyI#xxinQNISvw%kTt-(rD;x)1pyswnIl~Eg(mRVW; zEaEv8ed6?+D|;Fiwpy%1-SYL@&BlMI!z0uj^3N){ZrFU^xRb3VR z>CsFc#2N;8d=Xw)pt z(mYSAX*Heu_3g8-efBwfpS`c^fBr7l=c8KdUGMumzvnmH1IB$A%ITiABhwCdw^f)9 z`bJQb(0XiQj=3`MonHEJSN=IFkEc|?)d9Jfb;@qHdNZg(Zu`&p2ZfkGT+vSd*ovL1 zHCb0eCKSU@Y^aKgOdD&Ye30RfK0Ul*`FF0(#16Vzi_w?L=_Te$KEsU{nO}$DWa*922?DG-m zD;;^Jm1prtfDDDmtP$bPyxkqA<8Sg3vPIW)UXa{Aq zr{JI+z32rP3H>E>K+&7o}RIfw?DJg(0*mu}K$CAYOQFsa$;eBioY?xoS|52tB_g@(RONr{Y) zhhR=7te?%zUjt6`e9tM6XIg4%Tqk`a0r}_RqtPE822-E~c{!Q*WE^q+(oq zspeRGb#y7Fc6?fyzmVr|G0Pr}C}R*SnVz0`dMVW((4gL~ScO&dVfQazP&F+J+5i45 zc>#`Tswyfc_bW_BY>si3ar0$Tm?>VId7jMVvtKYb<>r>GslCaW*o%z3qR64&MzIF- zYKDb`q&wD#UH-PzVP%z`{BD)`Yhp?Q$iiEnJ(FTp4y+ML3TSWN&uq?|>(5nD@mj=g ztSK*Nbkn9MPgKXtuBRbjG{;#MwYP^A9o54uL6GET@jT(kk?kz287?J_fG-8)zsX3#>by7Dk+J>PiD}P!EY!1mO+*;*Y8LzR0DrBtIh4e zBTGq`SzgRg9N$@+a>mn_W~4dWxJ`j#Z#401^4F?!i+gwnRo?gR+oNM+)FjlVHY4>z zodvffWDeb(IdykHnO?ff<#*>hQ2L?ncl2lqSsb&TA-1jxh{D;-9y6RUO)%xw&9*ML z4B*%)@ggt~1vG41dFP7ud83IU78@s5Szc8YfBRi;G#ka;hou37aj_Pa_Vx~#UK;e8 zJMg7xw5M98KH9wct}h{mjiW(aiQa~rRf0nEaJ*XdcTW!{JVX5hy}f1@7Dr#t>3zPx z>O42rAxQ-=_yK`?PhY?8@Z7yd`=q~bfau$Z#|2ZNFugP!NK~S5%3!q0G(USkB}LE0 zrPE_q1vPsp!nUcaHmkK3H{7kT3{Xqe>h8*wH#+|nPQGWfv!m7R?HyUf52Ra_ zruXxTMu^$(-)WUuEHG9caM)|lsf%cecXggg6m8NgSn_2GeTHc#qP%#2^@@3g%Ap%Q zwLRa&*bZl#HWvoPWy44K_wVZ&=bx|U-s{#a&J$k^ZQyq)jwU_YtPpatP=9Sb?3^Ye zAHip~tnP*?Bkn@(-2q#uzl0u^4?p8f!7%*I8`r$My{n__>#lMhmfkB-RxB;Y;kB>r z=$q$-;VuBjrTf>n&hCpb#Y~@?^ibl#gU@Rd^{K9FyEr5;Fo=vx$}uQUSL}SKp$<%N zXpV(`hDjfbYgI;ecIOA<$|p9ackf!6bXJzUwO28S&avYj+KFm>`vH+$!g8wNRN`~sg3l169(Z+i)bxIQxYL8fP&ST~s+s395+wh5X}+(w|E2JW zh%-0!Y;ZDNhSkrquINLv`Y%(V;)49LM{!&L`~CiUX(BSsCvN+j>Kje=)ml_E8k2+8 zuOIvBy)sJ%m~LY; zWbebNDi?G#DaE%dt_BS%n$9A=(;RJOwSzfbvGsPHJ0u3zt2wj}=ha=+K61a&uJ)ql z>}X~_7t=lNzYli34|F*%6MyE(Yy}+e5Hv5HehbimA`_kqU6b1{YSZGzM==x-Y=&+Z&-7$%w4)94^Yce zhZ9<#T1S@43ghsS>klvZl^4#7Svu|3ouAB#43sFDAJZOEXTEy9zWV3nqom1BIGG3M zn{HIvp>;&SsY{<*`o(&q_~p(eF^Y7z<3qJAG+lNr7mt71D9&izAz9*%e_+}45(&V% z;mv7kY_~w+hYw zCxeXtYy$BA_t)NaMs4#fjp9r!yomY7{fQ0I(7hTN3Dmb#ep1;N1Py6*V|?;SXHIVJ z9;=V~sml(YC%_fJ(ClA+;?dcIN~)?W4t>qqFCfymd&^_woU^J2@l(fi(Z^8YR8d!7 zb8wHZp+3s$$H~th03-NCCsYHeB7fw3X&9xIk+}nr!bv|oGz2VMs@*$EL=v=>K!RnX z-*SBG9z29^VDJEU0v!$YF`vbG4XXWkhfg~9QZQ^^_g{J1|AhtdpMFbRryLLbR=K!# zZh1^E-Q?Jf_pO~w1G+63NaVznl+`95Ri6ivY&+4?0+bAhnCNI+^l%a(ly{ZxSrqbK zh!#VPx1piu_HfaNRHE41OVFFkDc2`H3l&-8IjEb>r=<$21CRW%LjR-YdoU&?1%qEu zkqbLX!@Pt*3oxz}E@C)UxE*s`By@kC*m+KR;DY|=6H~f;8CUwx6Qh^D7S4xnSNU|k zY2ZtH#iR})=X>?oAKB>tr+=Kf@CsZ|2#(l0I?A!_Z0XzS@ujV;4O41N&!-dHgs-Tn zLBpVLWJJ5K6;WH*^v5VB`&}Q@vIa&*Od$#nIK#vKaLpLj#a!py3212n?tozHz1 z#A!fL?8bEffQ#7*e&B^vfBgccX9Q?0Fc5MDWqGW)M>KxR84po=!#D{z+8E~T04Kru zGKa8rm=TvHoXg;B9PsFoBydqde~gs}`*3c84K@iiQd`>t$F616e1gxX9qDt7?u z&|;w4_?N?CYSHR2P#Az1hVVUY(#;2xl4rXqEAcGmCm z+vy=ifEOBKpW}sL?g=K(pr2UoNE9Fzp!DIJfaHO4FHj(n^Qa?UpK;6vKLSh?zz(>! z(N4*raB^ba^$VyIvOn;4^na{ZByCmL4;LHFIK{y_w?u7;qaPuTLc*xg#!~tQ437{)Ptw6-a ztz$1RV02Np)QR54Cn_QIqqd{ zUY=suNk6)%gakNItH52ZHD3U6_l@#wFKX9_G<7^Ms1~6_eEz%|yK3k$;!0Lpn(W1k z>6w|MwUHYNZUayD59$~ba^T-LZWJ(Y6~I~(7A8~`@Sw>?NIJJ|*#dkBtF$tR(^zNd zUeZg0Sjff6c?+mVdg++xXlQcxBSz6nW2^-Bx~7&^Cn!%*oRk5?hK882pJ^q~Vgu@e zUK&2PU-05^s)A#3R6LY6@ZErr=N9kf)%gH0=n3GuQU(B-!Uzk4P#2fN(IF*zLs)5y zj^gjoc>;M8VFjEbX=StwAk&taoeihBI8GC+D|{e4vZQWS14F}>pFh#kkAgE@R6Nk% zfNjl>H2a7VZu0=(!|j?&e+^1(kg!B4S@$gq_ocJow6rqFA9xvHZ?LEE`C?*liMTsx zH6VsY%kF}M9QMq!D3BfCKMKGIigRxILQD?;XG6%TD^ds*s)h|9Rwohyke#sot-Epl zBN9M73SpqWwSKn}s~;ecU(paNJOMmE-V#?5z4cu;L!|zNp(K8&W8(EN(UDV32HQ?m zNCt==CNVy?M*rmjB)1Drg+4wt=z8D;q#^;*OrD=d2dkcj4YjU8G}aC*C9JGYkf1Qs zhiylY_H1p1PMp93Ye8^CdmMM<4&ya>Po!MD5My+5H(8qX9b z(%aPYU=D!nh>~uQHc(N|Ei7!mpG;${{64V=MJi*+h=A4sS5c1b!y_X=hOIPq4nrt7F&x@+{R#H}Jsp2xB^+%D;BsMj*(Ba0c*aDBTIE z&ysGCfiu8-0n8fYhPRy0mgkM*Qd9Lm`jZoJtI=ap&3!-pvjXs2OpxcsJ5JyDx=lg` z#|9A8CUC`x+bR*~wuPlYP-mlq2yMY`@avL4KK;w}; zswBefYa%W4CDhA9`cR6&FDeoMeo0Dyy*38aKT-53$xY1q?<^=MpN?Zu-5 zCljJuh_%Y}F|o0Xknwk%c@G_R&(h24>Z!-xJ`5K!gFIL%`eta-05o3RIDnv{B-tzz@JRlYADz z!_60`UTsmK%ZgTRBKYfnz^M1{ugj$cwWX;ktN0_BuMiYZdjB4*6hZ+Lk(&IICZa}N zO^t|+-|hgq4)L&2Z;%hkG-9QtrNS2N;L4?!Xbb9Zq*$b4ZKE|KAp>GZMh5>G*&w>& zJ}YXHMC5x3RW#4;+(`pgK)w8YE)#Hb5NA0rB~|MPT>RxDOqYR9Bxzjs{*tR~KL_4L}*9 zIfUcZ6DcX89W{yks17{w0st4VaR8eI&f9yu{!KtNat~sQ0?~>v2V*Wkk&XYx*$l=J zI!#T;xzJ??wiPTM*eN=~&?bEr8Zu=3q~r=VUUfo!J<|3xLv+}9H&H})ZmX;QuAqkrC*bXSYKz1iByYmP9{L^Ni%C!|_DVY9n4-*$IbvHyxKPS#Y9?@t0XtWC`BIx_~kb_w~&pLB>bGvcn126hQA2WPv*a(}zuU+>)kXsv<&pc*r8~aHr0~U=|k* z)dzsZA?7^R-MwSy&f=aa0LQ_GXw9*7h44O5%fK}t3kXV%#aUMq)1V{i=ZrF9f zK=D21fOw+ctE!L!Ea5?$xbC1LA+}*jCMt1?LS7817{Yb52gvOnc!FTD14zWMMF&GN zgk?xmP2$xMSuiv}EmTgcqH2uKO1v{ZD+D%xTJD642A42|unA#tWdB$#MEF1y!PPeC zN&#!O+T$aRvj8G1Ft_lXDVS&B%^1vMc*m>Oa^nebo2CZgG& zR6!jWK|+ELLXh4w|5U^#LCemt@YZxl+k)T?1Bq=giP4+g3tpb-0p5oK100aauTORXL!&1p+&hHFzRR1@PT54e;Szp)(#E;T z_x>LTo&Tq`_J5(8Cn{em604sEYa|;zJ5g7!JInBshcUGJ_ig%KT|cg}Qx!_|JGMwu z5k5jRuiT>8u3u!0{GdbY$v)A#%y(-0u|F;V#~!;yxk>otn=1Q>zV(t}J5RU>T&1Iy z_K>=6-~8LPjK4yL?N9e&TSKi_VIPxWEjt0g6`&dG*(ZF1z}o(&_|g9iTZ*p<5YpWK zD>k1W{(U9(656tU>duAPz_ZIk0qf{dg-(X`>-rZJqN>1r0ZN{lgiVZ`fHKGM)XNK6 z#Xqo4O*$_fq`MS$GHrSqKM1_@)QHM+`{>kuA6d4YVDVFJd;i9-lo~6H0G@ld^ zsX!CG1|A|v9^yC636N8}Q5>SEUmXPmU&N}n42DC5y0A}H;z3?sbBH_Wr#i*Ag!XRB zA<3~6I`Bn)|vKJ)KzZ(${t&pcYad!7$3oo zfhQt%z6MXqSg;rNQd?sqxpF&nzhIf5v-klAAczIU#Sg2E&^W`8{Y7P;%VIavUzF5d z;MVc0!W0zGL&2Q*M9h?%=zc&Q;)k(a%Ux{SDF`qRP@MNZiwXxT7*Y)QDBGC?29ab; zr_>E_^70Zks8B>elrDT9?_haDwb1j(v&1XzzB*cByr)mMefi>6Gmz1;wpL_UKsG8b z%qZMVZH znN6-=M*$y;Fi$6eQvwA=XQ8txcszI+2phF%8Q#1JVQ~C^2N+bWeziFGwn9ngrLXUs zNx%Ju1QBw&1k-=G-IH$P}0=?AjFoT@k`3PF?W`hzLwfNPMrL zQHVq(_v6P7Ts2BG)I0>`0o5<~(~#yO3<;2g)bZ^qXa=8=I6H!a?Le*S?KJ@36qN^R zK9>%h#Ay6C?nVQFb;kr_s?`yc^?%mxQE4m7>cxx*v)SP&F~j1yQ!EGG<} zK6$c- z()8aPZa8DW5{3CP(B&u<>yVw*)TDwRi=r4kFtD!x=ow^ZXng`Va$t=(F1@^JVW9`G z1Nt+l%dh~{3mq6*H3C!p-fdAuWrsc}bOS>3@|K9>8Vv#{%mCoH>y_OU9zD_(EDjL} zV;l|Ej{Hm~0aUQh{!`Q4C7Y4-!?Tm{p^Im5zV$4sAIdwhC&J3b|0AXSH#i8q>E{oc*Go9I_AqDTfU7lm->%a@HhIZuX4+vtP89^TL@ z%;Bc7XT)OL$DlC3n>S+D233D2O1j1w^b1?I-s+AYXL8c}sFb-nm{m0X<<@lIx4G$w z`U=hLunNKjX~bIZG&b;TD5uo{Cye2x8~Kp3rBp}duw{P z*XZ!i1=rQd)t6U3+?!bZHdP*UUS!5~==#lTQdFmIPkrw$nh5kLHP;EP+S@5Bo7O5G zuGn#J&mvj=?q<1`$2GqL#=o$6vAa}{@(fRzRPLB@Fgzf7?-xjUAoxQ`wdN;)tVT%c zu?bE??7fAQ`%l9aZ#BYLlxRS-SatgOI} zKI|8y^^m)=zI!)G^m#vm2Ixkh00B3FI1#fOLKAhLK3&DxgasoGiIT^p|jg zaT@(KI7`9w541$Q@6X1@%;I+%@Ct=Sf*B~XaD73sg1p+z7cmRr2}ZoRh^;s$+1ym@ zj-r4BA>0JAgxG}WhNBa~y}~bid=XIY#~TwGK>Q=m&JxoEDxAI@ z80KOd;?v4OenZd>dUQY$f4(G3Jp2l9Y; z2|hY1C_)iZn<7tr*PM5QQV8IW41&GYBa$1g6kRivYw4)p@b2t^T4K+kcJ<+dsOxGN zo&U?1@enTh$1;{syFv|!TL#I6tXJ#R?#>_{P;J>_(waGh8;f%EPm3I*lm@g!O+Sc{ zS+o#uv6j}kmuLd6SyWUcKxyDA%D@B-0%?f-Xv#$=sFhp;M2a z%g<(CV!3rAHbPrTz+N)`qu+SNopT<>r%ZixaDt269Z5Z1GeA4m*wVJ>)3IADdY~fc zihXiGmhlC}CFZ!|)OP2oY3J6)2f*&gJz8@Jd|BxH^{nN$uUqHzIO$&0=6%bTd-ap= zQ^V)$HwK@pQya^DBP$IYu@rHU)Dnw`%QU5&H5Y7ZX{(W0OOL7k>BP#Pb9;6{?@6mk zLrxgIC;M^BD?(2?_q0`7&Mv%p@1E+dQ>b3Tz`4t#BQ(T^diw3!4vF^AkfK%J?y*~% zC3;>Z?>T3%LU7nZYyi+UoDUCIkEQI=*Vjkof}u&EJ%op5C#cKM%AW< z=+q!j-6a7vHc+~w-EFO`fK10355+k&PqD~c0fNIo;iFCp=(*UBDC-7!kq#4n%xxYk zdpY393I+!TFNC5MRP}D&M5oih(vq)Wx~VDP2TCOz<7lv>(~{mY3Yb`hdyuMz#y!YT z;8=LIdgBhZCr&mV#>$o!O(yLmGBPcEVkofz{fvqmz15*PbWoJk)NHM->8Unikev0A zDgA?v1-KP5Y)F=|9}1|5xf(QbATtG~G>*5}8FwDU44C{tb>IdflxqJh?(WNw5R9g= zs-YnW2`%UbpyN$R6uUS12^~+2G~lF%zCYRBv@fWn`!?sZi@;^8sfDBG*|Gjg-`}nn zn?W*z=+W}>4k_dfdrMe4p^${GtobR`Y#K8k7X@8Undl@c2(V6$$v8~^BrOlpB;_Ix%*hFWvu4k<5-nBIrt%!9#v1(rrIa1he z_H#rV$pv#bS2@oewJ}TmA(kT4L&=o?Uga9_f<*5@MUqJSQdiOYWjd`xJMYKpLs5so zlQ%|&nszySY1P>BlcGHYKAGg=sm`AAao z^1R27r|BhzL_{dgpMqjCBjd$GTUYM(jkh3Mfr;BShX-Sg~9{{SsjvJ^jilZBN<2ela?d4rB1&LV%4qaV&5eDkf;K-Hf959%9l_UO?g z!t*XhZue#Rwp$3?5DdX|7e99j0#B_v^?KG z7LeX?ED+YVgd1;PU+I@GkVW#PL-!1^h}hWh0|z-FbYHEB#R0*E-q}d)ttriyS9 zE?-rb%~`HV33ZyKzV#z7c`4w-_I*Abd(xJFEjIO>u-bCu*~Zmu4?0#qC5g1?51Bmt zse=p8-Q$W`c1To6|Mn7nkh$?$RHBaQyQI4M&nJGDhrU@O+#iC*iWa6zzNMcak))Q3 z*6NOMz6VczzYxi-(#W%vVQpVy-LG8|R$Dya@Fc{1BIM)S)4F;-*4 zrj7fTN4~edZPvF8c7aYhdu0kBi$D1QS#TjE=U?=f!>;!*wtrfSeE zIJszQz9OI40@Q$Aq!LC(BG8NQld*<&3PL`lZq7q(_Ul(8v`|zTi3SC7OEi>2>FVJm zh4ut=W<;uGpoKxTZ5t-Ck4B3tc;h~NfU^BfM0x}u#7s{wFEb3z0(a{m#=d!TKb%W> zMwyBPK?2AQpnTNMFanh!8RYyx^G9^oZ{D=)t6+E*W#DdVI$7QvpUVa0LsN0_Z@fGF zvf?9`x%PPhYKI#_c4lH>u>>eWUWlRg#-$xQcA#p6Ei5ZBazS_a5>(M-WsPx<8M0HS ztF`aW#DCtM-QBt{np+N!mA$zqPnLBhtM9WD)}HBdwGcO$is0*t8#YZ!Yk9X}#+`dr zxKv70R$1{%Q*)`&)vIz29*6ZcwP+E(t;X7VtJ-QhO{VPK`7SgBDD+Q=G?ytYO;bFM z?EMHm{N!{sL4&f!Dp852pu0)0cE~8oy{0?icRA2idLeWSxP-vEp`UcIyr| z%5&I86bOzDJgY7|L8!b$#;t3RROniNnC2KdL*O^o1(<-_PxL|E+&1P8%xuLN8t9h= zggli0Z`Q0Zp+u_o`s_g&Sy{i;%~*CYdBF_D{4#As4Jac;x4R$8uu&jd3wX+C#5pK0 z;idwO;O2|=yxe9r2}#Kzdo~0@2-OwqD+D&fnjK+~Ku`<}TsVLJVh+ZW5Su#X+(itq z$rEvy4sLy1j0pq;B`}J5Su-GPT;GcX4rnms-56Gc8(w|@EpE(z`j*u3VhAdw*Y8ww zXg?YrmVKLNdy&9|N8!Iil_}BDD!_$ZGxG~yJPt{(p@JI{k-mkAh?VKvZzW9Y{O>{y zY9+jugowgzYlkH)OorXN5q)%Xtvw38Sp9BcX`!ctDH!-ZtJ+XU7CLom5s5KGB#`Rx z@LbB~#Bdt<6RIJUBJNL~z!SLH#)$pQDG@L_IqBhr(qI>^ZgC3JZh&Jj=D>k{8N*vX znZVru_AJ86?XL$1Nu+Zk9I+K|Wq`MU`gpWanhOU!Nis)14RiQ;^lOGl0e9l!zeR&frvi3=)v-MxG0F6JSlo_^5C&!lUwD~l$AAeETC872X(kJHqA&Ckq)7n zMa-yQ+ws%P7E+A>v52DuAy=tb^NIe6;q-PO zWFeuqa~oI|wE6+`Q60=k$PfC~LzwO%RFU`7554zJPoE}s6^q!rq$CK8C>c{j6bAk1 z{j@iM;vwH^hWM`cfioh|YQ!7?3B3BL^~CTFr72!xAHR{;s1@8R@EV>{QLqdQQOp)0 zl44A8&(1 zaE|7JU*FgmGoTndcS4TnDOcMQ;J8AoR}EhHncomBIv<#Xo{$5c9I_6ud@)TsBOqXn z7Q3~&MW0<7;zuA2fuF)y{G-cCZg_Ynp&hs8YGBH)y&2suR0a-F+ep#KO#oGMU7m6W z$^~_cwXJya|6#veko&gDoVp;bhnyT$e}el)$85k7)2*Z(64@)O4Z|hsu@)kAWoJz( zZ@k@nkDqaVEKwKKBU~XBr4UZ57Q1%0#JDfZE~4nU)2hW1IYKl-zouF8_^fAbS=|i!w{WQ^RNN~u%vk&Bd`|s!&T{j??5eHbuBZLDG@LhGQ`A2u z5|>!T{39zc@!92IH3e$pmde$9oufPLMKrvIyCtdY7mv=?C4Kp(;%*th=Ir z&!03C1Cico=1b(Bo9JVryABMi^S74WTzq^*c&Nxg1-?~<2y(;XE`^zTol=ILdFW!U z2KW0GhE@DIZ_#sfqP1xs&cpS~@3}-T3}{>3xdY+PSEugAhJ>`Dk!56+XRPBrG7@p~W`Goq<)J{ow4`dkNZO-zP@VWSO^*{K7rUL~f z^o06!w-O`2Ey}UyWaQ*R`EM%p^@09Rv|=FT?BI|)I*m#Ur*C=M^{%hjI%tsg*^n)H z1O&)HDMb|Iojpis#o>41Faxao)PU%0=3bi-sM1>hN%#?G!|j;3IPf1^koJ|85hqvu zggQiUZyknFqR4ZD?O%rtKu=iVguveCHKPmWM|B|8N5BN_lTc?SXg#PEXMjR)l>)+X|$KvQkqQsAEe z1(xiV>S_hCKASCr)@n3-ZGX!VQhrl_UZfJFKf37$WJG&uN z>H-zf5Pbcbz)0c5+_Ps7U_AG$jnpwPAOnVlpU2X}JP>!#9H1VUHxUZ#U(YY$C`QN{ zwB&l~;qejeT&QW9TG(KkODJFg@C%~>+~A7_W^uHR5ECu{*`+Xpe7&$Jv=>uPhmM_#ny2Z!v=fC#jb$!<`E^$XK+Eav>qE7Rj%hpq zAOAqV(d&MU?j?}JR3v1_gw!aS#+ZnFxjuz#go=c_b4ft~{d58&gV3Q^!*&we8*N^k zpE0SauF!>)C<9g!8SNPeaw1bjX9J1pE(xRzSf|IY{Uf}OQqCrRn)5P}5>z(W`1;vq zSYIuGQ4SIK^pKDc!Y~3>Q1~=dB(%A4Dgr+U;XI2#jy5#afojG#qhsIx^XE%%J~z5F zjjBE?@rj2J(8mh(rAvpU78J<1h&2k}Z(o0ZHpbHc--L_W`_n;rpAK7ug(U(Dbce+M z-jQEko2uU?1ReFyCW7Wd)hllgRZP=e+24?%sX#>Q#&`<*DGn z$v`=Ur3uL*OoaitDMF~hh!~A=wZUgt4CgOjuE#S$x&%}5kpPewpz5CRY!9ac=J?w54)pkvb2wFa0-Iy?AT|BN71 zDC|lIVq0NVoOw&x*mwvjJrxP(6lU@f$g41K!wW#+Mm=&`FsHsEPyOVrz+?fGN-mZP zFjMB{_7qbJ)JE=B`_EJaxYVYCkaeGKZSy?w9|`-B*9`w%7u1CqFGwjXr$J{6B9yhY zw~@b+Bcfr44)QPC&Oajhsd{d7sDR++g;WsET7=B=@`4}TG|Xo(;)akn4r81r|13Ae zZ#0l`vi00PiQ3)zly&vW@-onfkb1zxkeY;I3u=SVLB@-bUDFvR@8tvOjrnKz$vf9^ zq>*3vp<@8}kDNG1YoB|jxOSt%jUn^7c_$UIDa2wR znt*4xeR4mPtdY|rau1sf_V=H^koofEp4{N1imz%JiiIy21S~ssot^^H~(iEj`e&|??SYPIP6l>10g`ALg_R^n5EHHn=Cilw$7^r zd~Z#Na@4Qijo!1L3>68z93&%Pr5ps6JSHkif(nA6AQ{1J>MWdLP)*?Ik*C^=5P+Bh zuEEu7*Xl6&5sRq#UmJ8|gM%`Jo*0@2479p^%F%eZ5Q)G^fmY+jzs>=(5EB^f>TAmn zdPObs_NF6zeCn4k!+S$PIId^bTG$ z@W+9M7#vRmBYH@G4Ic${5l(X=uK-YniU1YROIJsT>*u02zJ@hNz#Cq_CZ==%k=0e= zwjw7(R2IOY&$V3(0$<7Cu>KoOO5cbGBnmDR3WUlWe##*>HZ(xl;xgrk#-j?3qjXdt zRh|lS?Gm&8g~3;nm7TC~4n~Bq$phlU??7HcdRo(H0H2|an7#9$ldSLop-|nWAweES zPm6L~9r7MBk1hby&m#j>TP})!bPP;ZIY+j!r$z+%q4K?E%H~3wa z@3lNefX2=MqMS@~4)+&17!C=vv*SNQYKMj1ofbwf}tp{@d~lz4hbaMEdX-II}g$#A2K{cT`|TgMGUS+x&3X#4>* z0!aJwXV0SI6jkFYb|K!PC&cJkiZ(a)1r47&)XI^uZQXkJ_U$)0sp)C5ShKYeQw-mu z`h(L&BJ#!b72w@|?AUuyZuE`kxwMV@WL28Xk0c3I?^(CU{o000f*Dy^z?mRhcqPT^ z@%%Xrlr`Pjaa=%v6#zyjv53k(C<^$=Wa6M&Shz>)4w;6V*tcd`82mYo+&t7m^7VfCKR&thb z`~ubx<64UeHyb;<^W5JULzxMk=H`}T^;6MolA6jwPfzqKaIm2-WMSa~TSPw@G8j5=RLeaJUsfb%Ek%{kh#l(Y zYKbyX{QUj4lM#DZO9X{ler`vyoHR0%CbuHvNV3imIWmR)-1&Ou@paUu&P2#!0l6*~G_bI;W^ zRiSADEC9|R#h1q-D_YewkK-O7QWF@kY9j~|;5b8|t;+5+4ZysE2stn+uA`zVY{(hU* zm`tzrH=3X{y7~fywad77z`zvU`5TERo+{T8PY?=LW%?$ZBbGV=mLMAgZ~;K0bp1j) z5G0s{8oL5sEU>ZSV!Md>+FnxRTw&7sScl+$CyGvJwl9eQN%^*zzYh($IrPdYLh%!_ z80Fz{$Lzu`{zn(R{yV72_bdLq3aBlqNlAI2PBD7+_4G8HrED5>H$aG0L;Bunlc0#y zl$Vp!S8VTN0y#mreYbQUz>jY^_Gu%!4>ph1AI2Z|DGxXa?CiED|J^?h*Kn4k^azvD z(YW6(nCWBr@%&!fl3Yf-*rY5#x!O?IEm6L8tDF}9V)Dr-?d1Ny{{VUIQ?>W;>W~;cIk~K)Skt5=WQT`N=i=*cT+%dogz`Smeye4Y$~Ji!jN7@6 zNvz$AAS(a&ulT?H5x@FPbhGbF)ZyGI2f5{5?Ok}=`1N4vT+N{WxL+ugeIj>xyZs!1 z$ttofMd!|YH{l!ZD@OgRZ0?iU1l}6XD@W-`U+|S7-8 zhdpeiq0SeUC0MK+4yte%#J zq{8MjKFqp!ODMV^Xaju=*eO~FW(F2|Iyzy2fwEMmT*u9BnC?RsDp7_Gq1iigDBn_% zhK!Bl6v7d_rY3K7e)$nZ=N}aQwP$MEwr$j;a#>lsaVexcLs}ALQ2)Q7Ul@H_7YY!N zXhBsXRozM@Q7btStS)#GC1)HjIoV+?(45TC$X3<`mhj4YL`yeyK~ zoRE;*NI&J(t=jX|sjwAM5JgHpygllpJup;6hD1#Y!W?YFU&uA_ zX&@(=5E*$Sj+?koYu7KQdgbPxS5lgI`gAf`TWIgT(37Y0ezvxhf4}ZmO5kf&FrWY# z7EW_G<+L&12`Dw}@(#$Ri4KpL zG(hsO(c@gMJFS=JkY!oqvKQKpY=?gwy8;@)x0VeaMQGlC&rn*fSHRf=8 zOp>Rksm(sL!*@y`4bRHV;^#jRodkI#Jqy^`Q9I6$9(F^P4FU+&#>b_l?2P@4WFaJe zsr&skc+}eNuRC*Q1#4oM6^xg4PI8x?otV0F=kLdVBPWG)AbxAUdNm*Q7Gy6t#n5zZ zKBxRbgYB~atHxqLfp~(z<~~yZ4YKHW;G09^9gUp-20oXsT!zWZA5t>(nxOo6)6lRG&$Xf=N*Ku>@ef8uY=y3C-I7r;rE6Uu zzVul^_D9S~20h8f#(Ex39yWTsJ~6Po%YmjB{~2EMiEsd$3s~K-HmNs0EH3`*V;Ir5 zZS;~YIAMe%(6ZZpNli*t_PBcqz|Q6kLig!@Pjpdw%WDt0Z$}9JH(93CWxB@<7C0 z=!cLG%NZ}K?Gv4E2Xe%&;q4b*ggh}CCg|v3t0?4AJ*ynvz;p`ec)ow#Tjd}t)T_G#{~9kW zuJj_!q+O#^6@R<$Ft-7HZ-k@7ZZ<~_k(4~8_Yx<$lIb^SD3b69IxZQ_1ozLSjO*OKlJ#1|{`%*Ki*|2WAZJz{^B2W|qSu+6nVHpVWxejc zs2D*v zeZ1#}jdJW~Jm>m*T0Vocus4|PlYSNQidVbvcV*@Jb+>*2K&66oZu$fDE{rnH+dZgV zU0t$L^064VzyQD&c{yXjdpjkcSNySZIn<{dzEn5K9;Bm_*tFW{iggj4blD&AIpkO0 zQ1?We$#_@`aB20bSbrHt-zP0v+Vc!&#QSTKQY2UFO59)PS>Lg;!uWje!py;?*tvQW zItk8aiIeASpq%ji0dspt*yim_8rOb5{a4M`Ga(Mjv ztmI1OEn^BxOz{6KR+KuP56 zTuavL)uqM<;a8+t@V4yT`Y=gc-+Dk8Ut+=Nsryzph#=c`k_#_?MM1!m{UD+adr^AYd6%8 zG=Q_*^yL0^XCD=hLJbNGoP%zn4h!2?Mq-LqLspkm_$(*nLvvaM(q5muwtwYwZNlB) zww&S^mR`h+TTK=2H3RCL@(1a*F`wXMKV|~=wBUaa0&LV1J&iBL`x6&kJkNOUDZs2TG>v9ZQ1J~ zJXXP&1y$HzD~_&vk6X=#5OUs!E^GsYs;R!-qON!bd=jz{YJFwD9Jqm~rj)}*>6_O9 zc&ZfHc04)v$bGac=O#4F1oh*YG&HmTF>rgV8|NyoDCgGUC-B9sKVDLso0B3$e=#!E3p}`?;CB|nk$lv z&XKs|+(YCe)zUj8AfXG6v&me${jS58Fgx#lPkID7ViAjFH~X2@vZ}I|$DKpW79*6k zDgH(`Z}MuU=c{r@fLjtNxv6hpAXOvFXyt3QnUG_9>J8MfRHV(@nfHpju#$Qw{d^M| zRtG*bLE6TvpkSp!)znM=l8hjqbKvQ(-@ZkN*j%rG{_CZcm8rMx(CK?;l>sp}B&8hh zuMG5YtD71dPXv41$}HWwoA^jW^$fUg{4NoPLmk$yV>;1Kb4>M3LIN6y80Sb+MRJ;~ zg)yAkH!TY&~f5CNu3;QVWN9Q zTvs2iZg63B6UZ`!)J$HI`s#S+TLL@}DHI5g!})f+!}I77-m%)W8+{EeY0jZGH%4an ztv=_&r+2iS2wQGbk&v<3o!Fm*X|E4p{ks_%6B80T^6e#MWfPLCq9YQD6yari$c;xY zoxGS4w|RA&t)1n0D!5&HLWZE9w++X}%8GVeZ0zdZ{D?xT=T+7FUI~gg^u7n&>B*DW z(KHmwaHcu6-y7X#(iBnCs6D@HG3DQ)u7b%m?rJjK~J3OQ|Z(nZ7GM)c8)4xjs5T=OW;HAOtHS2h=WHn)PJjJqe*A&e=h*x<{1d`U|`3_>Nx+Ju6!{O}NCE)&GVG*e`INZO= z+JB1l1+vKSv4(iRMA?{j4&XVV+3N#6DFaaMqxB|qZ7~PX`*6D)uot?W%+Adf^%d~s zINFXDVO0Ff-NysB4nboX@&{do40Q=t+@Zn^*HJgU)nA`iT$~-DvE#G%v_kF_bl6)r zZIrpGJ2*Tft1f+^i`^~LxGhL5D%;yT!Nd5{rEMg(H@c1QNDD|c%4VeH z72htjR_}72Pf3jsmsTcsgC!Sm#UGUb6$v|ZjPe|^d-Jrzi{)>db?8Y_SLEbGsLMeE zgXxIK#D%U;_v!pYXVw%ci(aieB?PhrV)z(+zCkppE9>rsi8luj^`Fo#z9RG#l|pwV zczKJh{fMLl7oLzjBuN+wkY{Pq@1}EG280I%g$B13N^Tz7$;|wEOB<$V_2QVd?vzO6 z*}U$}`s+@qmuzj-fP`cg8(ecD#>IILKD)X;wi|Bj`xNncrho0ujM2-~RG`mI`s$H8 zWM*Z>6s2qM3>7G2m~PowXxu-}n&<4Irx%ztytgq)d;UOox3Jwr>v8L{H)E%5?HzNh ztgX>j0ixdXdzjd4!>5QL-i-7NSY##f;B*c~1MYdzs01a=@z0nzxj03C>$Xw)9WEIa zuPOm4{17dry|gBthCF|;Az@LX>Fk9IIjDx;zaJSpZ4H3(>a##dJzkcS3=rEQt^Cpc z<2N7o{o)5$^Uk^GiFLe6`$zb;ZC{}>bH3kr z$Qb8Cs=T0B!js_DncAD`rwSX_*_CZrcjcH^1q>!4=zb6PD^Mw`_U)4BuhGBSoS9&~ z;i$UbD(Tq!2G{`~fK$Yh+836sjOv<95jAn*(p*rQ zLkIMcp-Y-&(P4D9NG#88j67#i+A{@zn|%jdW`37$t>=6jm&8FwuVyDj>%MDw;9N`F z>&&cGc`b1A^>Pi66|ET<7^$4f{nCB=9v7FY%W9Jo)?~8wJQOn8^Y2JLsD>M0szpXs z)ur4-9!5E7&5u_GQVJaAgE~Has`aJw5AmO#>=q{kz1@XO)b1+lM+Idi|C;K#klLdM z=5R}Ky}t^-y=L}wR;pq(-^$I}<^~S8Ue$p7_3QRLZ`p7O)8V#kv+SH4yW6)9x*_Jq zPc0rfQvOG|mOBZd`Um;zlk?~CcL;Lsd?uCLmYI-#7V46GdS7~%o3p~n-I7q}j}W!L zL}mP=>d@4RBj$$2-9#JO`9LNH_nC9^@=j~vtE!MT_>p3)W)y3^0kvs+*jf>H#pk-? zTwIqarhaE9*8+`yz-gX(<6kX@F0zc*LjhlgN3X!-acF3siy$*sip6-2g|v)o!R=L@ ztM0Z~QT1L);lr7(8i{mmqY2)KHH9a223vOLzCYEbm9``^r!wPTshMqgv zotRg#y7m4eeVa5M%k^TbzWcdIROr}0st4YXWzFMD6>PL zyL`A_T2!(hgTEe*OCq;_)nu8fA!HRGOI#}~$gyl=?GVPQLs^2ER?G|=*I;u|QEmt& z^~MEQoowHlw~9=$wY612;k%o!%gSc3;GQoVF7(L-<4n{0cwKYg6K#5qNkiD{*N|(0 zr?)cn|EcVk`sJk-7q$RykC(Qi?GnWHL;o?y+{s4!Jr|9Jp%X2iXVGgcI67% zR>j+xs@rYbwrtbBai|skH0TR>H@VKi&FH|%dm8HMmUC4@GXvkVO-+hSYxEpK;($T> zTynuIL_jlt@PD-T7En>QZ@Z|zzAC7Mq9P#Rh=72AAR+xa5=uAHBGM%}l4F1f2&i;R zcX!MnBA|pw3?n%-l0$dwd;Ip^>-%>6_de^av(7o|92W~+I86NFdG7nVuLvcdKttJs zE0EYLZ8_(Hp!91#S;U6pL7MGNj$$Eg{bjHj~OmG=8T=^B#Vczy*D(`b+>dq!( zE%YkUw+~?`UU4LDxx7wSYVDkCJw4WCaNn?TuvW`&>R@+E%JI4jG_KHYfUhge)ia|Y zm3om%QWaF0Qp!tL|B5MvzqG$U3or? zp&Zuw7N^Y2(EEJ6oSaS*8Qe;?u@7p8#3l40Y!GN0o&9%?d_uqG;A}S5H(;n#YBwMG z$p}*}VBY?FKZbPxr`#yiCG5pqEZY`v z&qQ(T|ly{GT;FX%X$?Q z;MqAj_Jm>uZ24cuc48qr1ZXI&t@Ha=IV211S@!;5I4eCq3~VP(G@3JY9MwGk;Nui< zOQkdN-aSmFQcRsm&*jrGFWF_^zN=%r4mw8y;44kTp2NUJZOu+8nsnmQi)Io4&b)EG+ah45n~O&pBN2ZcbKhOK+Vk^Ts~5MVBvz-8kmZCMXH_5p#pu4L zS~~-ER`<2d`#!R^rFGiuTwu${fLiz9BX7O$K%Br%B_Npjy5%LGiaxitTF+N7CMI%E z8FCzZA4gxjijlLfD~S8-Ibm_ZZDu#sSO@K3n9zH+5TlvL7!(avOQU zEHia=jqx3y$)D(|IS7#f0O{DqiGK+|{d;gqF_F+v=80DpVIsx$Np|*fgiRUx9kF-b z?D@n)g2ry2|KscXqJfk*b?pD6f8AY`sFOxUoRxV(E~6IiWkcen3Igf>zeEF08b%!< zI*sT8d^tJxgui_&CPmdQKLn$~uOC11Crfu1NtRF1nYH>|_XQuEW2cgD!kFYEiu=$X z+*_(%Hi^Oyx6|HiuE6}`H4n)fw%H027OP&90?Gbm@Zr0MYHYl`sGX8@3+1GbhTCkC zK0g+8X@4Z;+86eQhePZI1SmiYYe%R6qgEZa#b5>#z+!sK*?=Gcw$^)-<`-oEDzCXr z8a$P^qyfNSQmPB-*eXz{9srgd5E@E*rp@M;jD|w4?j0&hIZETM<@MRHOKnl)eqS8W zmZZzjH@^OLb^&xyK|u;kQa(VvQzC<0Bgl~M1CE#dGMnTf+&#WX6G$17N zLnO6}V1og+cbQpPzw%;EBPPM<3iia2k^J9Jl3-V1S@1A2T7rI7)OBeU-*mPkuCl1C z1nhaM&tIM%Zmli)v~0GZfPB#05(*$Qx4s8Vg3lvC?s@%7BlsKwURPl`wzI(lQ@_us z7mgVI1#ndx3JAOy)a3hqDE=z)El~C`LfnF`AZ~1CWBb9wV}dUPN@qB=x}N&3BqI6E z%S4!-MqH$g(|=@uahlp()c2)^lxpw63SgXC&_;nFxbT-RkZb_<5io#;>4jaafcqL7 zwyFvO5noa}Z7E+wfIw=}$fXP#)Uro5HVj+lOkUX7&_c*2gucLsaVs_@3%WI!B1766 zfbMa^_E3L#xVuYLp^4waTK?qLz>Y(E@uEOQ1@_tDzSNQUwl)3&I68ZNE`lpodVG4C ziDqrz8;LZvflaU$rZAA^myWl#whF$&rw&Pg;gP>*X93nM7BT~^zALdSjQY#ivn6R6 z56{XPXZFAr4e~jhJ`i~RA&kO>;pYbv48M!4vvj>doikh<9ENqzUQ$0XGjrW&jeyke zp?CvURvA$FS{1_?10p1-f8^wJpz?%$5{B3yG=gEg&Ev=4CbBOeAvGFW6_SQ|eg=JH zRF-Mc79BkUI|3=1z`PVRBdOONYHNi}OX(u-0{V`ndm}?v{3tCg5BBRTw9J{Ag+PLo z`r5Xq zoNgSB8;W*G9v)uaEtvOla*AtdVH2^5Bz2oI&^4766fPZZU7A_{qz*d3nm4k3AA!ma z(=mJd5csaDT4X(RcYj(5%yGae$>TND80}yW6~92s*O{M3PlIe{hyh>7==x^ugyvYD=ioMB)4=Y_ieki+D2L;U!0xHNP0j87oPoBt=C0m@vD}ohg zb8t~!o+6V1X zuZhu7P<^MJ&{7Atjk!5%h)*1L5S$aW)kfix0V zRgB_Fsz0pxhYZq!SJu{!N)%4QZjfM#!|S-R|A%5p4|_9kpxoI%v@i**YC7UDVA?ZO zeW%AK=^if-E8N$Ylc1w`%n6g{+h>z9H8U5bK()cd;%P=70zRvNB!dL27($ud+kg@! z;j#Ub7IO>E>Bbqg=^#sMD_Fy9=@Z&V9B-GA#9W!90!n4v^3-4g9xVxOJkx3aRyvOp4teEZ-Agt;#U zPARx^a+2_gx~cccjer+J<`)eT2KM5f(=O22>WkHK1{q?VBK+l?k#9ei06kzr>IR#h zp#81dm&wT=iVPlrJ1>7pQCXTziO+Cs2;&J-Y#JG)iO$HhuffsbF|3HE=C|35w>K1p zL_z4EWDE^WyC*q(sUav0zJOquo^EAls!>Qwx?JVH*4tYOZ<{n$VWqHeIM3|H%iJw&>Vs9^>jj(nbn6a?UxvGBbs! zp}O-zt^-6c3j)5$!QMvpf!fW$-ASQ-k$&Izz#nYo5%?+m{%|N4l?0hb);3m^5O=fb z51-=2fT>Y9EH{98Z+`E9MG2_965uk#B=Pz;D=cXn`ZQWvk_h0Lope)*lc#m64(v`k zIyVB6^it=N&Ui^&E{gFLiG|R60h(`aQ0W4Xq4uZf48aGoAz24{cMsJ3GLn2uZqa)e#GZSYKQ4yu$2|M;Xj0 z>b4JYgUD|H)&&Q@JAEh)&Nd5>V3n&~U{Gx>Xcz)xo%P{b*xDr|^jCNGd8KqoMd{@U zhvtHY-HkZg#f82CT~bzLYRkLDUwrSe8?&Xb?jLOq_KK-}nD5(XkUvGi1cHk3!AkpJ z#yi%-131PLC(w+-P=>91*#U&CJz6lXaSS;45U>wg-||8`0LUl=~ZFaDqLi~N7uuRBh9K8Ie7 zHt_3(z?7RieWXU$8e*+4{<$^T^1l3S@GZz0dwq7&*t508rdFZ_hBEsz32a{7o!NQkgA zv4WtDN4(`wpS&mxHc^v>BK+Gou)lyT_Ju=?Cosxf!a-OcQs)iDEFOxd=?;BR+R-3^ zLIh#1;LiYhwZIgRPl2oeCTwwnYu9`s?G1F?IKZ^D-TGkj0sA7rb=y0*p}hTrB1FG3 zaW=ad$jQqEGveTYfSu*B*FiyC2kA#~{Dy&&L4nR>j;r$w9YEbB1ynInTJPjhZ{^ZBF ztb93%d<%+A9G4E*@H;s>MTB1jl^!_)xZH=B-!QwD_9Z}WF{G)6tv&p+xj^}0<_uD3`Mkj=Uxr_|eCCBQ(b>WZmv$JtA zF%n+e@7tzelX1Lzl~m>f%`6CueHjuWlvKz@pdo!CQIlWCXrKWY%LZd1D4lH>;z)`e zuuYW#wW5>9i2!Luhm5>5&_Zx|sr((+v1vQIF?x6aX?0+MG>ZhDHdrJUI{Y((fJ^4_ z8R(b-Q~vgQ1-!=f^|G1HL=Zy28w8^ ztQW|W3NKUtRED;`ZK|fK#;C^SLyLx%s_J`5AAqf4bOs_G81Pjmo`GlVJ@G$?ai8~1 z$ubl}ZEx?2h>H5`r2^B<>-4sG`hO-5L)`9~AMDHwfEd7G85qzTafN#6g~zg~44o2p z2V@-vD=FT_kgDK4($D@>!Hn*B61Fo((YW+SeEi<;KM;L4O**HBGmGS|GEKSAJH2SgB@Ab5EzYs#}ZIAUVx2qlv3;IcBY>oI=bO9iGMpwaR3 zlc;fpSzdShFe?|A22Z*5D1=A$;4||SDMMHP+CD{XhK-~O2$0OL19)Ic3xNM~bNwV1 z6alOK4h)-Vc@1vE$nVP+q&xm3eIyWLjzryDrlx>eDCM*s4Fm7WLiNTJmyy6Q(b$+jy;_L!~$d^-1Mwt1)vV~ADc;H+(;(dzpHxNbh z-kT;T8IHoZqgSQlu+#(B`Yx0X(V`4eq$Ck#~vZ+0RN%Z8JwlP-lag zmF3DuUS9vkF|g4-T8QcCwnlrxtwcxRB&voHj((#ESu;0pe#1bz0u;~Z6u5FtTU3@c z-Jvl7v1ve5R3+pv8>iYEKRi(#eT=|7z0vwjU0a(;*kl|8tl-YbVYvO@w;!0-9_{gb zhBZn+t+X#tUf*vZ5u+frZ#E}<5^N~gp1XT&?^VQ#S-3$P?*b7OOL;NChgzxRRj>x3h$UOb1ySEVq&Y6@{lDAho*InkdWK$hiQv42{ z?7l&fGk_mEY>8(OXU?oPioPj0T+(kdr%8&r?ez6FLK>tvmJbFajJ>UN%RN!6C$>U= z(~oc<3J8#Re(u!$4R(1a{ZTs*-utWtp9IUOg7qr^LCs)=D~@Mh-+#jNKPH1a~9KpJ!75<|COorXbubW_k}ZPA#Au#0beotS8> z^=;Y+f`ml*w$)soXz-H?zRH&epZ^5SxX<1qzF;gNPb$`$9#-W2=kV#uZP3aJDrYII zZ2Bv6g6wd3E-}kW0vC~u^C2LQd-powTpsaOx5cPx6fjPR!-Y_M78H-81+>Z9{ z{+bDI^!%lM?}mMRerRPZC-VM)&*m&U#$z*DV8u#pqeWsRhWx}S(DWuIE)n_r!bV4865R30jG zoJg}^=QS$1mEyT&!7gEn@pM`(fUTNCBU55$()VCbgURQ2LsO9C^Zfw!OeIedUg52s z@11a&b#r=pdZu<+x_jn3)EmMEyWE=BzjcnT#2VL1)InQ_%(XO!+Tl1Y$5L1|GL#3C zN*t!S?xbn4hcKh(zPErVb#G+vtbgbg=!3^)&Jqf9_D`Oj_Ip!-_8xf!NE+ys=AWAN zl)+8VA|bl#bgu#IZJR?F>X#3;3eHq%33jLGJ|2w~l-io@sob&az~}8$qYdh+Mw&8u zW+Qow1l)#9K@|&rjo#*8G-wh%o(MeW94^y?99&vIYV*>a zd|}$JE$re)Uw}2#nW!cgy1%kBlhon9QSR$|oLINk2Py^@7SGGHw8Z{W&mZyl0`A2@ z2kj}^N%TQSWn!Wc@@>ZP<1BBeloS-sQc@l|c2KdaBAjZEIo*dC);MWxlCw%%ab!=B0!A02vWF)-lF(c-EOyo-TJMXxp&|HmgHQQ6B3en_yBoXNJsE@j{Tsi}Tiw0_Q;-5~U4D=C)KG~- zUuw8Jn1)%tfD&$SHI`Y^_+Yp)s?gwYHMcNb?0qz1%Om~^?KKooUWr!MfCKSO6 z6q&D=0ERAWosx_a(`pg&uEU%oM~^?asN%eauvj0D1S7Js`5Bb{+O$@}LmN17%(o0~ z87|`XUt_F!QK-;A7tnz@Xx0ElaE6pZua*S-0-}AY* zar&mOB|Y`>{u(cj!S-QWPo|-#CGsukO7-5%)zx7DZ>K-AzP7csy6!QyGh@#jP2G=~ z7bDh@f-Hjrb3kc@mU`-G;X53fuF_o*|^4J$SqR1^khXa?8UV7C~T` z|5{HUn=URcVe{+ToZ;3JXJ=HD(e~cnS;WA}(+Uni2lAud*@?QPZ(V-0Pv%t!juJey zlT*`uX=ivH9NOmRq?Ys?U7gDf76t1lSz%EV_WJsbHHcPrYjFeCHfN_2n@23Lv#mcR za5=*&1+5#0mqBa&4c};R@YpydIU?B|1lI1}yWd-SGU~w-q!|(@z^2wfU(duOd5>^p zOoP06F>sn&??EB(9aZARyV9NI<`)YMum)DSOEr6m4XB}Nv$kn7g+H60Oi+}p?B+QN zJ1OUBFch^oTt1jP&q9o>5uiJDBC`+)u*$*v~_ADSR z=!l-jJ-!_t8KHZ0p-MY9f--ZL#w=Mo*VxBw`aadj(f1Z+L)RLkggc&V8Np$R-aG3p)L!HFqXssT`{?1AcdDs*hdXYtO^nZR z(G%S%WJz-Urjpuywo}r=%#f*_4Mm^0WA_bOTD+d%h~B+>hvh5jY{7X(`8*Y|&W?`f zkp^`x-|?M=+FJW>^SzNix;0)-94kfSzGi20pnk!Jr65OoZD6D{iWto(}z{JfRTZ zZCwtoB^sF+Tg>fi*G6+luxn6Ikhr+G7AHJ=J=QzbpMWBkq$|L(H!wIzRgL-`$sGs2 zpB4(?E350AJO%qE+JlQyF&-{vR zc1j&|N*)B0>@3y#Lx7|uloXMEq6zjLu|#7Jt5`Ei)#0VYtixlK_WkP5svkr3RPMdh z57sWfCns-F%)hO#ce+*M8uYu5I|b6fIILQ7OD!NN_m)03g)%q_?)IY{ivtz8tg$9- zeQ-2Dl2M_y^t99lL-mtYdv6!x_C;^;@CeaU0Lu`h)-19k%#1Y7d!LRIy!SdLRK#6} z_3p;}lgds!o&idEKVm&CL>64QaNQSN#+{s8+P_r+w>x^>7=mN;4dDYu)k_wj1cJ>AYWJga3i` z_DGO$mi5S0&mJhVL-7%lX0koq-Dw{M^ZWX~(IdQ7d$OUr`NOd0%DFe7)Ssv4MkO_W z-Mn)pcx|R*u{YaU3mx~yb*|2CP`hm~3BAjQC`f8}oOLK|IMqLsSc)G&o4M*h2xLIR z9G(uj>f2Pu?THW&Cxu(*2<9y|c8{nUpy-Ouhb-i(l+cgUkRvK3U*T<^S8KDM=CUtr&T#keCk z>u>@)=O&Ku&CJws+mxazsB>9)qGgx6<631owud6P`%mQqH8|7X!pLZf)tSF=FO=T$ z=_IWgKnmdg6BAx$I;CSgf+9*l3jvq0^;#DD+w;SA? zh?J1e0yvI?N9b~Uk4klIEli^BkvYPCN3zH`Bz|xW z2&hG|*Gq2UUXnZZRaz^6qtz#zHE{UzdS-p8*;V3y)tHr<_4!pzA8DI1F#_{M2zncI z2FW#THldPG!kJ?VHwJA|(tguS(qezD2)nh%GGmR`8n?Qg&(D7*5Qq!arO zjd^J1zl2%MYHjMlt+jBuOG21;3u2@nI^gpa+P}4v9eS#_Y2A&%AIMP%@UJpFZvEE& z+@<{pmIDV~q7i2A9iy;vYy!LcXoEl8X_7nJsl3?jp`J$PWk%FH^a6R?K-Kp4&YE#( z;chLoQyV><*l1ygrEpp{IEKHYeL9sAZygZ8j%2o!7wcu(u&;Z^Sm;VH0+Fl`RR}H- z^*Mi2QFUf(WOl}jnD#UiK!ob-xV-}5KxKry(K ztVUJ8((KhXaMGb}qhXKev)>iC|7!oU`AZF>Sh(KWN`w$5qyXUEmL@INyJKU9wA@C! zOJWWZJ6}zimYBArmPg^t+c>2ZIJG384z?#^hik*Q6-GSfhhf9Q7C%k|`Z+uTOtmy{ z8g4l{9mkETo%&Oi(W3Api`MY$B%jq4$bo{ShEVXY^RDvJm6grN&DB3TbcEYt&$7v% zOUGwwdhRmKpu>2YMWOK%9Mt?D)7zk&hJ4v`QpWYCndvv?a!coz_Zp!@0>6j7cXU0_ zm37^^UG#=lUkTjPZc0cjre10jq>oceWvWoj&C$99r5`vlbc)}xn*AsP{S(wtq1596 z?Cb_$i12!g0K0>nVG~ zC@Oci@g7*`?Xsqa$KT0Lqy?yu3@pF+TF}>U(LWO>TyuyfjeWK?kCrf4|zrhc7RXt8nx%Tv>a9a`Yl;l|D(t3XY_Z67Y}(-Qathr zMcLh2pmYN_yHZ9plh(a-bs5>scoCb;`f8=!>E+GMn4@NWg{WIb#ZRhpgKRVlM`+lU zat1Fl_kO)Y!$n8!MLh7kB$_~-V&5nmJmSwK3AYFGZSG;-U-T3tQsh62f6O6NrAYI* zf13Y~ecwkZJ(u6C|D+5AiBT!*FB&Sh3~S1g^;aCu1JQDu_oI`d-;bX^DRwGJ&$~Y( z5POy7&%f}GX0A-P0!S@V&DnCBG)er{TrQGv{v97jySX#wq6_J2`TSXLQQbgKjaTc$ zu@`aQyGAOs2l0p-y;m{++i$g(;?Wk=F7!oi$BwBAhp|Zx|5VzRyDuA~KPOFk^(Q3C z>9;E+rs@AHzdypr&;h?oC~iJi01~b5Mt7L|Asr`L3oCB|UIGL7xqtgPNMS4mVi|ON z;PJ3U0Y_|?6C5=JC}HLSj#$D4`yN63U}xrm!9o@Q_6!VYoOB*N%EHe>NV|iTO1r+^Be7d zojNvJ{}3ix0`&08389k7*ahG+6S-bxeEQ0vnTW zAAkeLaY=~2Ts^z$WqGg8!tI!Lvr8UGpb8absNO8Ah-HW}pR;@MFjM%wDNMMv+RaOq z9jY9s@cQ9=v81fRPZxv*ZuIJhCo90=(VTnp=I=j47=Bq2hv@&3?-}-=Yc$k1!8-8} zM_E45)wNRbc@WGb3TsopKiyrdG`|1pe(cFpBcnpv$U?lsuVqjFO~zOVo-Ok0HGuvD zjI^#_uYr!N*Np%LJ2)1AHKuTi3EZ#>6#ZPKQmgbU^xJB~Ky_)U zi?0}<4*W1SE$zAC_y7d0fDx{|0+iNxO9A1k7#Ogrosgp|*8>M=7R=__mWqPXaHT_G z!()J`I5_rPL=8ikK6DRgu&XdhIf_e4CU-lPl$L}f-8ItFn;RYd3E|o>A+o6i&yt}o zQ#lrJNYl^=3Jko;$Ox9ffPki#1DrM)Kts#V1Gm#%5fM=J>(as?#%1ywGk9+43;+H9|r{f}MTPQlO@)3YPokrY0>tGyWK`&Mz(DPuE%;I0>AdhjJd1zdyLy z4JL@YLb6Obzz82djsukjXu6R97akrCaR!1n?%rUzlM3_X=4Q4mt@i>yTt`3qWa}(^ zK0E*yyTFi;^T?+&PXSI6q}a}F5KZ9W<`#rG_fvkTe&LS$H8`k{D`Yot<)^?u4!570 zo8P>6#+al87~qI#Z~5!k&_5Jc%?h4?6B~a_8Xl$+^74V)YSWY1Vf6HBpB4T#t z3+Kc=(O#n&Bp6%1ud{*h z@;GGj0|~cv0Mjd}u#L^lvSh^$piQq014}tU`i>Q;o;y4SS8hLh537?)8tvNZE%rOS z#BsR#626E+XA5X%zJftqRNVaZG(fZXMo8$H49!>#>jpZ=v5-SwSK)B8HAO2^=E1e1BD$ysocLs;%|^{--Ajwv;)rrUVe0Jssmy7=HXhCQXh*z&qn z3#C;d_%yJyF8=<>cMGmy6j5?%iODq!^TW?}xI{Nyy`_0`o|zVpz25@3`m0x7h_4Y` zQTU@x@Z0oMRJ1*+s`_F01w3rLr`N3%VvI&cAZ-_Xk)6{sk*QrS#4Z*dc+w;+=sX6% zAf7r!Bl8E~mFJNzb3-C*6@+q6=vU2qnuEdUXAWP8HZbtoqhti*Ms) zRv8~178f6!J;TE+>QdA_aQs*nFU1g-hNfm6k7GXdm&doCT3Emp@$1)NIcG9_Qpob? z>MFJyC_9g=s`b1fIPCL#6!;s75%$cu+$aIJo?_EqU@Uodbq!8FSha_J_`qlT>+N8y zFfH=A=U)6>ACjfsiPOUcU6w$d1t+$_Oci6R8%+&eCc`!5<@s=Qt^~^>e2ofG&M5ed z-3<-*=Kd0a%rzMMMe~9Dd50VUfCumN)I$lykC2gEuz0nEjFSAr4`AXkqS)C1f4?nM zkpveT<~4>InTykV6P(8g5ew<+8^IxwOTMei>qC{OP7sebei41h@b{@x@`Zq`!RQyj z-JHYUBt8M$W$$E7A!dL&<@4<6?G0LCr*kPlaxgG zk&v0&|LZyzSI^*Jo0D9nY^v3Oz-Ssy$)a!UdtaY&X71{1*xif-wiy+byBQTv?wq9M zc?z|-F7{o1eMBxo=``&2ettS>tjCXca4xD<6LzH2?UzGZg?N_!DKdC#Cf+2 zjv)r~n)=J&py$!yfoOvA+|2DO=irX9_k-0nEp6c}1%=&kh7xR0N$3nTGu1i=T%@U+UY5kw%+C5U-#0|3=20iY{#hqCdu=pE8yWkvG;r=cfYQ#nOS=Gg>pR>U$Ch2^Y@?02xfqFvkH#p z%M*KO<9cjf;Ad1m3wr;9;}}o~++mvpYd`!7@jH*3n_jv)*!}@s*mKdy#3aE*bQsja zuwyzom7tasYo4#DM=dYYYo9sx52n`7zIk(F<17^w0ZcI}-;yyi69CUhl{@@ZXZ1QP ztW-TaFQ@XKY|Tv~^VS}59x$2d(a}$;H$iE6a1hsr`{PgMMVYqh;9UWkHz^939?ycLbxik)&Hg}5WTyZLc(0+k>_L;M18yjoE z82AhVMqtpJ198@(@eRSw))xK?OdaF!c?z;*Y6b>%0KUN}0!aFwK3!`IR@Td}P>QQS zUzOC|z&)J?hrW&eQShp&VxtP|& zFkch}7O*s3^3S7H(<8E(HTdr2FHj>N_DojrO z)8%fCu9uLI#J9V>4Zl^cw>UR9fc5r=V{FXeeGv(Ufga#B4JU-fL;?zC*!C6hHpMZ{2+ga%-qL8Sn!*bW=0MwCEc z`0SY~X9RpsNT~*_=vL?k3>Q#NZfZH<6>e^%duRmXFM!yJWw~_5uL$*w?2NUYsVV4; z>p^5TJT>*T;Oh_N5alhPv(9pz zw?99e-oQ5NY&BBnml+i`l?A6+0K*~0fAUyWQ@^FXCNUsITSGEe&7c*-x%xgV>|idw z-?T-dnOFL+WA^lNo`VdUtK0&l2H{i1TmB;vsQpfyqFmkFtU1g$c5G<%PppFQ)jv|f zh-;)yl8)uSet)4Cz1&MfG3@^1bbhN(Ry8vb$coE^NQU>ssDtQWY1n>F& z^>-~a#r@BerNG=yE?lzi?m z6^di1AuoqUEJs%XPTZ%J(i>MqWa)zB?*t?J{Gn+rP}nUH1_ljnUz>wcWbbv1>dlLh zv^sVV3*meP$GC>@#VAhK3%b-=ORos0t8-uk<2rQG={x|fuq?YJB725UPR0Dz4j;$P zx9l?s$;olrEEPg?OUc~Lg#J5eW;7f>4F-kplU};3WW6C;F@uGjM|^*7Mif(=%%Ei> zM2}dU`aAQp@gVJ6^&S*PiL$WK?T? zsBvFir$aM)PU<;{6`SSvDy92FkJM23$3Cg++XY4@{>t&pA`^`Z3VsyB1#yUExwq6$ z9(Qh148Q+#bAGxUS=gVbue!eU)ugm}WMw?d*Nj*4k*4}#7w<#(4TggIxfx2B;U8u* zTMIwCzc&;l$E{Jh-WP_uP^7;|7)NMJSDESS9;D2VJr^?fICE!yZ#|09KWe{d(M#Ef zh8NH7-+b=fxl2f|o%tmZW_GNA^=F;=t;tE+&4r)VOEf4kYdb$`-KaAb`P-~J-#FMk z2OHEFljxXo)pB7Rz&qKob9ZHQWlhpvnTjg#Digl^CFK_LYmYZ`6wM;cg@!^?4OR9H zxx&P#NUn>47H?WYeiO>m45F&msOAmzgxA~`i);0SR^%T_WvY*4jnI%TwJeUX{`e25 z>X=afjW0VY6fpuN_0&&@#id~ciYM z%OPx$BihZ^e1)}_L_9p!M-%xB2Yl9@yT@_*e$+aFt+E}vcjw2aGT+EnT1|^NH}S@8 zr4J9Cz{Dbx-x8TVdQGl}+-F}q6PWgvjqWPWWWf-lY-Y6Yvv%lXIH()Rbtw?VPGK|L zK9jrQxq2qB#$TxZo?R*|#4loVe$FbfmA+0;O1JSIN*F=gKgW+w^H91SA6cU6*tbOQ z_Fq;KPcMhlc%E^j0+~r%{~2$ZdB=~M16VKdtzM3rU$S0G_)^pI(h`*jSrqCWCk@t z<8y@F`&Gs&74nWKWHV$qQ^F&8uqlk^Qc|0B0+OBYBcZ9|o?`k|0euy#KA+<5r)xIL z{CyUIjTam!dG`3JCr9fQC38%}^F<@su!m%7vpKsmq*dzjuA6up|hgbkzhY}H_xEnVymmC`=e)yn4GKa)Z%owzN(AR zp1SIbDEVxGSVf^Zv{O@mo&xf%&`U`UD+@pBzTAI1DSB7XDnw%xqx)`tp#u@8ma3gU z?D(r|#BF`_CPMnGlnUZ2R~wqrZtSSP<|)Fr%Q7b;>xbQ61C{G&3tR>l>(ogZ(A`z& zb6Qx|FRSz|#TPGR(#)*+BE7IYJ0Au;B_-23l|-=e55l~3AXec6N>}fRK#ZsVNw}R3 zZaLy}DE3A?Jbu@)6Z_qkw+~j%M`F|=_PhO?CmfZL$LmhcbIe@@-CvF*NEqIy%XP!? z*jR}Sn+HM0ZdVV@_Qpc;|I+^9(MxEPA>+G_oi92xL@|n#TQ_3WUVD%scqWYsGH&`I zSC&dy;Nq;eXAQc2cTaQ6TfxH;8>p zoz5bWS6O@?h`N*@9j^4=(IhLjpZUN_aF}PjEUlw{Qh zcLM+ZgQ)lY?}GmV=G|*Lw^U3%6y{L+!X^C~{VG@%_fsjW)|y_0blH6fOAKb{YpqXa zP)C{M@8>5i+XRy?eN#5pW9jPdXvNdPdXa=Z`tsGoXiE9?l5PQ(w)?u^TU z2WJ>M*Ndd43<|nxXuIk?Ym6}yTW zf=&Sb0Kv7(vMdiH_|QZqT^$~3RSv8M8;EN_w9fj(~Zj0Lw06z@M_xy_WmbW%bEo@MP{`{t!31vBJ%TO!b=Z`vRJA7JGR}j7czQWKlZb#ae|k_xu%<`vu3K$@F-WYigK`V( z_D3g6ehBFBT{#DlKk6I5yCy(}2^|sC=H1UoLf8EE$G77FC<13%fK-o;-{9sJrT<2q R3|r-~hce321<1#*{u4BRvo8Pu literal 0 HcmV?d00001 diff --git a/ui-ngx/src/assets/locale/locale.constant-ca_ES.json b/ui-ngx/src/assets/locale/locale.constant-ca_ES.json index f52ed102f2..db7d6b06ce 100644 --- a/ui-ngx/src/assets/locale/locale.constant-ca_ES.json +++ b/ui-ngx/src/assets/locale/locale.constant-ca_ES.json @@ -3646,8 +3646,7 @@ "assign-rulechains": "Assignar cadenes de regles", "delete-rulechains": "Eliminar cadenes de regles", "unassign-rulechain": "Anul·lar assignació de cadena de regles", - "unassign-rulechains-from-edge-action-title": "Anul·lar assignació {count, plural, =1 {1 cadena de regles} other {# cadenes de regles} } des vores", - "assign-new-rulechain": "Assignar nova cadena de regles" + "unassign-rulechains-from-edge-action-title": "Anul·lar assignació {count, plural, =1 {1 cadena de regles} other {# cadenes de regles} } des vores" }, "rulenode": { "details": "Detalls", @@ -5692,7 +5691,6 @@ "show-empty-space-hidden-action": "Mostrar espai buit en lloc de cel·la oculta", "dont-reserve-space-hidden-action": "No reserveu espai per als botons en cel·la oculta", "display-timestamp": "Mostra columna timestamp", - "display-milliseconds": "Mostrar mil·lisegons", "display-pagination": "Mostrar pàgines", "default-page-size": "Mida de pàgina per defecte", "use-entity-label-tab-name": "Usar etiqueta important al nom de la taula", diff --git a/ui-ngx/src/assets/locale/locale.constant-cs_CZ.json b/ui-ngx/src/assets/locale/locale.constant-cs_CZ.json index c0950bb047..7402aedc5c 100644 --- a/ui-ngx/src/assets/locale/locale.constant-cs_CZ.json +++ b/ui-ngx/src/assets/locale/locale.constant-cs_CZ.json @@ -2411,7 +2411,6 @@ "search": "Vyhledat řetězy pravidel", "selected-rulechains": "Vybráno { count, plural, =1 {1 řetězů pravidel} other {# řetězů pravidel} }", "open-rulechain": "Otevřít řetěz pravidel", - "assign-new-rulechain": "Přiřadit nový řetěz pravidel", "edge-template-root": "Hlavní šablona", "assign-to-edge": "Přiřadit k edge", "edge-rulechain": "Řetěz pravidel edge", 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 87579470d2..582e3e2902 100644 --- a/ui-ngx/src/assets/locale/locale.constant-de_DE.json +++ b/ui-ngx/src/assets/locale/locale.constant-de_DE.json @@ -19,6 +19,7 @@ "suspend": "Unterbrechen", "save": "Speichern", "saveAs": "Speichern unter", + "move": "Verschieben", "cancel": "Abbrechen", "ok": "OK", "delete": "Löschen", @@ -27,18 +28,20 @@ "no": "Nein", "update": "Aktualisieren", "remove": "Löschen", - "select": "Auswählen", "search": "Suche", "clear-search": "Suchanfrage löschen", "assign": "Zuordnen", "unassign": "Zuordnung aufheben", "share": "Teilen", "make-private": "Privat machen", + "make-public": "Öffentlich machen", "apply": "Anwenden", "apply-changes": "Änderungen übernehmen", "edit-mode": "Bearbeitungsmodus", "enter-edit-mode": "Zum Bearbeitungsmodus wechseln", "decline-changes": "Änderungen nicht übernehmen", + "open": "Öffnen", + "decline": "Verwerfen", "close": "Schließen", "back": "Zurück", "run": "Ausführen", @@ -56,16 +59,27 @@ "import": "Importieren", "export": "Exportieren", "share-via": "Teilen mit {{provider}}", + "select": "Auswählen", "continue": "Fortsetzen", "discard-changes": "Änderungen verwerfen", "download": "Download", + "next": "Nächste", "next-with-label": "Nächste: {{label}}", "read-more": "Mehr dazu", "hide": "Verstecken", "done": "Erledigt", "print": "Drucken", "restore": "Wiederherstellen", - "confirm": "Bestätigen" + "confirm": "Bestätigen", + "more": "Mehr", + "less": "Weniger", + "skip": "Überspringen", + "send": "Senden", + "reset": "Zurücksetzen", + "show-more": "Zeige mehr", + "dont-show-again": "Nicht wieder anzeigen", + "see-documentation": "Siehe Dokumentation", + "clear": "Leeren" }, "aggregation": { "aggregation": "Aggregation", @@ -80,9 +94,11 @@ "none": "kein Wert" }, "admin": { + "settings": "Einstellungen", "general": "Allgemein", "general-settings": "Allgemeine Einstellungen", "home-settings": "Home Einstellungen", + "home": "Home", "outgoing-mail": "E-Mail Versand", "outgoing-mail-settings": "Konfiguration des Postausgangsservers", "system-settings": "Systemeinstellungen", @@ -103,7 +119,7 @@ "timeout-required": "Wartezeit ist erforderlich.", "timeout-invalid": "Das ist keine gültige Wartezeit.", "enable-tls": "TLS aktivieren", - "tls-version" : "TLS-Version", + "tls-version": "TLS-Version", "enable-proxy": "Proxy aktivieren", "proxy-host": "Proxy Host", "proxy-host-required": "Proxy Host ist erforderlich.", @@ -114,8 +130,21 @@ "proxy-password": "Proxy Passwort", "change-password": "Passwort ändern", "send-test-mail": "Test E-Mail senden", + "use-system-mail-settings": "System E-Mail-Server Einstellungen benutzen", + "mail-templates": "E-Mail Vorlagen", + "mail-template-settings": "Einstellungen E-Mail Vorlagen", + "use-system-mail-template-settings": "System E-Mail Vorlagen benutzen", + "mail-template": { + "mail-template": "E-Mail Vorlage", + "test": "E-Mail Nachricht testen", + "activation": "Nachricht Benutzerkontoaktivierung", + "account-activated": "Nachricht Benutzerkonto aktiviert" + }, + "mail-subject": "E-Mail Betreff", + "mail-body": "E-Mail Nachricht", "sms-provider": "SMS Anbieter", "sms-provider-settings": "SMS Anbieter Einstellungen", + "use-system-sms-settings": "System SMS Anbieter benutzen", "sms-provider-type": "SMS Anbieter Typ", "sms-provider-type-required": "SMS Anbieter Typ ist erforderlich.", "sms-provider-type-aws-sns": "Amazon SNS", @@ -138,6 +167,7 @@ "password-expiration-period-days-range": "Die Gültigkeitsdauer des Passworts in Tagen kann nicht negativ sein", "password-reuse-frequency-days": "Häufigkeit der Kennwortwiederverwendung in Tagen", "password-reuse-frequency-days-range": "Die Häufigkeit der Kennwortwiederverwendung in Tagen kann nicht negativ sein", + "allow-whitespace": "Leerzeichen erlauben", "general-policy": "Allgemeine Politik", "max-failed-login-attempts": "Maximale Anzahl fehlgeschlagener Anmeldeversuche, bevor das Konto gesperrt wird", "minimum-max-failed-login-attempts-range": "Die maximale Anzahl fehlgeschlagener Anmeldeversuche kann nicht negativ sein", @@ -146,11 +176,14 @@ "alarm": { "alarm": "Alarm", "alarms": "Alarme", + "all-alarms": "Alle Alarme", "select-alarm": "Alarm auswählen", "no-alarms-matching": "Keine passenden Alarme zu '{{entity}}' wurden gefunden.", "alarm-required": "Alarm ist erforderlich", + "alarm-filter": "Alarmfilter", + "filter": "Filter", "alarm-status": "Alarm Status", - "alarm-status-list": "Alarm Status Liste", + "alarm-status-list": "Alarm Statusliste", "any-status": "Jeder Status", "search-status": { "ANY": "Jeder", @@ -178,6 +211,7 @@ "end-time": "Endzeit", "ack-time": "Bestätigungszeit", "clear-time": "Zeit gelöscht", + "duration": "Dauer", "alarm-severity-list": "Alarm Schwere Liste", "any-severity": "Jede Schwere", "severity-critical": "Kritisch", @@ -187,6 +221,7 @@ "severity-indeterminate": "Unbestimmt", "acknowledge": "Bestätigen", "clear": "Löschen", + "delete": "Löschen", "search": "Alarme suchen", "selected-alarms": "{ count, plural, =1 {1 Alarm} other {# Alarme} } ausgewählt", "no-data": "Keine Daten zum Anzeigen", @@ -197,11 +232,18 @@ "aknowledge-alarms-text": "Sind Sie sicher, dass Sie { count, plural, =1 {1 Alarm} other {# Alarme} } bestätigen möchten?", "aknowledge-alarm-title": "Alarm bestätigen", "aknowledge-alarm-text": "Möchten Sie den Alarm wirklich bestätigen?", + "selected-alarms-are-acknowledged": "Ausgewählte Alarme wurden bereits bestätigt", "clear-alarms-title": "{ count, plural, =1 {1 Alarm} other {# Alarme} } löschen", "clear-alarms-text": "Möchten Sie wirklich { count, plural, =1 {1 Alarm} other {# Alarme} } löschen?", "clear-alarm-title": "Alarm löschen", "clear-alarm-text": "Möchten Sie den Alarm wirklich löschen?", - "alarm-status-filter": "Alarm Status Filter" + "delete-alarms-title": "Lösche { count, plural, =1 {1 Alarm} other {# Alarme} }", + "delete-alarms-text": "Sind Sie sicher { count, plural, =1 {1 Alarm} other {# Alarme} } zu löschen?", + "selected-alarms-are-cleared": "Ausgewählte Alarme wurden bereits gelöscht", + "alarm-status-filter": "Alarm Status Filter", + "alarm-filter-title": "Alarmfilter", + "assigned": "Zugewiesen", + "filter-title": "Filter" }, "alias": { "add": "Alias hinzufügen", @@ -228,14 +270,14 @@ "filter-type-edge-type-description": "Rand vom Typ '{{edgeTypes}}'", "filter-type-relations-query": "Beziehungsabfrage", "filter-type-relations-query-description": "{{entities}} mit {{relationType}} Beziehung {{direction}} {{rootEntity}}", + "filter-type-edge-search-query": "Edge-Abfrage", + "filter-type-edge-search-query-description": "Edge vom Typ {{edgeTypes}} mit {{relationType}} Beziehung {{direction}} {{rootEntity}}", "filter-type-asset-search-query": "Objektabfrage", "filter-type-asset-search-query-description": "Objekte vom Typ {{assetTypes}} mit {{relationType}} Beziehung {{direction}} {{rootEntity}}", "filter-type-device-search-query": "Geräteabfrage", "filter-type-device-search-query-description": "Geräte vom Typ {{deviceTypes}} mit {{relationType}} Beziehung {{direction}} {{rootEntity}}", "filter-type-entity-view-search-query": "Entitätsansichtsabfrage", "filter-type-entity-view-search-query-description": "Entitätsansichten vom Typ {{entityViewTypes}} mit {{relationType}} Beziehung {{direction}} {{rootEntity}}", - "filter-type-edge-search-query": "Randabfrage", - "filter-type-edge-search-query-description": "Rand vom Typ {{edgeTypes}} mit {{relationType}} Beziehung {{direction}} {{rootEntity}}", "entity-filter": "Entitätsfilter", "resolve-multiple": "Als mehrere Entitäten auflösen", "filter-type": "Filtertyp", @@ -254,11 +296,16 @@ "any-relation": "Jede Beziehung" }, "asset": { + "all": "Alle", + "all-assets": "Alle Objekte", + "groups": "Gruppen", + "shared": "Geteilt", "asset": "Objekt", "assets": "Objekte", "management": "Objektverwaltung", "view-assets": "Objekte anzeigen", "add": "Objekt hinzufügen", + "asset-type-max-length": "Objekttyp sollte kürzer als 256 Zeichen sein", "assign-to-customer": "Einem Kunden zuordnen", "assign-asset-to-customer": "Objekte dem Kunden zuordnen", "assign-asset-to-customer-text": "Bitte wählen Sie die Objekte aus, die dem Kunden zugeordnet werden sollen", @@ -281,6 +328,8 @@ "asset-types": "Objekttypen", "name": "Name", "name-required": "Name ist erforderlich.", + "name-max-length": "Name sollte weniger als 256 Zeichen sein", + "label-max-length": "Label sollte weniger als 256 Zeichen sein", "description": "Beschreibung", "type": "Typ", "type-required": "Typ ist erforderlich.", @@ -290,6 +339,7 @@ "asset-details": "Objektdetails", "assign-assets": "Objekte zuordnen", "assign-assets-text": "Kunden { count, plural, =1 {1 Objekt} other {# Objekte} } zuordnen", + "assign-asset-to-edge-text":"Bitte wählen Sie die Objekte aus, die dem Edge zugeordnet werden sollen", "delete-assets": "Objekte löschen", "unassign-assets": "Objektzuordnungen aufheben", "unassign-assets-action-title": "Kunden { count, plural, =1 {1 Objektzuordnung} other {# Objektzuordnungen} } aufheben", @@ -316,7 +366,6 @@ "name-starts-with": "Name des Objekts beginnt mit", "label": "Bezeichnung", "assign-asset-to-edge": "Objekte dem Rand zuordnen", - "assign-asset-to-edge-text":"Bitte wählen Sie die Objekte aus, die dem Rand zugeordnet werden sollen", "unassign-asset-from-edge": "Objekte von Rand entfernen", "unassign-asset-from-edge-title": "Sind Sie sicher, dass Sie die Zuordnung für das Objekt '{{assetName}}' aufheben möchten?", "unassign-asset-from-edge-text": "Nach Bestätigung wird die Zuordnung des Objekts aufgehoben und es ist für den Kunden nicht mehr zugänglich.", @@ -327,6 +376,7 @@ "attribute": { "attributes": "Eigenschaften", "latest-telemetry": "Neueste Telemetrie", + "no-latest-telemetry": "Keine Telemetriedaten", "attributes-scope": "Entitätseigenschaftsbereich", "scope-telemetry": "Telemetrie", "scope-latest-telemetry": "Neueste Telemetrie", @@ -334,11 +384,15 @@ "scope-server": "Server Eigenschaften", "scope-shared": "Gemeinsame Eigenschaften", "add": "Eigenschaft hinzufügen", + "add-attribute-prompt": "Bitte Attribut hinzufügen", "key": "Schlüssel", + "key-max-length": "Der Schlüssel sollte weniger als 256 Zeichen haben", "last-update-time": "Datum der letzten Aktualisierung", "key-required": "Eigenschaftsschlüssel ist erforderlich.", "value": "Wert", "value-required": "Eigenschaftswert ist erforderlich.", + "telemetry-key-required": "Telemetrieschlüssel ist erforderlich", + "telemetry-value-required": "Telemetriewert ist erforderlich", "delete-attributes-title": "Sind Sie sicher, dass Sie { count, plural, =1 {1 Eigenschaft} other {# Eigenschaften} } löschen möchten?", "delete-attributes-text": "Seien Sie vorsichtig, nach der Bestätigung werden alle ausgewählten Eigenschaften entfernt.", "delete-attributes": "Eigenschaften löschen", @@ -350,7 +404,12 @@ "add-to-dashboard": "Zum Dashboard hinzufügen", "add-widget-to-dashboard": "Widget zum Dashboard hinzufügen", "selected-attributes": "{ count, plural, =1 {1 Eigenschaft} other {# Eigenschaften} } ausgewählt", - "selected-telemetry": "{ count, plural, =1 {1 Telemetrieeinheit } other {# Telemetrieeinheiten} } ausgewählt" + "selected-telemetry": "{ count, plural, =1 {1 Telemetrieeinheit } other {# Telemetrieeinheiten} } ausgewählt", + "no-attributes-text": "Keine Attribute gefunden", + "no-telemetry-text": "Keine Telemetriedaten gefunden", + "copy-key": "Schlüssel kopieren", + "add-telemetry": "Telemetriedaten hinzufügen", + "copy-value": "Wert kopieren" }, "audit-log": { "audit": "Audit", @@ -371,17 +430,27 @@ "type-credentials-updated": "Anmeldeinformationen wurden aktualisiert", "type-assigned-to-customer": "Kunden Zuordnung", "type-unassigned-from-customer": "Kunden Zuordnung aufgehoben", - "type-assigned-to-edge": "Rand Zuordnung", - "type-unassigned-from-edge": "Rand Zuordnung aufgehoben", + "type-assigned-to-edge": "Zum Edge hinzugefügt", + "type-unassigned-from-edge": "Vom Edge entfernt", "type-activated": "Aktiviert", "type-suspended": "Ausgesetzt", "type-credentials-read": "Anmeldeinformationen gelesen", "type-attributes-read": "Eigenschaften gelesen", + "type-added-to-entity-group": "Zur Gruppe hinzugefügt", + "type-removed-from-entity-group": "Aus der Gruppe entfernt", "type-relation-add-or-update": "Beziehung aktualisiert", "type-relation-delete": "Beziehung gelöscht", "type-relations-delete": "Alle Beziehungen gelöscht", "type-alarm-ack": "Bestätigt", "type-alarm-clear": "Gelöscht", + "type-alarm-assign": "Zugeweisen", + "type-alarm-unassign": "nicht zugewiesen", + "type-added-comment": "Kommentar hinzugefügt", + "type-updated-comment": "Kommentar aktualisiert", + "type-deleted-comment": "Kommentar gelöscht", + "type-rest-api-rule-engine-call": "Regelkette REST API Aufruf", + "type-made-public": "Öffentlich machen", + "type-made-private": "Privat machen", "type-login": "Anmeldung", "type-logout": "Ausloggen", "type-lockout": "Aussperrung", @@ -392,7 +461,15 @@ "action-data": "Aktionsdaten", "failure-details": "Fehlerdetails", "search": "Audit-Protokolle durchsuchen", - "clear-search": "Suche leeren" + "clear-search": "Suche leeren", + "type-assigned-from-tenant": "Vom Tenant zugewiesen", + "type-assigned-to-tenant": "Dem Tenant zugewiesen", + "type-provision-success": "Gerätebereitstellung erfolgreich", + "type-provision-failure": "Gerätebereitstellung fehlgeschlagen", + "type-timeseries-updated": "Telemetriedaten aktualisiert", + "type-timeseries-deleted": "Telemetriedaten gelöscht", + "type-owner-changed": "Besitzer wurde gewechselt", + "type-sms-sent": "SMS gesendet" }, "confirm-on-exit": { "message": "Sie haben nicht gespeicherte Änderungen. Möchten Sie diese Seite wirklich verlassen?", @@ -409,7 +486,10 @@ "address2": "Adresse 2", "phone": "Telefon", "email": "E-Mail", - "no-address": "Keine Adresse" + "no-address": "Keine Adresse", + "state-max-length": "Staat sollte weniger als 256 Zeichen haben", + "phone-max-length": "Telefonnummer sollte weniger als 256 Zeichen haben", + "city-max-length": "Ort sollte weniger als 256 Zeichen haben" }, "common": { "username": "Benutzername", @@ -417,7 +497,12 @@ "enter-username": "Benutzername eingeben", "enter-password": "Passwort eingeben", "enter-search": "Suche eingeben", - "created-time": "Erstellungszeit" + "created-time": "Erstellungszeit", + "loading": "wird geladen...", + "proceed": "Fortfahren", + "open-details-page": "Detailseite öffnen", + "not-found": "Nicht gefunden", + "documentation": "Dokumentation" }, "content-type": { "json": "Json", @@ -425,6 +510,11 @@ "binary": "Binär (Base64)" }, "customer": { + "all": "Alle", + "all-customers": "Alle Kunden", + "groups": "Gruppen", + "shared": "Geteilt", + "hierarchy": "Hierarchie", "customer": "Kunde", "customers": "Kunden", "management": "Kundenverwaltung", @@ -437,7 +527,6 @@ "public-devices": "Öffentliche Geräte", "public-assets": "Öffentliche Objekte", "public-entity-views": "Öffentliche Entitätsansichten", - "public-edges": "Öffentliche Rand", "add": "Kunde hinzufügen", "delete": "Kunde löschen", "manage-customer-users": "Kundenbenutzer verwalten", @@ -446,7 +535,6 @@ "manage-public-devices": "Öffentliche Geräte verwalten", "manage-public-dashboards": "Öffentliche Dashboards verwalten", "manage-customer-assets": "Kundenobjekte verwalten", - "manage-customer-edges": "Randobjekte verwalten", "manage-public-assets": "Öffentliche Objekte verwalten", "manage-public-edges": "Öffentliche Rand verwalten", "add-customer-text": "Neuen Kunden hinzufügen", @@ -463,6 +551,7 @@ "manage-dashboards": "Dashboards verwalten", "title": "Titel", "title-required": "Titel ist erforderlich.", + "title-max-length": "Titel sollte weniger asl 256 Zeichen haben", "description": "Beschreibung", "details": "Details", "events": "Ereignisse", @@ -1463,7 +1552,6 @@ "management": "Regelverwaltung", "debug-mode": "Modus zur Fehlersuche", "assign-rulechains": "Regelketten zuweisen", - "assign-new-rulechain": "Neues Regelkette zuweisen", "delete-rulechains": "Regelketten löschen", "unassign-rulechain": "Nicht zugeordnete Regelkette", "unassign-rulechains": "Nicht zugeordnete Regelketten", @@ -1588,26 +1676,98 @@ "hours": "Stunden", "minutes": "Minuten", "seconds": "Sekunden", - "advanced": "Erweitert" + "advanced": "Erweitert", + "predefined": { + "yesterday": "Gestern", + "day-before-yesterday": "Vorgestern", + "this-day-last-week": "Dieser Tag letzte Woche", + "previous-week": "Letzte Woche (So - Sa)", + "previous-week-iso": "Letzte Woche (Mo - So)", + "previous-month": "Letzter Monat", + "previous-quarter": "Letztes Quartal", + "previous-half-year": "Letztes Halbjahr", + "previous-year": "Letztes Jahr", + "current-hour": "Aktuelle Stunde", + "current-day": "Aktueller Tag", + "current-day-so-far": "Aktueller Tag bisher", + "current-week": "Aktuelle Wiche (So - Sa)", + "current-week-iso": "Aktuelle Woche (Mo - So)", + "current-week-so-far": "Aktuelle Woche bisher (So - Sa)", + "current-week-iso-so-far": "Aktuelle Woche bisher (Mo - So)", + "current-month": "Aktueller Monat", + "current-month-so-far": "Aktueller Monat bisher", + "current-quarter": "Aktuelles Quartal", + "current-quarter-so-far": "Aktuelles Quartal bisher", + "current-half-year": "Aktuelles Halbjahr", + "current-half-year-so-far": "Aktuelles Halbjahr bisher", + "current-year": "Aktuelles Jahr", + "current-year-so-far": "Aktuelles Jahr bisher" + } + }, + "timeunit": { + "milliseconds": "Millisekunden", + "seconds": "Sekunden", + "minutes": "Minuten", + "hours": "Stunden", + "days": "Tage" }, "timewindow": { + "timewindow": "Zeitfenster", + "years": "{ years, plural, =1 { Jahr } other {# Jahre } }", + "years-short": "{{ years }}J", + "months": "{ months, plural, =1 { Monat } other {# Monate } }", + "months-short": "{{ months }}M", + "weeks": "{ weeks, plural, =1 { Woche } other {# Wochen } }", + "weeks-short": "{{ weeks }}W", "days": "{ days, plural, =1 { Tag } other {# Tage } }", + "days-short": "{{ days }}T", "hours": "{ hours, plural, =0 { Stunde } =1 {1 Stunde } other {# Stunden } }", + "hr": "{{ hr }} Std", + "hr-short": "{{ hr }}S", "minutes": "{ minutes, plural, =0 { Minute } =1 {1 Minute } other {# Minuten } }", + "min": "{{ min }} Min", + "min-short": "{{ min }}m", "seconds": "{ seconds, plural, =0 { Sekunde } =1 {1 Sekunde } other {# Sekunden } }", + "sec": "{{ sec }} Sek", + "sec-short": "{{ sec }}s", + "short": { + "days": "{ days, plural, =1 {1 Tag } other {# Tage } }", + "hours": "{ hours, plural, =1 {1 Stunde } other {# Stunden } }", + "minutes": "{{minutes}} Min ", + "seconds": "{{seconds}} Sek " + }, "realtime": "Echtzeit", "history": "Historie", "last-prefix": "letzte", "period": "von {{ startTime }} bis {{ endTime }}", "edit": "Zeitfenster bearbeiten", "date-range": "Datumsbereich", + "for-all-time": "Für immer", "last": "Letzte", - "time-period": "Zeitfenster" + "time-period": "Zeitfenster", + "hide": "Verstecken", + "interval": "Intervall", + "just-now": "Soeben", + "just-now-lower": "soeben", + "ago": "vor", + "style": "Zeitfenster Style", + "icon": "Symbol", + "icon-position": "Position Symbol", + "icon-position-left": "Links", + "icon-position-right": "Rechts", + "font": "Schriftart", + "color": "Farbe", + "displayTypePrefix": "Echtzeit-/Verlaufspräfix anzeigen", + "preview": "Vorschau" }, "user": { - "user": "User", - "users": "Users", - "customer-users": "Kunden Users", + "all": "Alle", + "all-users": "Alle Benutzer", + "groups": "Gruppen", + "user": "Benutzer", + "users": "Benutzer", + "management": "Benutzerverwaltung", + "customer-users": "Kunden-Benutzer", "tenant-admins": "Mandanten-Administratoren", "sys-admin": "System-Administrator", "tenant-admin": "Mandanten-Administrator", @@ -1618,6 +1778,7 @@ "add-user-text": "Neuen Benutzer hinzufügen", "no-users-text": "Keine Benutzer gefunden", "user-details": "Benutzer-Details", + "delete-users": "Benutzer löschen", "delete-user-title": "Möchten Sie den Benutzer '{{userEmail}}' wirklich löschen?", "delete-user-text": "Vorsicht, nach Bestätigung werden der Benutzer und alle zugehörigen Daten gelöscht.", "delete-users-title": "Sind Sie sicher, dass Sie { count, plural, =1 {1 Benutzer} other {# Benutzer} } löschen möchten??", @@ -1649,7 +1810,11 @@ "disable-account": "Benutzerkonto deaktivieren", "enable-account": "Benutzerkonto aktivieren", "enable-account-message": "Benutzerkonto wurde erfolgreich aktiviert!", - "disable-account-message": "Benutzerkonto wurde erfolgreich deaktiviert!" + "disable-account-message": "Benutzerkonto wurde erfolgreich deaktiviert!", + "copyId": "Benutzer-Id kopieren", + "idCopiedMessage": "Benutzer-Id in die Zwischenablage kopiert", + "user-list": "Benutzerliste", + "user-list-required": "Benutzerliste ist erforderlich" }, "value": { "type": "Wertetyp", @@ -1813,6 +1978,27 @@ }, "widgets": { "date-range-navigator": { + "date-range-picker-settings": "Einstellungen Datumsbereichsauswahl", + "hide-date-range-picker": "Datumsbereichsauswahl verstecken", + "picker-one-panel": "Datumsbereichsauswahl in einem Bereich", + "picker-auto-confirm": "Automatische Bestätigung der Datumsbereichsauswahl", + "picker-show-template": "Vorlage für die Anzeige der Datumsbereichsauswahl", + "first-day-of-week": "Erster Tag der Woche", + "interval-settings": "Intervalleinstellungen", + "hide-interval": "Intervall verstecken", + "initial-interval": "Anfangsintervall", + "interval-hour": "Stunde", + "interval-day": "Tag", + "interval-week": "Woche", + "interval-two-weeks": "2 Wochen", + "interval-month": "Monat", + "interval-three-months": "3 Monate", + "interval-six-months": "6 Monate", + "step-settings": "Schritteinstellungen", + "hide-step-size": "Schrittweite verstecken", + "initial-step-size": "Anfangsschrittweite", + "hide-labels": "Beschriftung verstecken", + "use-session-storage": "Sessionspeicher verwenden", "localizationMap": { "Sun": "So.", "Mon": "Mo.", @@ -1897,6 +2083,7 @@ }, "icon": { "icon": "Symbol", + "icons": "Symbole", "select-icon": "Symbol auswählen", "material-icons": "Material-Symbole", "show-all": "Alle Symbole anzeigen" 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 7937b197f3..34109326b7 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -77,7 +77,10 @@ "show-more": "Show more", "dont-show-again": "Do not show again", "see-documentation": "See documentation", - "clear": "Clear" + "clear": "Clear", + "upload": "Upload", + "delete-anyway": "Delete anyway", + "delete-selected": "Delete selected" }, "aggregation": { "aggregation": "Aggregation", @@ -179,7 +182,10 @@ "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-password-length-range": "Minimum password length should be in a range from 6 to 50", + "maximum-password-length": "Maximum password length", + "maximum-password-length-min": "Maximum password length should be at least 6", + "maximum-password-length-less-min": "Maximum password length should be greater than minimum length", "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", @@ -193,6 +199,8 @@ "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", + "force-reset-password-if-no-valid": "Force to reset password if not valid", + "force-reset-password-if-no-valid-hint": "Please be careful when enabling this feature: it will require users with not valid password to reset their password via email.", "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", @@ -664,7 +672,7 @@ "asset-type": "Asset type", "asset-type-required": "Asset type is required.", "select-asset-type": "Select asset type", - "enter-asset-type": "Enter asset type", + "enter-asset-type": "Enter asset profile", "any-asset": "Any asset", "no-asset-types-matching": "No asset types matching '{{entitySubtype}}' were found.", "asset-type-list-empty": "No asset types selected.", @@ -1178,6 +1186,7 @@ "hide-details": "Hide details", "select-state": "Select target state", "state-controller": "State controller", + "state-controller-default": "static (deprecated)", "search": "Search dashboards", "selected-dashboards": "{ count, plural, =1 {1 dashboard} other {# dashboards} } selected", "home-dashboard": "Home dashboard", @@ -1188,7 +1197,8 @@ "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" + "edit-mode": "Edit mode", + "duplicate-state-action": "Duplicate state" }, "datakey": { "settings": "Settings", @@ -2017,6 +2027,7 @@ "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}}", + "upgrade-instructions": "Upgrade Instructions", "widget-datasource-error": "This widget supports only EDGE entity datasource" }, "edge-event": { @@ -2198,6 +2209,8 @@ "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-tb-resources": "Resources", + "list-of-tb-resources": "{ count, plural, =1 {One resource} other {List of # resources} }", "type-ota-package": "OTA package", "type-rpc": "RPC", "type-queue": "Queue", @@ -2686,7 +2699,12 @@ "rpc-command-result": "Response", "rpc-command-edit-params": "Edit parameters", "gateway-configuration": "General Configuration", - "docker-label": "In order to run ThingsBoard IoT gateway in docker with credentials for this device you can use the following commands.", + "docker-label": "Use the following instruction to run IoT Gateway in in Docker compose with credentials for selected device", + "install-docker-compose": "Use the instructions to download, install and setup docker compose", + "download-configuration-file": "Download configuration file", + "download-docker-compose": "Download docker-compose.yml for your gateway", + "launch-gateway": "Launch gateway", + "launch-docker-compose": "Start the gateway using the following command in the terminal from folder with docker-compose.yml file", "create-new-gateway": "Create a new gateway", "create-new-gateway-text": "Are you sure you want create a new gateway with name: '{{gatewayName}}'?", "created-time": "Created time", @@ -3027,6 +3045,59 @@ "browse-file": "Browse file", "browse-files": "Browse files" }, + "image": { + "gallery": "Image gallery", + "search": "Search image", + "selected-images": "{ count, plural, =1 {1 image} other {# images} } selected", + "created-time": "Created time", + "name": "Name", + "name-required": "Name is required.", + "resolution": "Resolution", + "size": "Size", + "system": "System", + "download-image": "Download image", + "export-image": "Export image to JSON", + "import-image": "Import image from JSON", + "upload-image": "Upload image", + "edit-image": "Edit image", + "image-details": "Image details", + "no-images": "No images found", + "delete-image": "Delete image", + "delete-image-title": "Are you sure you want to delete image '{{imageTitle}}'?", + "delete-image-text": "Be careful, after the confirmation image will become unrecoverable.", + "delete-images-title": "Are you sure you want to delete { count, plural, =1 {1 image} other {# images} }?", + "delete-images-text": "Be careful, after the confirmation all selected images will be removed and all related data will become unrecoverable.", + "list-mode": "List view", + "grid-mode": "Grid view", + "image-preview": "Image preview", + "update-image": "Update image", + "export-failed-error": "Unable to export image: {{error}}", + "image-json-file": "Image JSON file", + "invalid-image-json-file-error": "Unable to import image from JSON: Invalid image JSON data structure.", + "image-is-in-use": "Image is used by other entities", + "images-are-in-use": "Images are used by other entities", + "image-is-in-use-text": "The image '{{title}}' was not deleted because it is used by the following entities:", + "images-are-in-use-text": "Not all images have been deleted because they are used by other entities.
You can view referenced entities by clicking the References button in the corresponding image row.
If you still want to delete these images, select them in the table below and click the Delete selected button.", + "delete-image-in-use-text": "If you still want to delete the image, click the Delete anyway button.", + "system-entities": "System entities:", + "entities": "entities:", + "references": "References", + "include-system-images": "Include system images", + "clear-image": "Clear image", + "no-image": "No image", + "no-image-selected": "No image selected", + "browse-from-gallery": "Browse from gallery", + "set-link": "Set link", + "image-link": "Image link", + "link": "Link", + "copy-image-link": "Copy image link", + "embed-image": "Embed image", + "embed-to-html": "Embed to HTML", + "embed-to-html-hint": "This feature will make link available to any unauthorized user.", + "embed-to-html-text": "Using the following code snippet, you may embed an image into the components based on the plain HTML.
Such components include HTML card widgets, cell content functions, etc.", + "embed-to-angular-template": "Embed to Angular HTML template", + "embed-to-angular-template-text": "Using the following code snippet, you may embed an image into the Angular HTML template.
Such components include the Markdown widget, HTML section in the widget editor, custom actions, etc." + }, "image-input": { "drop-images-or": "Drag and drop an images or", "drag-and-drop": "Drag & Drop", @@ -3175,7 +3246,9 @@ "weeks": "(week ago)", "months": "(month ago)", "years": "(year ago)" - } + }, + "label": "Label", + "value": "Value" }, "login": { "login": "Login", @@ -3365,15 +3438,13 @@ "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-list": "User list", - "users-entity-owner": "Users of the entity owner", - "users-entity-owner-hint": "Users of the entity owner hint" + "users-entity-owner": "Users of the entity owner" }, "recipients": "Recipients", "notification-recipients": "Notifications / Recipients", @@ -3485,69 +3556,70 @@ } }, "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", - "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." + "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", + "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-file": "Package file", + "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": "Top", @@ -3645,7 +3717,8 @@ "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} }" + "uppercase-letter": "{ count, plural, =1 {1 uppercase letter} other {# uppercase letters} }", + "at-most": "At most:" } }, "relation": { @@ -3714,6 +3787,8 @@ "no-resource-text": "No resources found", "open-widgets-bundle": "Open widgets bundle", "resource": "Resource", + "resource-file": "Resource file", + "resource-files": "Resource files", "resource-library-details": "Resource details", "resource-type": "Resource type", "resources-library": "Resources library", @@ -3771,7 +3846,6 @@ "search": "Search rule chains", "selected-rulechains": "{ count, plural, =1 {1 rule chain} other {# rule chains} } selected", "open-rulechain": "Open rule chain", - "assign-new-rulechain": "Assign new rulechain", "edge-template-root": "Template root", "assign-to-edge": "Assign to edge", "edge-rulechain": "Edge rule chain", @@ -3865,7 +3939,9 @@ "test": "Test", "help": "Help", "reset-debug-mode": "Reset debug mode in all nodes", - "test-with-this-message": "{{test}} with this message" + "test-with-this-message": "{{test}} with this message", + "queue-hint": "Select a queue for message forwarding to another queue. 'Main' queue is used by default.", + "queue-singleton-hint": "Select a queue for message forwarding in multi-instance environments. 'Main' queue is used by default." }, "timezone": { "timezone": "Timezone", @@ -4053,7 +4129,7 @@ "rule-engine": "Rule Engine", "time-to-live": "Time-to-live", "alarms-and-notifications": "Alarms and notifications", - "ota-files-in-bytes": "OTA files in bytes", + "ota-files-in-bytes": "Files", "ws-title": "WS", "unlimited": "(0 - unlimited)", "maximum-devices": "Devices maximum number", @@ -4074,12 +4150,15 @@ "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-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", + "maximum-resources-sum-data-size": "Maximum total size of resources files (bytes)", + "maximum-resources-sum-data-size-required": "Maximum total size of resources files is required.", + "maximum-resources-sum-data-size-range": "Maximum total size of resources files can't be negative", + "maximum-resource-size": "Maximum resource file size (bytes)", + "maximum-resource-size-required": "Maximum resource file size is required", + "maximum-resource-size-range": "Maximum resource file size can't be negative", + "maximum-ota-packages-sum-data-size": "Maximum total size of OTA package files (bytes)", + "maximum-ota-package-sum-data-size-required": "Maximum total size of OTA package files is required.", + "maximum-ota-package-sum-data-size-range": "Maximum total size of OTA package files 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", @@ -4206,30 +4285,36 @@ "seconds": "Seconds", "advanced": "Advanced", "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" + "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" + }, + "type": { + "week": "Week (Sun - Sat)", + "week-iso": "Week (Mon - Sun)", + "month": "Month", + "quarter": "Quarter" } }, "timeunit": { @@ -4288,6 +4373,12 @@ "displayTypePrefix": "Display Realtime/History prefix", "preview": "Preview" }, + "tooltip": { + "value": "Value", + "date": "Date", + "background-color": "Background color", + "background-blur": "Background blur" + }, "unit": { "millimeter": "Millimeter", "centimeter": "Centimeter", @@ -4566,6 +4657,7 @@ "gram-per-cubic-centimeter": "Gram per cubic centimeter", "kilogram-per-square-meter": "Kilogram per square metre", "milligram-per-milliliter": "Milligram per milliliter", + "milligram-per-cubic-meter": "Milligram per cubic meter", "pound-per-cubic-foot": "Pound per cubic foot", "ounces-per-cubic-inch": "Ounces per cubic inch", "tons-per-cubic-yard": "Tons per cubic yard", @@ -5155,15 +5247,20 @@ "background": { "background": "Background", "background-settings": "Background settings", - "background-type-image": "Upload image", - "background-type-image-url": "Image URL", - "background-type-color": "Solid color", + "background-type-image": "Image", + "background-type-color": "Color", "image-url": "Image URL", "overlay": "Overlay", "enable-overlay": "Enable overlay", "blur": "Blur", "preview": "Preview" }, + "bar-chart": { + "bar-appearance": "Bar appearance", + "label-on-bar": "Label on bar", + "value-on-bar": "Value on bar", + "bar-chart-card-style": "Bar chart card style" + }, "battery-level": { "layout": "Layout", "layout-vertical-solid": "Vertical. Solid", @@ -5189,9 +5286,6 @@ "date": "Date", "active-bars-color": "Active signal bars color", "inactive-bars-color": "Inactive signal bars color", - "tooltip": "Tooltip", - "background-color": "Background color", - "background-blur": "Background blur", "signal-strength-card-style": "Signal strength card style" }, "chart": { @@ -5434,18 +5528,8 @@ "clockwise-layout": "Clockwise layout", "sort-series": "Sort series by label", "central-total-value": "Central total value", - "legend-position-top": "Top", - "legend-position-bottom": "Bottom", - "legend-position-left": "Left", - "legend-position-right": "Right", - "legend-label": "Label", - "legend-value": "Value", - "tooltip": "Tooltip", - "tooltip-value": "Value", "tooltip-value-type-absolute": "Absolute", "tooltip-value-type-percentage": "Percentage", - "tooltip-background-color": "Background color", - "tooltip-background-blur": "Background blur", "doughnut-card-style": "Doughnut card style" }, "entities-hierarchy": { @@ -5921,6 +6005,14 @@ "no-columns-found": "No columns found", "no-columns-matching": "'{{column}}' not found." }, + "range-chart": { + "chart": "Chart", + "data-zoom": "Data zoom", + "range-colors": "Range colors", + "out-of-range-color": "Out of range color", + "fill-area": "Fill area", + "range-chart-card-style": "Range chart card style" + }, "rpc": { "value-settings": "Value settings", "initial-value": "Initial value", @@ -6348,8 +6440,7 @@ "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-timestamp": "Timestamp", "display-pagination": "Display pagination", "default-page-size": "Default page size", "use-entity-label-tab-name": "Use entity label in tab name", @@ -6710,9 +6801,9 @@ "ka_GE": "ქართული", "ko_KR": "한국어", "lv_LV": "Latviešu", + "nl_BE": "Koninkrijk België", "pt_BR": "Português do Brasil", "ro_RO": "Română", - "ru_RU": "Русский", "sl_SI": "Slovenščina", "tr_TR": "Türkçe", "uk_UA": "Українська", diff --git a/ui-ngx/src/assets/locale/locale.constant-es_ES.json b/ui-ngx/src/assets/locale/locale.constant-es_ES.json index b9a386071a..8727339851 100644 --- a/ui-ngx/src/assets/locale/locale.constant-es_ES.json +++ b/ui-ngx/src/assets/locale/locale.constant-es_ES.json @@ -2655,7 +2655,6 @@ "rpc-command-result": "Resultado", "rpc-command-edit-params": "Editar parametros", "gateway-configuration": "Configuración General", - "docker-label": "Usa los siguientes comandos para ejecutar el gateway en Docker.", "create-new-gateway": "Crear un gateway nuevo", "create-new-gateway-text": "Crear un nuevo gateway con el nombre: '{{gatewayName}}'?", "created-time": "Hora de creación", @@ -3094,6 +3093,35 @@ "backup-code-auth-description": "Por favor, introduce el código de backup.", "backup-code-auth-placeholder": "Código de Backup" }, + "signup": { + "firstname": "Nombre", + "lastname": "Apellido", + "email": "Correo electrónico", + "signup": "Registrarse", + "create-password": "Crear una contraseña", + "repeat-password": "Repite tu contraseña", + "have-account": "¿Ya tienes una cuenta?", + "signin": "Iniciar sesión", + "no-captcha-message": "Debes confirmar que no eres un robot", + "password-length-message": "Tu contraseña debe tener al menos 6 caracteres", + "email-verification": "Verificación de correo electrónico", + "email-verification-message": "Se envió un correo electrónico con detalles de verificación a la dirección de correo electrónico especificada. Por favor, sigue las instrucciones proporcionadas en el correo electrónico para completar tu proceso de registro. Nota: si no has visto el correo electrónico durante un tiempo, por favor revisa tu carpeta de 'spam' o intenta reenviar el correo electrónico haciendo clic en el botón 'Reenviar'.", + "account-activation-title": "Activación de cuenta", + "account-activated": "¡Cuenta activada con éxito!", + "account-activated-text": "¡Felicidades! Tu cuenta ha sido activada.", + "resend": "Reenviar", + "inactive-user-exists-title": "Ya existe un usuario inactivo", + "inactive-user-exists-text": "Ya hay un usuario registrado con dirección de correo electrónico no verificada. Haz clic en el botón 'Reenviar' si deseas reenviar el correo electrónico de verificación.", + "activating-account": "Activando cuenta...", + "activating-account-text": "Tu cuenta se está activando actualmente. Por favor espera...", + "accept-privacy-policy": "Aceptar la Política de Privacidad", + "accept": "Aceptar", + "privacy-policy": "Política de Privacidad", + "accept-privacy-policy-message": "Debes aceptar nuestra Política de Privacidad", + "recaptcha-title": "reCAPTCHA", + "terms-of-use": "Términos de Uso", + "accept-terms-of-use-message": "Debes aceptar nuestros Términos de Uso" + }, "markdown": { "edit": "Editar", "preview": "Previsualizar", @@ -3247,15 +3275,13 @@ "recipient-type": { "affected-tenant-administrators": "Administradores afectados", "affected-user": "Usuario afectado", - "affected-user-hint": "Sugerencia en usuario afectado", "all-users": "Todos los usuarios", "customer-users": "Usuarios del cliente", "system-administrators": "Administradores del sistema", "tenant-administrators": "Administradores de propietarios", "user-filters": "Filtro de usuarios", "user-list": "Lista de usuarios", - "users-entity-owner": "Usuarios que sean propietarios de la entidad", - "users-entity-owner-hint": "Sugerencia en usuarios propietarios de la entidad" + "users-entity-owner": "Usuarios que sean propietarios de la entidad" }, "recipients": "Destinatarios", "notification-recipients": "Notificaciones / Destinatarios", @@ -3653,7 +3679,6 @@ "search": "Buscar cadenas de reglas", "selected-rulechains": "{ count, plural, =1 {1 cadena de reglas} other {# cadenas de reglas} } seleccionadas", "open-rulechain": "Abrir cadena de reglas", - "assign-new-rulechain": "Asignar nueva cadena de reglas", "edge-template-root": "Raíz de plantilla", "assign-to-edge": "Asignar a Edge", "edge-rulechain": "Cadena de reglas de Edge", @@ -6066,7 +6091,6 @@ "show-empty-space-hidden-action": "Mostrar espacio vacío en lugar de celda oculta", "dont-reserve-space-hidden-action": "No reservar espacio para los botones en celda oculta", "display-timestamp": "Mostrar columna timestamp", - "display-milliseconds": "Mostrar milisegundos", "display-pagination": "Mostrar páginas", "default-page-size": "Tamaño de página por defecto", "use-entity-label-tab-name": "Usar etiqueta de entidad en el nombre de la tabla", 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 9fbdfef9f4..7e678d9ed9 100644 --- a/ui-ngx/src/assets/locale/locale.constant-fr_FR.json +++ b/ui-ngx/src/assets/locale/locale.constant-fr_FR.json @@ -1866,7 +1866,6 @@ "set-root-rulechain-title": "Voulez-vous vraiment que la chaîne de règles '{{ruleChainName}} soit racine (root) ?", "system": "Système", "assign-rulechains": "Attribuer aux chaînes de règles", - "assign-new-rulechain": "Attribuer une nouvele chaînes de règles", "delete-rulechains": "Supprimer une chaînes de règles", "unassign-rulechain": "Retirer chaîne de règles", "unassign-rulechains": "Retirer chaînes de règles", diff --git a/ui-ngx/src/assets/locale/locale.constant-nl_BE.json b/ui-ngx/src/assets/locale/locale.constant-nl_BE.json new file mode 100644 index 0000000000..df3820d497 --- /dev/null +++ b/ui-ngx/src/assets/locale/locale.constant-nl_BE.json @@ -0,0 +1,6951 @@ +{ + "access": { + "unauthorized": "Geen toegang", + "unauthorized-access": "Geen toegang", + "unauthorized-access-text": "Gelieve u zich opnieuw in te loggen.", + "access-forbidden": "Toegang verboden", + "access-forbidden-text": "Je hebt geen toegangsrechten tot deze locatie!
Probeer in te loggen met een andere gebruiker als u toch toegang wilt verkrijgen.", + "refresh-token-expired": "Sessie is verlopen", + "refresh-token-failed": "Kan sessie niet vernieuwen", + "permission-denied": "Toestemming geweigerd", + "permission-denied-text": "U hebt geen toestemming om deze bewerking uit te voeren!" + }, + "action": { + "activate": "Activeren", + "suspend": "Opschorten", + "save": "Opslaan", + "saveAs": "Opslaan als", + "cancel": "Annuleren", + "ok": "OK", + "delete": "Verwijderen", + "add": "Toevoegen", + "yes": "Ja", + "no": "Nee", + "update": "Update", + "remove": "Verwijderen", + "search": "Zoeken", + "clear-search": "Zoekopdracht wissen", + "assign": "Toewijzen", + "unassign": "Toewijzing ongedaan maken", + "share": "Delen", + "make-private": "Privé maken", + "make-public": "Openbaar maken", + "apply": "Toepassen", + "apply-changes": "Wijzigingen toepassen", + "edit-mode": "Bewerk modus", + "enter-edit-mode": "Ga naar de bewerkingsmodus", + "decline-changes": "Wijzigingen weigeren", + "open": "Open", + "close": "Sluiten", + "back": "Terug", + "run": "Uitvoeren", + "sign-in": "Aanmelden", + "edit": "Bewerken", + "view": "Bekijken", + "create": "Aanmaken", + "drag": "Slepen", + "refresh": "Vernieuwen", + "undo": "Ongedaan maken", + "copy": "Kopiëren", + "paste": "Plakken", + "copy-reference": "Referentie kopiëren", + "paste-reference": "Referentie plakken", + "import": "Importeren", + "export": "Exporteren", + "share-via": "Delen via {{provider}}", + "move": "Verplaatsen", + "select": "Selecteren", + "continue": "Voortzetten", + "discard-changes": "Wijzigingen negeren", + "download": "Downloaden", + "next": "Volgend", + "next-with-label": "Volgende: {{label}}", + "read-more": "Lees meer", + "hide": "Verbergen", + "done": "Klaar", + "print": "Afdrukken", + "restore": "Herstellen", + "confirm": "Bevestigen", + "more": "Meer", + "less": "Minder", + "skip": "Overslaan", + "send": "Verzenden" + }, + "aggregation": { + "aggregation": "Aggregatie", + "function": "Functie voor gegevensaggregatie", + "limit": "Maximale waarden", + "group-interval": "Groeperingsinterval", + "min": "Min", + "max": "Max", + "avg": "Gemiddeld", + "sum": "Som", + "count": "Tellen", + "none": "Geen" + }, + "admin": { + "settings": "Instellingen", + "general": "Algemeen", + "general-settings": "Algemene instellingen", + "home-settings": "Home-instellingen", + "home": "Thuis", + "outgoing-mail": "E-mailserver", + "outgoing-mail-settings": "Serverinstellingen voor uitgaande e-mail", + "system-settings": "Systeeminstellingen", + "test-mail-sent": "Testmail is succesvol verzonden!", + "base-url": "Basis-URL", + "base-url-required": "Basis-URL is vereist.", + "prohibit-different-url": "Verbieden om de hostnaam te gebruiken in de headers van de clientaanvraag", + "prohibit-different-url-hint": "Deze instelling moet zijn ingeschakeld voor productieomgevingen. Kan beveiligingsproblemen veroorzaken wanneer deze is uitgeschakeld", + "mail-from": "E-mail van", + "mail-from-required": "Mail Van is vereist.", + "smtp-protocol": "SMTP-protocol", + "smtp-host": "SMTP-host", + "smtp-host-required": "SMTP-host is vereist.", + "smtp-port": "SMTP-poort", + "smtp-port-required": "U moet een smtp-poort opgeven.", + "smtp-port-invalid": "Dat ziet er niet uit als een geldige smtp-poort.", + "timeout-msec": "Time-out (msec)", + "timeout-required": "Er is een time-out vereist.", + "timeout-invalid": "Dat ziet er niet uit als een geldige time-out.", + "enable-tls": "TLS inschakelen", + "tls-version": "TLS-versie", + "enable-proxy": "Proxy inschakelen", + "proxy-host": "Proxy-host", + "proxy-host-required": "Proxyhost is vereist.", + "proxy-port": "Proxy-poort", + "proxy-port-required": "Proxypoort is vereist.", + "proxy-port-range": "De proxypoort moet tussen 1 en 65535 liggen.", + "proxy-user": "Proxy-gebruiker", + "proxy-password": "Proxy wachtwoord", + "change-password": "Wachtwoord wijzigen", + "send-test-mail": "Testmail versturen", + "use-system-mail-settings": "Systeeminstellingen voor e-mailserver gebruiken", + "mail-templates": "E-mail sjablonen", + "mail-template-settings": "Instellingen voor e-mailsjablonen", + "use-system-mail-template-settings": "Systeem-e-mailsjablonen gebruiken", + "mail-template": { + "mail-template": "E-mail sjabloon", + "test": "E-mailbericht testen", + "activation": "Bericht over accountactivering", + "account-activated": "Bericht over account geactiveerd", + "account-lockout": "Bericht over accountvergrendeling", + "reset-password": "Bericht over wachtwoord opnieuw instellen", + "password-was-reset": "Bericht Wachtwoord is opnieuw ingesteld", + "user-activated": "Door de gebruiker geactiveerd bericht", + "user-registered": "Geregistreerd bericht van de gebruiker", + "api-usage-state-enabled": "Api-gebruiksstatus ingeschakeld", + "api-usage-state-warning": "Waarschuwing voor API-gebruiksstatus", + "api-usage-state-disabled": "Api-gebruiksstatus uitgeschakeld", + "two-fa-verification": "2FA-verificatiebericht" + }, + "mail-subject": "Onderwerp van de e-mail", + "mail-body": "Hoofdtekst van e-mail", + "sms-provider": "SMS-provider", + "sms-provider-settings": "Instellingen sms-provider", + "use-system-sms-settings": "De instellingen van de systeem-sms-provider gebruiken", + "sms-provider-type": "Type sms-provider", + "sms-provider-type-required": "Het type sms-provider is vereist.", + "sms-provider-type-aws-sns": "Amazone SNS", + "sms-provider-type-twilio": "Twilio", + "sms-provider-type-smpp": "SMPP", + "aws-access-key-id": "AWS-toegangssleutel-ID", + "aws-access-key-id-required": "AWS Access Key ID is vereist", + "aws-secret-access-key": "AWS geheime toegangssleutel", + "aws-secret-access-key-required": "AWS geheime toegangssleutel is vereist", + "aws-region": "AWS-regio", + "aws-region-required": "AWS-regio is vereist", + "number-from": "Telefoonnummer van", + "number-from-required": "Telefoonnummer van is vereist.", + "number-to": "Telefoonnummer naar", + "number-to-required": "Telefoonnummer Naar is vereist.", + "phone-number-hint": "Telefoonnummer in E.164-formaat, bijv. +19995550123", + "phone-number-hint-twilio": "Telefoonnummer in E.164-formaat/SID van telefoonnummer/SID-berichtenservice, bijv. +19995550123/PNXXX/MGXXX", + "phone-number-pattern": "Ongeldig telefoonnummer. Moet in E.164-formaat zijn, bijv. +19995550123.", + "phone-number-pattern-twilio": "Ongeldig telefoonnummer. Moet in E.164-indeling/SID/Berichtenservice SID van het telefoonnummer/telefoonnummer zijn, bijv. +19995550123/PNXXX/MGXXX.", + "sms-message": "SMS-bericht", + "sms-message-required": "SMS-bericht is vereist.", + "sms-message-max-length": "SMS-bericht mag niet langer zijn dan 1600 tekens", + "twilio-account-sid": "TSID voor Twilio-account", + "twilio-account-sid-required": "TSID voor Twilio-account is vereist", + "twilio-account-token": "Twilio-accounttoken", + "twilio-account-token-required": "Twilio-accounttoken is vereist", + "send-test-sms": "Test-sms verzenden", + "test-sms-sent": "Test-sms is succesvol verzonden!", + "security-settings": "Beveiligingsinstellingen", + "password-policy": "Wachtwoord beleid", + "minimum-password-length": "Minimale wachtwoordlengte", + "minimum-password-length-required": "Minimale wachtwoordlengte is vereist", + "minimum-password-length-range": "De minimale wachtwoordlengte moet tussen 5 en 50 liggen", + "minimum-uppercase-letters": "Minimum aantal hoofdletters", + "minimum-uppercase-letters-range": "Minimum aantal hoofdletters mag niet negatief zijn", + "minimum-lowercase-letters": "Minimum aantal kleine letters", + "minimum-lowercase-letters-range": "Minimum aantal kleine letters mag niet negatief zijn", + "minimum-digits": "Minimum aantal cijfers", + "minimum-digits-range": "Minimum aantal cijfers mag niet negatief zijn", + "minimum-special-characters": "Minimum aantal speciale tekens", + "minimum-special-characters-range": "Minimum aantal speciale tekens mag niet negatief zijn", + "password-expiration-period-days": "Vervalperiode van wachtwoord in dagen", + "password-expiration-period-days-range": "De vervalperiode van het wachtwoord in dagen mag niet negatief zijn", + "password-reuse-frequency-days": "Frequentie van hergebruik van wachtwoorden in dagen", + "password-reuse-frequency-days-range": "De frequentie van hergebruik van wachtwoorden in dagen mag niet negatief zijn", + "allow-whitespace": "Witruimte toestaan", + "general-policy": "Algemeen beleid", + "max-failed-login-attempts": "Maximum aantal mislukte inlogpogingen voordat het account wordt vergrendeld", + "minimum-max-failed-login-attempts-range": "Het maximale aantal mislukte aanmeldingspogingen mag niet negatief zijn", + "user-lockout-notification-email": "Als het gebruikersaccount is vergrendeld, stuurt u een melding naar e-mail", + "domain-name": "Domeinnaam", + "domain-name-unique": "Domeinnaam en protocol moeten uniek zijn.", + "domain-name-max-length": "Domeinnaam moet kleiner zijn dan 256 tekens tekens", + "error-verification-url": "Een domeinnaam mag geen symbolen '/' en ':' bevatten. Voorbeeld: thingsboard.io", + "oauth2": { + "access-token-uri": "Toegangstoken URI", + "access-token-uri-required": "De URI van het toegangstoken is vereist.", + "activate-user": "Gebruiker activeren", + "add-domain": "Domein toevoegen", + "delete-domain": "Domein verwijderen", + "add-provider": "Provider toevoegen", + "delete-provider": "Provider verwijderen", + "allow-user-creation": "Aanmaken van gebruikers toestaan", + "always-fullscreen": "Altijd volledig scherm", + "authorization-uri": "Autorisatie-URI", + "authorization-uri-required": "Autorisatie-URI is vereist.", + "client-authentication-method": "Verificatiemethode voor clients", + "client-id": "Client-ID", + "client-id-required": "Client-ID is vereist.", + "client-id-max-length": "Client-ID lengte moet kleiner zijn dan 256 tekens tekens", + "client-secret": "Geheim van de klant", + "client-secret-required": "Clientgeheim is vereist.", + "client-secret-max-length": "Clientgeheim lengte moet kleiner zijn dan 2049 tekens", + "custom-setting": "Aangepaste instellingen", + "customer-name-pattern": "Patroon klantnaam", + "customer-name-pattern-max-length": "Het patroon van de klantnaam moet kleiner zijn dan 256 tekens tekens", + "parent-customer-name-pattern": "Patroon voor bovenliggende klantnaam", + "user-groups-name-pattern": "Naampatroon van gebruikersgroepen", + "default-dashboard-name": "Standaard dashboardnaam", + "default-dashboard-name-max-length": "De standaardnaam van het dashboard moet kleiner zijn dan 256 tekens tekens", + "delete-domain-text": "Let op, na de bevestiging zijn dit domein en alle providergegevens niet meer beschikbaar.", + "delete-domain-title": "Weet u zeker dat u instellingen wilt verwijderen van dit domein '{{domainName}}'?", + "delete-registration-text": "Let op, na de bevestiging zijn de gegevens van deze provider niet meer beschikbaar.", + "delete-registration-title": "Weet u zeker dat u de provider '{{name}}' wilt verwijderen?", + "email-attribute-key": "E-mail attribuut sleutel", + "email-attribute-key-required": "E-mailkenmerksleutel is vereist.", + "email-attribute-key-max-length": "De e-mailkenmerksleutel moet kleiner zijn dan 32 tekens", + "first-name-attribute-key": "Voornaam attribuutsleutel", + "first-name-attribute-key-max-length": "De kenmerksleutel voor de voornaam moet kleiner zijn dan 32 tekens", + "general": "Algemeen", + "jwk-set-uri": "JSON-websleutel-URI", + "last-name-attribute-key": "Sleutel voor het kenmerk achternaam", + "last-name-attribute-key-max-length": "De kenmerksleutel voor de achternaam moet kleiner zijn dan 32 tekens", + "login-button-icon": "Pictogram van de inlogknop", + "login-button-label": "Label van de aanbieder", + "login-button-label-placeholder": "Log in met $(Providerlabel)", + "login-button-label-required": "Label is vereist.", + "login-provider": "Login provider", + "mapper": "Mapper", + "new-domain": "Nieuw domein", + "oauth2": "OAuth2", + "password-max-length": "Wachtwoord moet kleiner zijn dan 256 tekens tekens", + "redirect-uri-template": "Sjabloon voor omleidings-URI", + "copy-redirect-uri": "Omleidings-URI kopiëren", + "registration-id": "Registratie-ID", + "registration-id-required": "Registratie-ID is vereist.", + "registration-id-unique": "Registratie-ID moet uniek zijn voor het systeem.", + "scope": "Draagwijdte", + "scope-required": "Scope is vereist.", + "tenant-name-pattern": "Patroon van tenantnaam", + "tenant-name-pattern-required": "Het patroon van de naam van de tenant is vereist.", + "tenant-name-pattern-max-length": "Patroon van tenantnaam imoet kleiner zijn dan 256 tekens tekens", + "tenant-name-strategy": "Strategie voor naam tenant", + "type": "Type mapper", + "uri-pattern-error": "Ongeldige URI-indeling.", + "url": "URL", + "url-pattern": "Ongeldige URL-indeling.", + "url-required": "URL is vereist.", + "url-max-length": "URL moet kleiner zijn dan 256 tekens tekens", + "user-info-uri": "Gebruikersinfo URI", + "user-info-uri-required": "URI voor gebruikersinformatie is vereist.", + "username-max-length": "Gebruikersnaam moet kleiner zijn dan 256 tekens tekens", + "user-name-attribute-name": "Sleutel voor gebruikersnaamattribuut", + "user-name-attribute-name-required": "De kenmerksleutel van de gebruikersnaam is vereist", + "protocol": "Protocol", + "domain-schema-http": "HTTP (HTTP)", + "domain-schema-https": "HTTPS", + "domain-schema-mixed": "HTTP+HTTPS", + "enable": "OAuth2-instellingen inschakelen", + "domains": "Domeinen", + "mobile-apps": "Mobiele applicaties", + "no-mobile-apps": "Geen applicaties geconfigureerd", + "mobile-package": "Applicatie pakket", + "mobile-package-placeholder": "Vb.: my.example.app", + "mobile-package-hint": "Voor Android: uw eigen unieke applicatie-ID. Voor iOS: ID van productbundel.", + "mobile-package-unique": "Het toepassingspakket moet uniek zijn.", + "mobile-app-secret": "Geheim van de toepassing", + "invalid-mobile-app-secret": "Het geheim van de toepassing mag alleen alfanumerieke tekens bevatten en moet tussen de 16 en 2048 tekens lang zijn.", + "copy-mobile-app-secret": "Toepassingsgeheim kopiëren", + "add-mobile-app": "Applicatie toevoegen", + "delete-mobile-app": "Toepassingsgegevens verwijderen", + "providers": "Providers", + "platform-web": "Web", + "platform-android": "Android", + "platform-ios": "iOS", + "all-platforms": "Alle platformen", + "allowed-platforms": "Toegestane platforms" + }, + "smpp-provider": { + "smpp-version": "SMPP-versie", + "smpp-host": "SMPP-host", + "smpp-host-required": "SMPP-host is vereist", + "smpp-port": "SMPP-poort", + "smpp-port-required": "SMPP-poort is vereist", + "system-id": "Systeem-ID", + "system-id-required": "Systeem-ID is vereist", + "password": "Wachtwoord", + "password-required": "Wachtwoord is vereist", + "type-settings": "Typ instellingen", + "source-settings": "Bron-instellingen", + "destination-settings": "Bestemming instellingen", + "additional-settings": "Aanvullende instellingen", + "system-type": "Type systeem", + "bind-type": "Type binden", + "service-type": "Soort dienst", + "source-address": "Bronadres", + "source-ton": "Bron: TON", + "source-npi": "Bron: NPI", + "destination-ton": "Bestemming TON (type nummer)", + "destination-npi": "Bestemming NPI (Nummerplan Identificatie)", + "address-range": "Adres bereik", + "coding-scheme": "Coderingsschema", + "bind-type-tx": "Zender", + "bind-type-rx": "Ontvanger", + "bind-type-trx": "Transciever", + "ton-unknown": "Onbekend", + "ton-international": "Internationaal", + "ton-national": "Nationaal", + "ton-network-specific": "Netwerk Specifiek", + "ton-subscriber-number": "Abonneenummer", + "ton-alphanumeric": "Alfanumeriek", + "ton-abbreviated": "Afgekort", + "npi-unknown": "0 - Onbekend", + "npi-isdn": "1 - ISDN/telefoonnummerplan (E163/E164)", + "npi-data-numbering-plan": "3 - Nummeringsplan voor gegevens (X.121)", + "npi-telex-numbering-plan": "4 - Telexnummerplan (F.69)", + "npi-land-mobile": "6 - Landmobiel (E.212)", + "npi-national-numbering-plan": "8 - Nationaal nummerplan", + "npi-private-numbering-plan": "9 - Privé nummerplan", + "npi-ermes-numbering-plan": "10 - ERMES-nummerplan (ETSI DE/PS 3 01-3)", + "npi-internet": "13 - Internet (IP)", + "npi-wap-client-id": "18 - WAP-client-ID (te definiëren door WAP-forum)", + "scheme-smsc": "0 - SMSC Default Alphabet (ASCII voor korte en lange code en naar GSM voor gratis)", + "scheme-ia5": "1 - IA5 (ASCII voor korte en lange code, Latijnse 9 voor gratis code (ISO-8859-9))", + "scheme-octet-unspecified-2": "2 - Octet Niet gespecificeerd (8-bits binair)", + "scheme-latin-1": "3 - Latijn 1 (ISO-8859-1)", + "scheme-octet-unspecified-4": "4 - Octet Niet gespecificeerd (8-bits binair)", + "scheme-jis": "5 - JIS (X 0208-1990)", + "scheme-cyrillic": "6 - Cyrillisch (ISO-8859-5)", + "scheme-latin-hebrew": "7 - Latijn/Hebreeuws (ISO-8859-8)", + "scheme-ucs-utf": "8 - UCS2/UTF-16 (ISO/IEC-10646)", + "scheme-pictogram-encoding": "9 - Codering van pictogrammen", + "scheme-music-codes": "10 - Muziek Codes (ISO-2022-JP)", + "scheme-extended-kanji-jis": "13 - Uitgebreide Kanji JIS (X 0212-1990)", + "scheme-korean-graphic-character-set": "14 - Koreaanse grafische tekenset (KS C 5601/KS X 1001)" + }, + "queue-select-name": "Selecteer de naam van de queue", + "queue-name": "Naam", + "queue-name-required": "Queue naam is verplicht!", + "queues": "Queues", + "queue-partitions": "Partities", + "queue-submit-strategy": "Strategie indienen", + "queue-processing-strategy": "Verwerkingsstrategie", + "queue-configuration": "Configuratie van queues", + "repository-settings": "Repository-instellingen", + "repository": "Opslagplaats", + "repository-url": "URL van opslagplaats", + "repository-url-required": "De URL van de opslagplaats is vereist.", + "default-branch": "Standaard filiaalnaam", + "repository-read-only": "Alleen-lezen", + "show-merge-commits": "Samenvoegcommits weergeven", + "authentication-settings": "Authenticatie-instellingen", + "auth-method": "Verificatiemethode", + "auth-method-username-password": "Wachtwoord / toegangstoken", + "auth-method-username-password-hint": "GitHub-gebruikers moeten toegang tokens gebruiken met schrijfmachtigingen voor de opslagplaats.", + "auth-method-private-key": "Privé-sleutel", + "password-access-token": "Wachtwoord / toegangstoken", + "change-password-access-token": "Wachtwoord / toegangstoken wijzigen", + "private-key": "Privé-sleutel", + "drop-private-key-file-or": "Sleep een bestand met een persoonlijke sleutel of", + "passphrase": "Wachtwoordzin", + "enter-passphrase": "Voer wachtwoordzin in", + "change-passphrase": "Wachtwoordzin wijzigen", + "check-access": "Toegang controleren", + "check-repository-access-success": "Toegang tot repository succesvol geverifieerd!", + "delete-repository-settings-title": "Weet je zeker dat je repository-instellingen wilt verwijderen?", + "delete-repository-settings-text": "Opgelet, na de bevestiging worden de instellingen van het archief verwijderd en is de versiebeheerfunctie niet meer beschikbaar.", + "auto-commit-settings": "Instellingen voor automatisch vastleggen", + "auto-commit": "Automatisch vastleggen", + "auto-commit-entities": "Entiteiten automatisch vastleggen", + "no-auto-commit-entities-prompt": "Geen entiteiten geconfigureerd voor automatisch vastleggen", + "delete-auto-commit-settings-title": "Weet je zeker dat je instellingen voor automatisch vastleggen wilt verwijderen?", + "delete-auto-commit-settings-text": "Opgelet, na de bevestiging worden de instellingen voor automatisch vastleggen verwijderd en wordt automatisch vastleggen uitgeschakeld voor alle entiteiten.", + "2fa": { + "2fa": "Twee-factor-authenticatie", + "available-providers": "Beschikbare providers", + "issuer-name": "Naam van de uitgever", + "issuer-name-required": "De naam van de uitgever is vereist.", + "max-verification-failures-before-user-lockout": "Max. aantal verificatiefouten vóór gebruikersvergrendeling", + "max-verification-failures-before-user-lockout-pattern": "Het maximum aantal mislukte verificaties moet een positief geheel getal zijn.", + "number-of-checking-attempts": "Aantal controlepogingen", + "number-of-checking-attempts-pattern": "Het aantal controlepogingen moet een positief geheel getal zijn.", + "number-of-checking-attempts-required": "Het aantal controlepogingen is vereist.", + "number-of-codes": "Aantal codes", + "number-of-codes-pattern": "Het aantal codes moet een positief geheel getal zijn.", + "number-of-codes-required": "Aantal codes is vereist.", + "provider": "Aanbieder", + "retry-verification-code-period": "Verificatiecodeperiode opnieuw proberen (sec)", + "retry-verification-code-period-pattern": "Minimale tijdsduur is 5 sec", + "retry-verification-code-period-required": "De periode van de verificatiecode voor opnieuw proberen is vereist.", + "total-allowed-time-for-verification": "Totale toegestane tijd voor verificatie (sec)", + "total-allowed-time-for-verification-pattern": "Minimaal toegestane tijd is 60 sec", + "total-allowed-time-for-verification-required": "De totale toegestane tijd is vereist.", + "use-system-two-factor-auth-settings": "Tweefactorauthenticatie-instellingen van het systeem gebruiken", + "verification-code-check-rate-limit": "Snelheidslimiet voor verificatiecodecontrole", + "verification-code-lifetime": "Levensduur verificatiecode (sec)", + "verification-code-lifetime-pattern": "De levensduur van de verificatiecode moet een positief geheel getal zijn.", + "verification-code-lifetime-required": "De levensduur van de verificatiecode is vereist.", + "verification-message-template": "Sjabloon voor verificatiebericht", + "verification-limitations": "Beperkingen voor verificatie", + "verification-message-template-pattern": "Verificatiebericht moet patroon bevatten: ${code}", + "verification-message-template-required": "Verificatieberichtsjabloon is vereist.", + "within-time": "Binnen de tijd (sec)", + "within-time-pattern": "Tijd moet een positief geheel getal zijn.", + "within-time-required": "Er is tijd nodig." + }, + "jwt": { + "security-settings": "JWT-beveiligingsinstellingen", + "issuer-name": "Naam van de uitgever", + "issuer-name-required": "De naam van de uitgever is vereist.", + "signings-key": "Sleutel ondertekenen", + "signings-key-hint": "Base64-gecodeerde tekenreeks die ten minste 256 bits aan gegevens vertegenwoordigt.", + "signings-key-required": "Ondertekeningssleutel is vereist.", + "signings-key-min-length": "De ondertekeningssleutel moet ten minste 256 bits aan gegevens bevatten.", + "signings-key-base64": "De ondertekeningssleutel moet de base64-indeling hebben.", + "expiration-time": "Vervaltijd token (sec)", + "expiration-time-required": "De vervaltijd van het token is vereist.", + "expiration-time-pattern": "De vervaltijd van het token is een positief geheel getal.", + "expiration-time-min": "De minimale tijd is 60 seconden (1 minuut).", + "refresh-expiration-time": "Vervaltijd token vernieuwen (sec)", + "refresh-expiration-time-required": "De vervaltijd van het vernieuwingstoken is vereist.", + "refresh-expiration-time-pattern": "De vervaltijd van het token vernieuwen is een positief geheel getal.", + "refresh-expiration-time-min": "De minimale tijd is 900 seconden (15 minuten).", + "refresh-expiration-time-less-token": "De tokentijd voor vernieuwen moet een grotere tokentijd zijn.", + "generate-key": "Sleutel genereren", + "info-header": "Alle gebruikers moeten opnieuw inloggen", + "info-message": "Wijziging van de JWT-ondertekeningssleutel zorgt ervoor dat alle uitgegeven tokens ongeldig zijn. Alle gebruikers moeten opnieuw inloggen. Dit heeft ook gevolgen voor scripts die gebruikmaken van Rest API/Websockets." + }, + "resources": "Weg", + "notifications": "Meldingen", + "notifications-settings": "Instellingen voor meldingen", + "slack-api-token": "Slack API-token", + "slack": "Los", + "slack-settings": "Slack-instellingen" + }, + "alarm": { + "alarm": "Alarm", + "alarms": "Alarmen", + "all-alarms": "Alle alarmen", + "select-alarm": "Selecteer alarm", + "no-alarms-matching": "Er zijn geen alarmen gevonden die overeenkomen met '{{entity}}'.", + "alarm-required": "Alarm is vereist", + "alarm-filter": "Alarm filter", + "filter": "Filter", + "alarm-status": "Alarmstatus", + "alarm-status-list": "Lijst met alarmstatussen", + "any-status": "Elke status", + "search-status": { + "ANY": "Enig", + "ACTIVE": "Actief", + "CLEARED": "Uitgeschakeld", + "ACK": "Erkend", + "UNACK": "Niet erkend" + }, + "display-status": { + "ACTIVE_UNACK": "Actief Niet erkend", + "ACTIVE_ACK": "Actief Erkend", + "CLEARED_UNACK": "Gewist Niet bevestigd", + "CLEARED_ACK": "Gewist Erkend" + }, + "no-alarms-prompt": "Geen alarmen gevonden", + "created-time": "Gecreëerde tijd", + "type": "Type", + "severity": "Strengheid", + "originator": "Opdrachtgever", + "originator-type": "Type opsteller", + "details": "Details", + "originator-label": "Etiket van de afzender", + "assign": "Toewijzen", + "assignments": "Toewijzingen", + "assignee": "Gevolmachtigde", + "assignee-id": "Verantwoordelijke ID", + "assignee-first-name": "Voornaam van de gevolmachtigde", + "assignee-last-name": "Achternaam van de cessionaris", + "assignee-email": "E-mailadres van de verantwoordelijke", + "unassigned": "Toegewezen", + "assignee-not-set": "Alle", + "status": "Status", + "alarm-details": "Details van het alarm", + "start-time": "Begintijd", + "assign-time": "Tijd toewijzen", + "end-time": "Eindtijd", + "ack-time": "Erkende tijd", + "clear-time": "Vrijgemaakte tijd", + "duration": "Duur", + "alarm-severity-list": "Lijst met alarmernst", + "any-severity": "Elke ernst", + "severity-critical": "Kritisch", + "severity-major": "Majoor", + "severity-minor": "Minderjarige", + "severity-warning": "Waarschuwing", + "severity-indeterminate": "Onbepaalde", + "acknowledge": "Erkennen", + "clear": "Duidelijk", + "search": "Alarmen zoeken", + "selected-alarms": "{ count, plural, =1 {1 alarm} andere {# alarms} } geselecteerd", + "no-data": "Geen gegevens om weer te geven", + "polling-interval": "Polling-interval alarmen (sec)", + "polling-interval-required": "Alarmen polling-interval is vereist.", + "min-polling-interval-message": "Minimaal 1 sec polling-interval is toegestaan.", + "aknowledge-alarms-title": "Erken { count, plural, =1 {1 alarm} andere {# alarms} }", + "aknowledge-alarms-text": "Weet je zeker dat je { count, plural, =1 {1 alarm} andere {# alarms} } wilt erkennen?", + "aknowledge-alarm-title": "Alarm bevestigen", + "aknowledge-alarm-text": "Weet u zeker dat u Alarm wilt erkennen?", + "clear-alarms-title": "Wis { count, plural, =1 {1 alarm} andere {# alarms} }", + "clear-alarms-text": "Weet u zeker dat u { count, plural, =1 {1 alarm} andere {# alarms} } wilt wissen?", + "clear-alarm-title": "Alarm wissen", + "clear-alarm-text": "Weet u zeker dat u Alarm wilt wissen?", + "alarm-status-filter": "Alarm Status Filter", + "alarm-filter-title": "Alarm Filter", + "assigned": "Toegewezen", + "filter-title": "Filter", + "max-count-load": "Maximaal aantal te laden alarmen (0 - onbeperkt)", + "max-count-load-required": "Er is een maximaal aantal alarmen vereist om te laden.", + "max-count-load-error-min": "Minimale waarde is 0.", + "fetch-size": "Ophaal grootte", + "fetch-size-required": "Ophaal grootte is vereist.", + "fetch-size-error-min": "Minimale waarde is 10.", + "alarm-type-list": "Lijst met alarmtypen", + "any-type": "Elk type", + "assigned-to-current-user": "Toegewezen aan huidige gebruiker", + "assigned-to-me": "Aan mij toegewezen", + "search-propagated-alarms": "Doorgegeven alarmen zoeken", + "comments": "Alarm opmerkingen", + "show-more": "Meer tonen", + "additional-info": "Aanvullende informatie" + }, + "alarm-activity": { + "add": "Voeg een reactie...", + "alarm-comment": "Alarm commentaar", + "comments": "Opmerkingen", + "delete-alarm-comment": "Wil je deze reactie verwijderen?", + "refresh": "Vernieuwen", + "oldest-first": "Oudste eerst", + "newest-first": "Nieuwste eerst", + "activity": "Activiteit", + "export": "Exporteren naar CSV", + "author": "Auteur", + "created-date": "Datum van aanmaak", + "edited-date": "Bewerkte datum", + "text": "Sms", + "system": "Systeem" + }, + "alias": { + "add": "Alias toevoegen", + "edit": "Alias bewerken", + "name": "Alias naam", + "name-required": "Aliasnaam is vereist", + "duplicate-alias": "Alias met dezelfde naam bestaat al.", + "filter-type-single-entity": "Eén entiteit", + "filter-type-entity-group": "Entiteiten van de groep", + "filter-type-entity-list": "Lijst met entiteiten", + "filter-type-entity-name": "Naam van de entiteit", + "filter-type-entity-type": "Type entiteit", + "filter-type-entity-group-list": "Lijst met entiteitsgroepen", + "filter-type-entity-group-name": "Naam van entiteitsgroep", + "filter-type-entities-by-group-name": "Entiteiten op groepsnaam", + "filter-type-state-entity": "Entiteit vanuit dashboardstatus", + "filter-type-state-entity-description": "Entiteit die is overgenomen uit de statusparameters van het dashboard", + "filter-type-state-entity-owner": "Eigenaar van entiteit vanuit dashboardstatus", + "filter-type-state-entity-owner-description": "Eigenaar van entiteit die is overgenomen uit de parameters van de dashboardstatus", + "filter-type-asset-type": "Type asset", + "filter-type-asset-type-description": "Asset van het type \"{{assetTypes}}\"", + "filter-type-asset-type-and-name-description": "Asset van het type '{{assetTypes}}' en waarvan de naam begint met '{{prefix}}'", + "filter-type-device-type": "Type device", + "filter-type-device-type-description": "Devices van het type \"{{deviceTypes}}\"", + "filter-type-device-type-and-name-description": "Devices van het type '{{deviceTypes}}' en waarvan de naam begint met '{{prefix}}'", + "filter-type-entity-view-type": "Type entiteitsweergave", + "filter-type-entity-view-type-description": "Entiteitsweergaven van het type '{{entityViewTypes}}'", + "filter-type-entity-view-type-and-name-description": "Entiteitsweergaven van het type '{{entityViewTypes}}' en met een naam die begint met '{{prefix}}'", + "filter-type-edge-type": "Type edge", + "filter-type-edge-type-description": "Edge van het type \"{{edgeTypes}}\"", + "filter-type-edge-type-and-name-description": "Edge van het type '{{edgeTypes}}' en met de naam beginnend met '{{prefix}}'", + "filter-type-relations-query": "Query op relaties", + "filter-type-relations-query-description": "{{entities}} die {{relationType}} relatie hebben {{direction}} {{rootEntity}}", + "filter-type-edge-search-query": "Edge-zoekopdracht", + "filter-type-edge-search-query-description": "Edge met types {{edgeTypes}} die {{relationType}} relatie hebben {{direction}} {{rootEntity}}", + "filter-type-scheduler-event": "Scheduler-events", + "filter-type-scheduler-event-type-description": "Scheduler-events met het type '{{eventType}}'", + "filter-type-scheduler-event-originator-description": "Scheduler-gebeurtenissen van een specifieke afzender", + "filter-type-scheduler-event-type-originator-description": "Scheduler-gebeurtenissen van een specifieke afzender met '{{eventType}}'", + "filter-type-asset-search-query": "Zoekquery voor asset", + "filter-type-asset-search-query-description": "Asset met types {{assetTypes}} die {{relationType}} relatie hebben {{direction}} {{rootEntity}}", + "filter-type-device-search-query": "Zoekquery voor device", + "filter-type-device-search-query-description": "Devices met types {{deviceTypes}} die {{relationType}} relatie hebben {{direction}} {{rootEntity}}", + "filter-type-entity-view-search-query": "Zoekquery voor entiteitsweergave", + "filter-type-entity-view-search-query-description": "Entiteitsweergaven met types {{entityViewTypes}} die {{relationType}} relatie hebben {{direction}} {{rootEntity}}", + "filter-type-apiUsageState": "Api-gebruiksstatus", + "entity-filter": "Entiteit filteren", + "resolve-multiple": "Oplossen als meerdere entiteiten", + "filter-type": "Filter type", + "filter-type-required": "Filtertype is vereist.", + "entity-filter-no-entity-matched": "Er zijn geen entiteiten gevonden die overeenkomen met het opgegeven filter.", + "no-entity-filter-specified": "Geen entiteitsfilter opgegeven", + "root-state-entity": "Dashboardstatusentiteit gebruiken als hoofdmap", + "group-state-entity": "Dashboardstatusentiteit gebruiken als entiteitsgroep", + "group-state-entity-owner": "Dashboardstatusentiteit gebruiken als eigenaar van entiteitsgroep", + "last-level-relation": "Alleen relatie op het laatste niveau ophalen", + "root-entity": "Hoofdentiteit", + "state-entity-parameter-name": "Naam van de parameter van de entiteit van de staat", + "default-state-entity": "Entiteit met standaardstatus", + "default-state-entity-group": "Entiteitsgroep standaardstatus", + "default-entity-parameter-name": "Standaard", + "max-relation-level": "Max. relatieniveau", + "unlimited-level": "Onbeperkt niveau", + "state-entity": "Entiteit voor dashboardstatus", + "entities-of-group-state-entity": "Entiteiten uit de entiteitsgroep van de dashboardstatus", + "all-entities": "Alle entiteiten", + "any-relation": "enig", + "originator": "Opdrachtgever", + "originator-state-entity": "Dashboardstatusentiteit gebruiken als afzender", + "scheduler-event-type": "Gebeurtenistype planner" + }, + "asset": { + "all": "Alle", + "all-assets": "Alle assets", + "groups": "Groepen", + "shared": "Gedeeld", + "asset": "Asset", + "assets": "Assets", + "management": "Vermogensbeheer", + "view-assets": "Assets bekijken", + "add": "Asset toevoegen", + "asset-type-max-length": "Het type asset moet kleiner zijn dan 256 tekens tekens", + "assign-to-customer": "Toewijzen aan klant", + "assign-asset-to-customer": "Asset(s) toewijzen aan klant", + "assign-asset-to-customer-text": "Selecteer de asset die u aan de klant wilt toewijzen", + "no-assets-text": "Geen asset gevonden", + "assign-to-customer-text": "Selecteer de klant om de asset toe te wijzen", + "public": "Publiek", + "assignedToCustomer": "Toegewezen aan klant", + "make-public": "Assets openbaar maken", + "make-private": "Assets privé maken", + "unassign-from-customer": "Toewijzing van klant ongedaan maken", + "delete": "Asset verwijderen", + "asset-public": "Asset is openbaar", + "asset-type": "Type asset", + "asset-type-required": "Het type asset is vereist.", + "select-asset-type": "Selecteer asset type", + "enter-asset-type": "Asset type invoeren", + "any-asset": "Elke asset", + "no-asset-types-matching": "Er zijn geen asset types gevonden die overeenkomen met '{{entitySubtype}}'.", + "asset-type-list-empty": "Er zijn geen asset types geselecteerd.", + "asset-types": "Soorten asset", + "name": "Naam", + "name-required": "Naam is verplicht.", + "name-max-length": "Naam moet kleiner zijn dan 256 tekens tekens", + "label-max-length": "Etiket moet kleiner zijn dan 256 tekens tekens", + "description": "Omschrijving: __________", + "type": "Type", + "type-required": "Type is vereist.", + "details": "Detail", + "events": "Events", + "add-asset-text": "Nieuw asset toevoegen", + "asset-details": "Details van het bedrijfsmiddel", + "assign-assets": "Middelen toewijzen", + "assign-assets-text": "Wijs { count, plural, =1 {1 asset} andere {# assets} } toe aan de klant", + "assign-asset-to-edge-title": "Asset(s) toewijzen aan Edge", + "assign-asset-to-edge-text": "Selecteer de assets die u aan de edge wilt toewijzen", + "delete-assets": "Assets verwijderen", + "unassign-assets": "Toewijzing van assets ongedaan maken", + "unassign-assets-action-title": "Toewijzing { count, plural, =1 {1 asset} andere {# assets} } van klant ongedaan maken", + "assign-new-asset": "Nieuw asset toewijzen", + "delete-asset-title": "Weet je zeker dat je de asset '{{assetName}}' wilt verwijderen?", + "delete-asset-text": "Opgelet, na de bevestiging worden de asset en alle gerelateerde gegevens onherstelbaar.", + "delete-assets-title": "Weet u zeker dat u { count, plural, =1 {1 asset} andere {# assets} } wilt verwijderen?", + "delete-assets-action-title": "Verwijder { count, plural, =1 {1 asset} andere {# assets} }", + "delete-assets-text": "Opgelet, na de bevestiging worden alle geselecteerde assets verwijderd en kunnen alle gerelateerde gegevens niet meer worden hersteld.", + "make-public-asset-title": "Weet je zeker dat je de asset '{{assetName}}' openbaar wilt maken?", + "make-public-asset-text": "Na de bevestiging worden de asset en alle bijbehorende gegevens openbaar en toegankelijk gemaakt voor anderen.", + "make-private-asset-title": "Weet je zeker dat je de asset '{{assetName}}' privé wilt maken?", + "make-private-asset-text": "Na de bevestiging worden de asset en al zijn gegevens privé gemaakt en zijn ze niet toegankelijk voor anderen.", + "unassign-asset-title": "Weet je zeker dat je de toewijzing van de asset '{{assetName}}' ongedaan wilt maken?", + "unassign-asset-text": "Na de bevestiging wordt de toewijzing van de asset ongedaan gemaakt en is het niet toegankelijk voor de klant.", + "unassign-asset": "Toewijzing van asset ongedaan maken", + "unassign-assets-title": "Weet u zeker dat u de toewijzing van { count, plural, =1 {1 asset} andere {# assets} } wilt opheffen?", + "unassign-assets-text": "Na de bevestiging worden alle geselecteerde assets ongedaan gemaakt en zijn ze niet toegankelijk voor de klant.", + "copyId": "Item-ID kopiëren", + "idCopiedMessage": "Item-ID is gekopieerd naar het klembord", + "select-asset": "Selecteer asset", + "no-assets-matching": "Er zijn geen assets gevonden die overeenkomen met '{{entity}}'.", + "asset-required": "Asset is vereist", + "name-starts-with": "Expressie van itemnaam", + "help-text": "Gebruik '%' naar behoefte: '%asset_name_contains%', '%asset_name_ends', 'asset_starts_with'.", + "search": "Assets zoeken", + "select-group-to-add": "Selecteer doelgroep om geselecteerde assets toe te voegen", + "select-group-to-move": "Selecteer de doelgroep om geselecteerde assets te verplaatsen", + "remove-assets-from-group": "Weet je zeker dat je { count, plural, =1 {1 asset} andere {# assets} } uit groep '{{entityGroup}}' wilt verwijderen?", + "group": "Groep van assets", + "list-of-groups": "{ count, plural, =1 {One asset group} andere {List of # asset groups} }", + "group-name-starts-with": "Asset groepen waarvan de naam begint met '{{prefix}}'", + "import": "Asset importeren", + "asset-file": "Asset bestand", + "label": "Etiket", + "assign-asset-to-edge": "Asset(s) toewijzen aan Edge", + "unassign-asset-from-edge": "Toewijzing van asset ongedaan maken", + "unassign-asset-from-edge-title": "Weet je zeker dat je de toewijzing van de asset '{{assetName}}' ongedaan wilt maken?", + "unassign-asset-from-edge-text": "Na de bevestiging wordt de toewijzing van de asset ongedaan gemaakt en is het niet toegankelijk via de edge.", + "unassign-assets-from-edge-title": "Weet u zeker dat u de toewijzing van { count, plural, =1 {1 asset} andere {# assets} } wilt opheffen?", + "unassign-assets-from-edge-text": "Na de bevestiging worden alle geselecteerde assets ongedaan gemaakt en zijn ze niet toegankelijk via de edge.", + "selected-assets": "{ count, plural, =1 {1 asset} andere {# assets} } geselecteerd" + }, + "attribute": { + "attributes": "Attributen", + "latest-telemetry": "Nieuwste telemetrie", + "attributes-scope": "Bereik van entiteits attributen", + "scope-latest-telemetry": "Nieuwste telemetrie", + "scope-client": "Attributen van de klant", + "scope-server": "Server-attributen", + "scope-shared": "Gedeelde attributen", + "add": "Attribuut toevoegen", + "add-attribute-prompt": "Voeg attribuut toe", + "key": "Sleutel", + "key-max-length": "Sleutel moet kleiner zijn dan 256 tekens tekens", + "last-update-time": "Laatste update tijd", + "key-required": "Attribuutsleutel is vereist.", + "value": "Waarde", + "value-required": "Kenmerkwaarde is vereist.", + "delete-attributes-title": "Weet u zeker dat u { count, plural, =1 {1 attribute} andere {# attributes} } wilt verwijderen?", + "delete-attributes-text": "Opgelet, na de bevestiging worden alle geselecteerde attributen verwijderd.", + "delete-attributes": "Attributen verwijderen", + "enter-attribute-value": "Kenmerkwaarde invoeren", + "show-on-widget": "Toon op widget", + "widget-mode": "Widget-modus", + "next-widget": "Volgende widget", + "prev-widget": "Vorige widget", + "add-to-dashboard": "Toevoegen aan dashboard", + "add-widget-to-dashboard": "Widget toevoegen aan dashboard", + "selected-attributes": "{ count, plural, =1 {1 attribute} andere {# attributes} } geselecteerd", + "selected-telemetry": "{ count, plural, =1 {1 telemetry unit} andere {# telemetry units} } geselecteerd", + "no-attributes-text": "Geen attributen gevonden", + "no-telemetry-text": "Geen telemetrie gevonden", + "copy-key": "Kopieer sleutel", + "copy-value": "Waarde kopiëren" + }, + "api-usage": { + "api-features": "API-functies", + "api-usage": "API-gebruik", + "alarm": "Alarm", + "alarms-created": "Alarmen gemaakt", + "alarms-created-daily-activity": "Alarmen creëerden dagelijkse activiteit", + "alarms-created-hourly-activity": "Alarmen creëerden activiteit per uur", + "alarms-created-monthly-activity": "Alarmen creëerden maandelijkse activiteit", + "data-points": "Datapunten", + "data-points-storage-days": "Opslagdagen voor datapunten", + "device-api": "Device-API", + "email": "E-mail", + "email-messages": "E-mailberichten", + "email-messages-daily-activity": "Dagelijkse activiteit e-mailberichten", + "email-messages-monthly-activity": "Maandelijkse activiteit e-mailberichten", + "exceptions": "Uitzonderingen", + "executions": "Executies", + "javascript": "JavaScript", + "javascript-executions": "JavaScript-uitvoeringen", + "javascript-functions": "JavaScript-functies", + "javascript-functions-daily-activity": "JavaScript-functies dagelijkse activiteit", + "javascript-functions-hourly-activity": "JavaScript-functies activiteit per uur", + "javascript-functions-monthly-activity": "JavaScript-functies maandelijkse activiteit", + "latest-error": "Laatste error", + "messages": "Berichten", + "notifications": "Meldingen", + "notifications-email-sms": "Meldingen (e-mail/sms)", + "notifications-hourly-activity": "Meldingen activiteit per uur", + "permanent-failures": "${entityName} Permanente storingen", + "permanent-timeouts": "Permanente time-outs van $ {entityName}", + "processing-failures": "${entityName} Verwerkingsfouten", + "processing-failures-and-timeouts": "Verwerkingsfouten en time-outs", + "processing-timeouts": "${entityName} time-outs voor verwerking", + "queue-stats": "Queue Statistieken", + "rule-chain": "Rule chain", + "rule-engine": "Rule engine", + "rule-engine-daily-activity": "Dagelijkse activiteit van de rule engine", + "rule-engine-executions": "Uitvoeringen van rule engine", + "rule-engine-hourly-activity": "Rule engine uurlijkse activiteit", + "rule-engine-monthly-activity": "Maandelijkse activiteit van Rule Engine", + "rule-engine-statistics": "Rule Engine-statistieken", + "rule-node": "Regel Knooppunt", + "sms": "SMS", + "sms-messages": "SMS-berichten", + "sms-messages-daily-activity": "Dagelijkse activiteit SMS-berichten", + "sms-messages-monthly-activity": "SMS-berichten maandelijkse activiteit", + "successful": "${entityName} Succesvol", + "telemetry": "Telemetrie", + "telemetry-persistence": "Persistentie van telemetrie", + "telemetry-persistence-daily-activity": "Dagelijkse activiteit met behoud van telemetrie", + "telemetry-persistence-hourly-activity": "Telemetriepersistentie activiteit per uur", + "telemetry-persistence-monthly-activity": "Maandelijkse activiteit voor telemetriepersistentie", + "transport": "Vervoer", + "transport-daily-activity": "Vervoer dagelijkse activiteit", + "transport-data-points": "Datapunten voor transport", + "transport-hourly-activity": "Vervoer per uur", + "transport-messages": "Berichten vervoeren", + "transport-monthly-activity": "Maandelijkse activiteit Transport", + "view-details": "Bekijk details", + "view-statistics": "Statistieken bekijken" + }, + "audit-log": { + "audit": "Audit", + "audit-logs": "Audit Logboeken", + "timestamp": "Tijdstempel", + "entity-type": "Type entiteit", + "entity-name": "Naam van de entiteit", + "user": "Gebruiker", + "type": "Type", + "status": "Status", + "details": "Details", + "type-added": "Toegevoegd", + "type-deleted": "Verwijderd", + "type-updated": "Bijgewerkt", + "type-attributes-updated": "Attributen geüpdatet", + "type-attributes-deleted": "Attributen verwijderd", + "type-rpc-call": "RPC-oproep", + "type-credentials-updated": "Inloggegevens bijgewerkt", + "type-assigned-to-customer": "Toegewezen aan klant", + "type-unassigned-from-customer": "Toewijzing van klant ongedaan gemaakt", + "type-assigned-to-edge": "Toegewezen aan Edge", + "type-unassigned-from-edge": "Toewijzing van Edge ongedaan gemaakt", + "type-activated": "Geactiveerd", + "type-suspended": "Latent", + "type-credentials-read": "Referenties gelezen", + "type-attributes-read": "Gelezen attributen", + "type-added-to-entity-group": "Toegevoegd aan groep", + "type-removed-from-entity-group": "Verwijderd uit groep", + "type-relation-add-or-update": "Relatie geüpdatet", + "type-relation-delete": "Relatie verwijderd", + "type-relations-delete": "Alle relaties verwijderd", + "type-alarm-ack": "Erkend", + "type-alarm-clear": "Uitgeschakeld", + "type-alarm-assign": "Toegewezen", + "type-alarm-unassign": "Toegewezen", + "type-added-comment": "Reactie toegevoegd", + "type-updated-comment": "Bijgewerkte reactie", + "type-deleted-comment": "Verwijderde reactie", + "type-rest-api-rule-engine-call": "REST API-aanroep van rule engine", + "type-made-public": "Openbaar gemaakt", + "type-made-private": "Privé gemaakt", + "type-login": "Inloggen", + "type-logout": "Logout", + "type-lockout": "Lockout", + "status-success": "Succes", + "status-failure": "Fout", + "audit-log-details": "Details van het auditlogboek", + "no-audit-logs-prompt": "Geen logboeken gevonden", + "action-data": "Actie gegevens", + "failure-details": "Details van de fout", + "search": "Auditlogboeken doorzoeken", + "clear-search": "Zoekopdracht wissen", + "type-assigned-from-tenant": "Toegewezen door tenant", + "type-assigned-to-tenant": "Toegewezen aan tenant", + "type-provision-success": "Device ingericht", + "type-provision-failure": "Het inrichten van devices is mislukt", + "type-timeseries-updated": "Telemetrie bijgewerkt", + "type-timeseries-deleted": "Telemetrie verwijderd", + "type-owner-changed": "Eigenaar gewijzigd" + }, + "confirm-on-exit": { + "message": "U hebt niet-opgeslagen wijzigingen. Weet je zeker dat je deze pagina wilt verlaten?", + "html-message": "U hebt niet-opgeslagen wijzigingen.
Weet je zeker dat je deze pagina wilt verlaten?", + "title": "Niet-opgeslagen wijzigingen" + }, + "contact": { + "country": "Land", + "city": "Stad", + "state": "Staat / Provincie", + "postal-code": "Postcode", + "postal-code-invalid": "Ongeldige postcode notatie.", + "address": "Adres", + "address2": "Adres 2", + "phone": "Telefoon", + "email": "E-mail", + "no-address": "Geen adres", + "state-max-length": "De lengte van de staat moet kleiner zijn dan 256 tekens tekens", + "phone-max-length": "Telefoonnummer moet minder zijn dan 256 tekens tekens", + "city-max-length": "De opgegeven stad moet kleiner zijn dan 256 tekens tekens" + }, + "common": { + "username": "Gebruikersnaam", + "password": "Wachtwoord", + "enter-username": "Gebruikersnaam invoeren", + "enter-password": "Wachtwoord invoeren", + "enter-search": "Zoekopdracht invoeren", + "created-time": "Gecreëerde tijd", + "loading": "Laden...", + "proceed": "Doorgaan", + "open-details-page": "Detailpagina openen" + }, + "converter": { + "converter": "Gegevens converteren", + "converters": "Data-converters", + "select-converter": "Selecteer gegevensomzetter", + "no-converters-matching": "Er zijn geen gegevensconverters gevonden die overeenkomen met '{{entity}}'.", + "no-converters-found": "Geen dataconverters gevonden.", + "converter-required": "Dataconverter is vereist", + "delete": "Converter verwijderen", + "management": "Beheer van dataconverters", + "add-converter-text": "Nieuwe gegevensconverter toevoegen", + "no-converters-text": "Geen dataconverters gevonden", + "selected-converters": "{ count, plural, =1 {1 data converter} andere {# data converters} } geselecteerd", + "delete-converter-title": "Weet u zeker dat u de dataconverter '{{converterName}}' wilt verwijderen?", + "delete-converter-text": "Opgelet, na de bevestiging worden de gegevensomzetter en alle gerelateerde gegevens onherstelbaar.", + "delete-converters-title": "Weet u zeker dat u { count, plural, =1 {1 data converter} andere {# data converters} } wilt verwijderen?", + "delete-converters-action-title": "Verwijder { count, plural, =1 {1 data converter} andere {# data converters} }", + "delete-converters-text": "Opgelet, na de bevestiging worden alle geselecteerde gegevensconverters verwijderd en kunnen alle gerelateerde gegevens niet meer worden hersteld.", + "events": "Events", + "add": "Gegevensconverter toevoegen", + "search": "Gegevensconverters zoeken", + "converter-details": "Details van de gegevensconverter", + "details": "Details", + "copyId": "Kopieer converter-ID", + "idCopiedMessage": "Converter-ID is gekopieerd naar klembord", + "debug-mode": "Foutopsporingsmodus", + "created-time": "Gecreëerde tijd", + "name": "Naam", + "name-required": "Naam is verplicht.", + "name-max-length": "Naam moet kleiner zijn dan 256 tekens", + "description": "Omschrijving: __________", + "decoder": "Decoder", + "encoder": "Coderingsprogramma", + "test-decoder-fuction": "Test decoder functie", + "test-encoder-fuction": "Encoderfunctie testen", + "decoder-input-params": "Ingangsparameters decoder", + "encoder-input-params": "Ingangsparameters van de encoder", + "payload": "Nettolading", + "payload-content-type": "Inhoudstype payload", + "payload-content": "Inhoud van payload", + "message": "Bericht", + "message-type": "Soort bericht", + "message-type-required": "Berichttype is vereist", + "test": "Test", + "metadata": "Metagegevens", + "metadata-required": "Metagegevensvermeldingen mogen niet leeg zijn.", + "integration-metadata": "Integratie metadata", + "integration-metadata-required": "Vermeldingen in integratiemetagegevens mogen niet leeg zijn.", + "output": "Uitvoer", + "import": "Converter importeren", + "export": "Converter exporteren", + "export-failed-error": "Kan converter niet exporteren: {{error}}", + "create-new-converter": "Nieuwe converter maken", + "converter-file": "Converter bestand", + "invalid-converter-file-error": "Kan converter niet importeren: Ongeldige gegevensstructuur van converter.", + "type": "Type", + "type-required": "Type is vereist.", + "type-uplink": "Uplink", + "type-downlink": "Downlink" + }, + "content-type": { + "json": "Json", + "text": "Sms", + "binary": "Binair (Base64)" + }, + "color": { + "color-picker": "Kleurkiezer", + "primary-colors": "Primaire kleuren", + "accent-colors": "Accent kleuren", + "no-color-selected": "Geen kleur geselecteerd" + }, + "customer": { + "all": "Alle", + "all-customers": "Alle klanten", + "groups": "Groepen", + "shared": "Gedeeld", + "hierarchy": "Hiërarchie", + "customer": "Klant", + "customers": "Klanten", + "management": "Klantenbeheer", + "dashboard": "Klantendashboard", + "dashboards": "Dashboards voor klanten", + "devices": "Devices van klanten", + "entity-views": "Weergaven van klantentiteiten", + "assets": "Assets van klanten", + "public-dashboards": "Openbare dashboards", + "public-devices": "Openbare devices", + "public-assets": "Publieke assets", + "public-entity-views": "Weergaven van openbare entiteit-views", + "add": "Klant toevoegen", + "delete": "Klant verwijderen", + "manage-customer-user-groups": "Gebruikersgroepen van klanten beheren", + "manage-customer-groups": "Klantgroepen beheren", + "manage-customer-device-groups": "Asset groepen van klanten beheren", + "manage-customer-asset-groups": "Asset groepen van klanten beheren", + "manage-customer-entity-view-groups": "Weergavegroepen voor klantentiteiten beheren", + "manage-customer-edge-groups": "Edge-groepen voor klanten beheren", + "manage-customer-dashboard-groups": "Groepen klantendashboards beheren", + "manage-customer-users": "Klantgebruikers beheren", + "manage-customers": "Klanten beheren", + "manage-customer-devices": "Devices van klanten beheren", + "manage-customer-entity-views": "Weergaven van klantentiteiten beheren", + "manage-customer-dashboards": "Klantdashboards beheren", + "manage-public-devices": "Openbare devices beheren", + "manage-public-dashboards": "Openbare dashboards beheren", + "manage-customer-assets": "Klant devices beheren", + "manage-customer-edges": "Beheer klant edges", + "manage-public-assets": "Openbare asset beheren", + "add-customer-text": "Nieuwe klant toevoegen", + "no-customers-text": "Geen klanten gevonden", + "customer-details": "Klantgegevens", + "delete-customer-title": "Weet je zeker dat je de '{{customerTitle}}' van de klant wilt verwijderen?", + "delete-customer-text": "Let op, na de bevestiging worden de klant en alle gerelateerde gegevens onherstelbaar.", + "delete-customers-title": "Weet u zeker dat u { count, plural, =1 {1 customer} andere {# customers} } wilt verwijderen?", + "delete-customers-action-title": "Verwijder { count, plural, =1 {1 customer} andere {# customers} }", + "delete-customers-text": "Opgelet, na de bevestiging worden alle geselecteerde klanten verwijderd en kunnen alle gerelateerde gegevens niet meer worden hersteld.", + "manage-user-groups": "Gebruikersgroepen beheren", + "manage-asset-groups": "Asset groepen beheren", + "manage-device-groups": "Asset groepen beheren", + "manage-dashboard-groups": "Dashboardgroepen beheren", + "manage-entity-view-groups": "Entiteitsweergavegroepen beheren", + "manage-edge-groups": "Edge-groepen beheren", + "manage-users": "Gebruikers beheren", + "manage-assets": "Assets beheren", + "manage-devices": "Devices beheren", + "manage-dashboards": "Dashboards beheren", + "manage-entity-views": "Entiteitsweergaven beheren", + "title": "Titel", + "title-required": "Titel is vereist.", + "title-max-length": "Titel moet kleiner zijn dan 256 tekens", + "description": "Omschrijving: __________", + "details": "Details", + "events": "Events", + "copyId": "Kopieer klant-ID", + "idCopiedMessage": "Klant-ID is gekopieerd naar klembord", + "select-customer": "Selecteer klant", + "no-customers-matching": "Er zijn geen klanten gevonden die overeenkomen met '{{entity}}'.", + "customer-required": "Klant is verplicht", + "select-group-to-add": "Selecteer doelgroep om geselecteerde klanten toe te voegen", + "select-group-to-move": "Selecteer doelgroep om geselecteerde klanten te verhuizen", + "remove-customers-from-group": "Weet je zeker dat je { count, plural, =1 {1 customer} andere {# customers} } uit groep '{{entityGroup}}' wilt verwijderen?", + "group": "Groep klanten", + "list-of-groups": "{ count, plural, =1 {One customer group} andere {List of # customer groups} }", + "group-name-starts-with": "Klantgroepen waarvan de naam begint met '{{prefix}}'", + "select-default-customer": "Selecteer standaardklant", + "default-customer": "Standaard klant", + "default-customer-required": "Standaardklant is vereist om fouten op te sporen in het dashboard op tenantniveau", + "allow-white-labeling": "White Labeling toestaan", + "search": "Klanten zoeken", + "selected-customers": "{ count, plural, =1 {1 customer} andere {# customers} } geselecteerd", + "edges": "Edge-instanties van de klant", + "manage-edges": "Edge beheren" + }, + "customers-hierarchy": { + "customers-hierarchy": "Hiërarchie van klanten", + "open-nav-tree": "Navigatiestructuur openen", + "return-to-top-level": "Terug naar het hoogste niveau" + }, + "custom-menu": { + "custom-menu": "Aangepast menu", + "custom-menu-hint": "Definieer hieronder de JSON van het aangepaste menu. Deze JSON bevat een lijst met aangepaste menu-items." + }, + "custom-translation": { + "custom-translation": "Aangepaste vertaling", + "translation-map": "Vertaling kaart", + "key": "Vertaling sleutel", + "import": "Vertaling importeren", + "export": "Vertaling exporteren", + "export-data": "Vertaalgegevens exporteren", + "import-data": "Vertaalgegevens importeren", + "translation-file": "Vertaal bestand", + "invalid-translation-file-error": "Kan vertaalbestand niet importeren: Ongeldige gegevensstructuur voor vertalingen.", + "custom-translation-hint": "Definieer hieronder de JSON voor aangepaste vertalingen. Deze JSON overschrijft de standaardvertaling. Klik op 'Download locale file' om een bestaande vertaling te krijgen. U kunt het gedownloade bestand ook gebruiken als referentie voor beschikbare sleutel-waardeparen voor vertalingen.", + "download-locale-file": "Landinstellingsbestand downloaden" + }, + "datetime": { + "date-from": "Datum van", + "time-from": "Tijd van", + "date-to": "Datum tot", + "time-to": "Tijd om" + }, + "dashboard": { + "all": "Alle", + "all-dashboards": "Alle dashboards", + "groups": "Groepen", + "shared": "Gedeeld", + "dashboard": "Dashboard", + "dashboards": "Dashboards", + "management": "Beheer van dashboards", + "view-dashboards": "Dashboards bekijken", + "add": "Dashboard toevoegen", + "assign-dashboard-to-customer": "Dashboard(s) toewijzen aan klant", + "assign-dashboard-to-customer-text": "Selecteer de dashboards die u aan de klant wilt toewijzen", + "assign-to-customer-text": "Selecteer de klant om de dashboard(s) toe te wijzen", + "assign-to-customer": "Toewijzen aan klant", + "unassign-from-customer": "Toewijzing van klant ongedaan maken", + "make-public": "Dashboard openbaar maken", + "make-private": "Dashboard privé maken", + "manage-assigned-customers": "Toegewezen klanten beheren", + "assigned-customers": "Toegewezen klanten", + "assign-to-customers": "Dashboard(s) toewijzen aan klanten", + "assign-to-customers-text": "Selecteer de klanten om de dashboard(s) toe te wijzen", + "unassign-from-customers": "Toewijzing van dashboard(s) van klanten ongedaan maken", + "unassign-from-customers-text": "Selecteer de klanten die u wilt opheffen in de dashboard(s)", + "no-dashboards-text": "Geen dashboards gevonden", + "no-widgets": "Geen widgets geconfigureerd", + "add-widget": "Nieuwe widget toevoegen", + "title": "Titel", + "image": "Dashboard afbeelding", + "mobile-app-settings": "Instellingen voor mobiele applicaties", + "mobile-order": "Dashboardbestelling in mobiele applicatie", + "mobile-hide": "Dashboard verbergen in mobiele applicatie", + "update-image": "Dashboardafbeelding bijwerken", + "take-screenshot": "Screenshot maken", + "select-widget-title": "Selecteer widget", + "select-widget-value": "{{title}}: Widget selecteren", + "select-widget-subtitle": "Lijst met beschikbare widgettypen", + "delete": "Dashboard verwijderen", + "title-required": "Titel is vereist.", + "title-max-length": "Titel moet kleiner zijn dan 256 tekens tekens", + "description": "Omschrijving: __________", + "details": "Details", + "dashboard-details": "Details van het dashboard", + "add-dashboard-text": "Nieuw dashboard toevoegen", + "assign-dashboards": "Dashboards toewijzen", + "assign-new-dashboard": "Nieuw dashboard toewijzen", + "assign-dashboards-text": "Wijs { count, plural, =1 {1 dashboard} andere {# dashboards} } toe aan klanten", + "unassign-dashboards-action-text": "Toewijzing { count, plural, =1 {1 dashboard} andere {# dashboards} } van klanten ongedaan maken", + "delete-dashboards": "Dashboards verwijderen", + "unassign-dashboards": "Toewijzing van dashboards ongedaan maken", + "unassign-dashboards-action-title": "Toewijzing { count, plural, =1 {1 dashboard} andere {# dashboards} } van klant ongedaan maken", + "delete-dashboard-title": "Weet je zeker dat je de '{{dashboardTitle}}' van het dashboard wilt verwijderen?", + "delete-dashboard-text": "Opgelet, na de bevestiging worden het dashboard en alle gerelateerde gegevens onherstelbaar.", + "delete-dashboards-title": "Weet u zeker dat u { count, plural, =1 {1 dashboard} andere {# dashboards} } wilt verwijderen?", + "delete-dashboards-action-title": "Verwijder { count, plural, =1 {1 dashboard} andere {# dashboards} }", + "delete-dashboards-text": "Opgelet, na de bevestiging worden alle geselecteerde dashboards verwijderd en worden alle gerelateerde gegevens onherstelbaar.", + "unassign-dashboard-title": "Weet u zeker dat u de toewijzing van het dashboard '{{dashboardTitle}}' wilt opheffen?", + "unassign-dashboard-text": "Na de bevestiging wordt de toewijzing van het dashboard ongedaan gemaakt en is het niet toegankelijk voor de klant.", + "unassign-dashboard": "Toewijzing dashboard ongedaan maken", + "unassign-dashboards-title": "Weet u zeker dat u de toewijzing van { count, plural, =1 {1 dashboard} andere {# dashboards} } wilt opheffen?", + "unassign-dashboards-text": "Na de bevestiging worden alle geselecteerde dashboards ongedaan gemaakt en zijn ze niet toegankelijk voor de klant.", + "public-dashboard-title": "Dashboard is nu openbaar", + "public-dashboard-text": "De {{dashboardTitle}} van uw dashboard is nu openbaar en toegankelijk via de volgende openbare link:", + "public-dashboard-notice": "notitie: Vergeet niet om gerelateerde devices openbaar te maken om toegang te krijgen tot hun gegevens.", + "public-dashboard-link": "Koppeling naar openbaar dashboard", + "public-dashboard-link-text": "Uw openbare dashboard {{dashboardTitle}} is toegankelijk via de volgende openbare link:", + "public-dashboard-link-notice": "notitie: Vergeet niet om gerelateerde Devices, asset en entiteitsweergaven openbaar te maken om toegang te krijgen tot hun gegevens.", + "make-private-dashboard-title": "Weet je zeker dat je het dashboard '{{dashboardTitle}}' privé wilt maken?", + "make-private-dashboard-text": "Na de bevestiging wordt het dashboard privé gemaakt en is het niet toegankelijk voor anderen.", + "make-private-dashboard": "Dashboard privé maken", + "socialshare-text": "'{{dashboardTitle}}' mogelijk gemaakt door ThingsBoard", + "socialshare-title": "'{{dashboardTitle}}' mogelijk gemaakt door ThingsBoard", + "select-dashboard": "Selecteer dashboard", + "no-dashboards-matching": "Er zijn geen dashboards gevonden die overeenkomen met '{{entity}}'.", + "dashboard-required": "Dashboard is vereist.", + "select-existing": "Bestaand dashboard selecteren", + "create-new": "Nieuw dashboard maken", + "new-dashboard-title": "Nieuwe dashboardtitel", + "open-dashboard": "Dashboard openen", + "set-background": "Achtergrond instellen", + "background-color": "Achtergrondkleur", + "background-image": "Achtergrondafbeelding", + "background-size-mode": "Modus voor achtergrondgrootte", + "no-image": "Geen afbeelding geselecteerd", + "empty-image": "Geen afbeelding", + "drop-image": "Zet een afbeelding neer of klik om een bestand te selecteren om te uploaden.", + "maximum-upload-file-size": "Maximale bestandsgrootte uploaden: {{ size }}", + "cannot-upload-file": "Kan bestand niet uploaden", + "settings": "Instellingen", + "layout-settings": "Lay-out instellingen", + "columns-count": "Aantal kolommen", + "columns-count-required": "Het aantal kolommen is vereist.", + "min-columns-count-message": "Er is slechts een minimum van 10 kolommen toegestaan.", + "max-columns-count-message": "Er is slechts een maximum van 1000 kolommen toegestaan.", + "widgets-margins": "Marge tussen widgets", + "margin-required": "Margewaarde is vereist.", + "min-margin-message": "Alleen 0 is toegestaan als minimale margewaarde.", + "max-margin-message": "Slechts 50 is toegestaan als maximale margewaarde.", + "horizontal-margin": "Horizontale marge", + "horizontal-margin-required": "Horizontale margewaarde is vereist.", + "min-horizontal-margin-message": "Alleen 0 is toegestaan als minimale horizontale margewaarde.", + "max-horizontal-margin-message": "Slechts 50 is toegestaan als maximale horizontale margewaarde.", + "vertical-margin": "Verticale marge", + "vertical-margin-required": "Verticale margewaarde is vereist.", + "min-vertical-margin-message": "Alleen 0 is toegestaan als minimale verticale margewaarde.", + "max-vertical-margin-message": "Slechts 50 is toegestaan als maximale verticale margewaarde.", + "apply-outer-margin": "Marges toepassen op de zijkanten van de lay-out", + "autofill-height": "Lay-outhoogte automatisch vullen", + "mobile-layout": "Mobiele lay-outinstellingen", + "mobile-row-height": "Mobiele rijhoogte, px", + "mobile-row-height-required": "De waarde van de rijhoogte van de mobiele rij is vereist.", + "min-mobile-row-height-message": "Er zijn slechts 5 pixels toegestaan als minimale waarde voor de rijhoogte van mobiele rijen.", + "max-mobile-row-height-message": "Er zijn slechts 200 pixels toegestaan als maximale waarde voor de rijhoogte van mobiele Devices.", + "title-settings": "Titelinstellingen", + "display-title": "Dashboardtitel weergeven", + "title-color": "Titel kleur", + "toolbar-settings": "Werkbalk-instellingen", + "hide-toolbar": "Werkbalk verbergen", + "toolbar-always-open": "Werkbalk open houden", + "display-dashboards-selection": "Dashboardselectie weergeven", + "display-entities-selection": "Selectie van weergave-entiteiten", + "display-filters": "Filters weergeven", + "display-dashboard-timewindow": "Tijdvenster weergeven", + "display-dashboard-export": "Export weergeven", + "display-update-dashboard-image": "Afbeelding van updatedashboard weergeven", + "dashboard-logo-settings": "Instellingen voor dashboardlogo's", + "display-dashboard-logo": "Logo weergeven in volledig scherm dashboard", + "dashboard-logo-image": "Afbeelding van het dashboardlogo", + "advanced-settings": "Geavanceerde instellingen", + "dashboard-css": "Dashboard CSS", + "import": "Dashboard importeren", + "export": "Dashboard exporteren", + "export-failed-error": "Dashboard kan niet worden geëxporteerd: {{error}}", + "export-pdf": "Exporteren als PDF", + "export-png": "Exporteren als PNG", + "export-jpg": "Exporteren als JPEG", + "export-json-config": "JSON-configuratie exporteren", + "download-dashboard-progress": "Dashboard genereren {{reportType}} ...", + "create-new-dashboard": "Nieuw dashboard maken", + "dashboard-file": "Dashboard bestand", + "invalid-dashboard-file-error": "Dashboard kan niet worden geïmporteerd: Ongeldige gegevensstructuur van het dashboard.", + "dashboard-import-missing-aliases-title": "Aliassen configureren die worden gebruikt door geïmporteerd dashboard", + "create-new-widget": "Nieuwe widget maken", + "import-widget": "Widget importeren", + "widget-file": "Widget bestand", + "invalid-widget-file-error": "Widget kan niet worden geïmporteerd: Ongeldige gegevensstructuur van de widget.", + "widget-import-missing-aliases-title": "Aliassen configureren die worden gebruikt door geïmporteerde widgets", + "open-toolbar": "Dashboardwerkbalk openen", + "close-toolbar": "Werkbalk sluiten", + "configuration-error": "Configuratie fout", + "alias-resolution-error-title": "Configuratiefout voor dashboardaliassen", + "invalid-aliases-config": "Kan geen devices vinden die overeenkomen met sommige aliassenfilter.
Neem contact op met uw beheerder om dit probleem op te lossen.", + "select-devices": "Devices selecteren", + "assignedToCustomer": "Toegewezen aan klant", + "assignedToCustomers": "Toegewezen aan klanten", + "public": "Publiek", + "copyId": "Dashboard-id kopiëren", + "idCopiedMessage": "Dashboard-id is gekopieerd naar klembord", + "public-link": "Openbare link", + "copy-public-link": "Kopieer openbare link", + "public-link-copied-message": "De openbare koppeling naar het dashboard is gekopieerd naar het klembord", + "manage-states": "Dashboardstatussen beheren", + "states": "Statussen van dashboards", + "search-states": "Statussen van zoekdashboard", + "selected-states": "{ count, plural, =1 {1 dashboard state} andere {# dashboard states} } geselecteerd", + "edit-state": "Dashboardstatus bewerken", + "delete-state": "Dashboardstatus verwijderen", + "add-state": "Dashboardstatus toevoegen", + "no-states-text": "Geen staten gevonden", + "state": "Status van het dashboard", + "state-name": "Naam", + "state-name-required": "De naam van de dashboardstatus is vereist.", + "state-id": "Staats-ID", + "state-id-required": "Status-id van het dashboard is vereist.", + "state-id-exists": "De status van het dashboard met dezelfde id bestaat al.", + "is-root-state": "Wortel staat", + "delete-state-title": "Dashboardstatus verwijderen", + "delete-state-text": "Weet u zeker dat u de status van het dashboard met de naam '{{stateName}}' wilt verwijderen?", + "show-details": "Details weergeven", + "hide-details": "Verberg details", + "select-state": "Selecteer de doelstatus", + "state-controller": "Controle van de staat", + "search": "Dashboards doorzoeken", + "selected-dashboards": "{ count, plural, =1 {1 dashboard} andere {# dashboards} } geselecteerd", + "home-dashboard": "Startpagina dashboard", + "home-dashboard-hide-toolbar": "Verberg de werkbalk van het startdashboard", + "select-group-to-add": "Selecteer doelgroep om geselecteerde dashboards toe te voegen", + "select-group-to-move": "Selecteer de doelgroep om geselecteerde dashboards te verplaatsen", + "remove-dashboards-from-group": "Weet je zeker dat je { count, plural, =1 {1 dashboard} andere {# dashboards} } uit groep '{{entityGroup}}' wilt verwijderen?", + "group": "Groep dashboards", + "list-of-groups": "{ count, plural, =1 {One dashboard group} andere {List of # dashboard groups} }", + "group-name-starts-with": "Dashboardgroepen waarvan de naam begint met '{{prefix}}'", + "unassign-dashboard-from-edge-text": "Na de bevestiging wordt de toewijzing van het dashboard ongedaan gemaakt en is het niet toegankelijk voor de edge.", + "unassign-dashboards-from-edge-title": "Weet u zeker dat u de toewijzing van { count, plural, =1 {1 dashboard} andere {# dashboards} } wilt opheffen?", + "unassign-dashboards-from-edge-text": "Na de bevestiging worden alle geselecteerde dashboards ongedaan gemaakt en zijn ze niet toegankelijk voor de edge.", + "assign-dashboard-to-edge": "Dashboard(s) toewijzen aan Edge", + "assign-dashboard-to-edge-text": "Selecteer de dashboards die u aan de edge wilt toewijzen", + "non-existent-dashboard-state-error": "Dashboardstatus met id '{{ stateId }}' is niet gevonden" + }, + "datakey": { + "settings": "Instellingen", + "advanced": "Geavanceerd", + "label": "Etiket", + "color": "Kleur", + "units": "Speciaal symbool om naast waarde weer te geven", + "decimals": "Aantal cijfers na drijvende komma", + "data-generation-func": "Functie voor het genereren van gegevens", + "use-data-post-processing-func": "Gebruik de functie voor het nabewerken van gegevens", + "configuration": "Configuratie van gegevenssleutels", + "timeseries": "Timeseries", + "attributes": "Attributen", + "entity-field": "Entiteit veld", + "alarm": "Alarmvelden", + "timeseries-required": "Timeseries van entiteiten zijn vereist.", + "timeseries-or-attributes-required": "Timeseries/attributen van entiteiten zijn vereist.", + "alarm-fields-timeseries-or-attributes-required": "Alarmvelden of tijdreeksen/attributen van entiteiten zijn vereist.", + "maximum-timeseries-or-attributes": "Maximaal { count, plural, =1 {1 timeseries/attribute is allowed.} andere {# timeseries/attributes are allowed} }", + "alarm-fields-required": "Alarmvelden zijn verplicht.", + "function-types": "Soorten functies", + "function-type": "Soort functie", + "function-types-required": "Functietypes zijn vereist.", + "alarm-keys": "Alarmgegevens toetsen", + "alarm-key": "Sleutel voor alarmgegevens", + "alarm-key-functions": "Functies van de alarmtoets", + "alarm-key-function": "Alarmtoets functie", + "latest-keys": "Nieuwste gegevenssleutels", + "latest-key": "Meest recente gegevenssleutel", + "latest-key-functions": "Nieuwste sleutelfuncties", + "latest-key-function": "Nieuwste toetsfunctie", + "timeseries-keys": "Gegevenssleutels voor tijdreeksen", + "timeseries-key": "Gegevenssleutel tijdreeksen", + "timeseries-key-functions": "Timeseries belangrijkste functies", + "timeseries-key-function": "Tijdreeks-sleutelfunctie", + "maximum-function-types": "Maximaal { count, plural, =1 {1 function type is allowed.} andere {# function types are allowed} }", + "time-description": "tijdstempel van de huidige waarde;", + "value-description": "de huidige waarde;", + "prev-value-description": "resultaat van de vorige functieaanroep;", + "time-prev-description": "tijdstempel van de vorige waarde;", + "prev-orig-value-description": "oorspronkelijke vorige waarde;", + "aggregation": "Aggregatie", + "aggregation-type-hint-common": "Om prestatieredenen is de berekening van de geaggregeerde waarden alleen beschikbaar voor vaste tijdsintervallen zoals 'huidige dag', 'huidige maand', enz., en niet voor schuifvensterintervallen zoals 'laatste 30 minuten' of 'laatste 24 uur'.", + "aggregation-type-none-hint": "Neem de laatste waarde.", + "aggregation-type-min-hint": "Zoek de minimumwaarde tussen gegevenspunten binnen een geselecteerd tijdvenster.", + "aggregation-type-max-hint": "Zoek de maximale waarde tussen gegevenspunten binnen een geselecteerd tijdvenster.", + "aggregation-type-avg-hint": "Bereken een gemiddelde waarde tussen gegevenspunten binnen een geselecteerd tijdvenster.", + "aggregation-type-sum-hint": "Tel alle waarden van de gegevenspunten binnen een geselecteerd tijdvenster bij elkaar op.", + "aggregation-type-count-hint": "Het totale aantal gegevenspunten binnen een geselecteerd tijdvenster.", + "delta-calculation": "Delta-berekening", + "enable-delta-calculation": "Deltaberekening inschakelen", + "enable-delta-calculation-hint": "Als deze optie is ingeschakeld, wordt de waarde van de gegevenssleutel berekend op basis van de geaggregeerde waarden voor een geselecteerd tijdvenster en een opgegeven vergelijkingsperiode. Om prestatieredenen is de deltaberekening alleen beschikbaar voor historische tijdvensters en niet voor realtimewaarden. U kunt bijvoorbeeld de delta berekenen tussen het energieverbruik van gisteren ten opzichte van het energieverbruik van eergisteren.", + "delta-calculation-result": "Resultaat van de deltaberekening", + "delta-calculation-result-previous-value": "Vorige waarde", + "delta-calculation-result-delta-absolute": "Delta (absoluut)", + "delta-calculation-result-delta-percent": "Delta (procent)" + }, + "datasource": { + "type": "Type gegevensbron", + "name": "Naam", + "label": "Etiket", + "add-datasource-prompt": "Voeg gegevensbron toe" + }, + "details": { + "details": "Details", + "edit-mode": "Modus bewerken", + "edit-json": "JSON bewerken", + "toggle-edit-mode": "Bewerkingsmodus in-/uitschakelen" + }, + "device": { + "all": "Alle", + "all-devices": "Alle Devices", + "groups": "Groepen", + "shared": "Gedeeld", + "device": "Device", + "device-required": "Device is vereist.", + "devices": "Devices", + "management": "Device beheer", + "view-devices": "Devices bekijken", + "device-alias": "Alias van het device", + "device-type-max-length": "Device type moet kleiner zijn dan 256 tekens", + "aliases": "Aliassen van Devices", + "no-alias-matching": "'{{alias}}' niet 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}}'.
Apparaataliassen moeten uniek zijn binnen het dashboard.", + "configure-alias": "Configureer de alias '{{alias}}'", + "no-devices-matching": "Er zijn geen devices gevonden die overeenkomen met '{{entity}}'.", + "alias": "Alias", + "alias-required": "Device alias is vereist.", + "remove-alias": "Device alias verwijderen", + "add-alias": "Device alias toevoegen", + "name-starts-with": "Expressie van device naam", + "help-text": "Gebruik '%' naar behoefte: '%device_name_contains%', '%device_name_ends', 'device_starts_with'.", + "device-list": "Lijst met Devices", + "use-device-name-filter": "Filter gebruiken", + "device-list-empty": "Geen devices geselecteerd.", + "device-name-filter-required": "Apparaatnaamfilter is vereist.", + "device-name-filter-no-device-matched": "Er zijn geen devices gevonden die beginnen met '{{device}}'.", + "add": "Device toevoegen", + "assign-to-customer": "Toewijzen aan klant", + "assign-device-to-customer": "Device(en) toewijzen aan klant", + "assign-device-to-customer-text": "Selecteer de devices die u aan de klant wilt toewijzen", + "make-public": "Device openbaar maken", + "make-private": "Device privé maken", + "no-devices-text": "Geen devices gevonden", + "assign-to-customer-text": "Selecteer de klant om het/het device(en) toe te wijzen", + "device-details": "Gegevens van het device", + "add-device-text": "Nieuw device toevoegen", + "credentials": "Geloofsbrief", + "manage-credentials": "Inloggegevens beheren", + "delete": "Device verwijderen", + "assign-devices": "Devices toewijzen", + "assign-devices-text": "Wijs { count, plural, =1 {1 device} andere {# devices} } toe aan de klant", + "delete-devices": "Devices verwijderen", + "unassign-from-customer": "Toewijzing van klant ongedaan maken", + "unassign-devices": "Toewijzing van devices ongedaan maken", + "unassign-devices-action-title": "Toewijzing { count, plural, =1 {1 device} andere {# devices} } van klant ongedaan maken", + "unassign-device-from-edge-title": "Weet u zeker dat u de toewijzing van het device '{{deviceName}}' wilt opheffen?", + "unassign-device-from-edge-text": "Na de bevestiging wordt de toewijzing van het device ongedaan gemaakt en is het niet toegankelijk via de edge.", + "unassign-devices-from-edge": "Toewijzing van devices aan de edge ongedaan maken", + "assign-new-device": "Nieuw device toewijzen", + "make-public-device-title": "Weet je zeker dat je het device '{{deviceName}}' openbaar wilt maken?", + "make-public-device-text": "Na de bevestiging worden het device en al zijn gegevens openbaar gemaakt en toegankelijk gemaakt voor anderen.", + "make-private-device-title": "Weet je zeker dat je het device '{{deviceName}}' privé wilt maken?", + "make-private-device-text": "Na de bevestiging worden het device en al zijn gegevens privé gemaakt en zijn ze niet toegankelijk voor anderen.", + "view-credentials": "Inloggegevens bekijken", + "delete-device-title": "Weet u zeker dat u de '{{deviceName}}' van het device wilt verwijderen?", + "delete-device-text": "Opgelet, na de bevestiging worden het device en alle gerelateerde gegevens onherstelbaar.", + "delete-devices-title": "Weet u zeker dat u { count, plural, =1 {1 device} andere {# devices} } wilt verwijderen?", + "delete-devices-action-title": "Verwijder { count, plural, =1 {1 device} andere {# devices} }", + "delete-devices-text": "Opgelet, na de bevestiging worden alle geselecteerde devices verwijderd en kunnen alle gerelateerde gegevens niet meer worden hersteld.", + "unassign-device-title": "Weet u zeker dat u de toewijzing van het device '{{deviceName}}' wilt opheffen?", + "unassign-device-text": "Na de bevestiging wordt de toewijzing van het device ongedaan gemaakt en is het niet toegankelijk voor de klant.", + "unassign-device": "Toewijzing van device ongedaan maken", + "unassign-devices-title": "Weet u zeker dat u de toewijzing van { count, plural, =1 {1 device} andere {# devices} } wilt opheffen?", + "unassign-devices-text": "Na de bevestiging worden alle geselecteerde devices ongedaan gemaakt en zijn ze niet toegankelijk voor de klant.", + "device-credentials": "Inloggegevens van het device", + "loading-device-credentials": "Devicereferenties worden geladen...", + "credentials-type": "Type referenties", + "access-token": "Toegang token", + "access-token-required": "Toegangstoken is vereist.", + "access-token-invalid": "De lengte van het toegangstoken moet tussen de 1 en 32 tekens zijn.", + "certificate-pem-format": "Certificaat in PEM-formaat", + "certificate-pem-format-required": "Certificaat is vereist.", + "copy-access-token": "Toegangstoken kopiëren", + "copy-certificate": "Kopie certificaat", + "copy-client-id": "Client-ID kopiëren", + "copy-user-name": "Gebruikersnaam kopiëren", + "copy-password": "Kopieer wachtwoord", + "generate-client-id": "Client-ID genereren", + "generate-user-name": "Gebruikersnaam genereren", + "generate-password": "Wachtwoord genereren", + "generate-access-token": "Toegangstoken genereren", + "lwm2m-security-config": { + "identity": "Identiteit van de klant", + "identity-required": "Clientidentiteit is vereist.", + "identity-tooltip": "De PSK-identifier is een willekeurige PSK-identifier van maximaal 128 bytes, zoals beschreven in de standaard [RFC7925].\nDe PSK-id MOET eerst worden geconverteerd naar een tekenreeks en vervolgens worden gecodeerd in octetten met behulp van UTF-8.", + "client-key": "Client-sleutel", + "client-key-required": "Clientsleutel is vereist.", + "client-key-tooltip-prk": "RPK openbare sleutel of id moet in de standaard [RFC7250] en gecodeerd zijn naar Base64-indeling!", + "client-key-tooltip-psk": "PSK-sleutel moet in het standaard [RFC4279] en HexDec-formaat zijn: 32, 64, 128 tekens!", + "endpoint": "Naam van endpoint", + "endpoint-required": "De naam van de endpoint is vereist.", + "client-public-key": "Openbare sleutel van client", + "client-public-key-hint": "Als de openbare sleutel van de client leeg is, wordt het vertrouwde certificaat gebruikt", + "client-public-key-tooltip": "De openbare sleutel X509 moet in DER-gecodeerd X509v3-formaat zijn en uitsluitend het EC-algoritme ondersteunen en vervolgens worden gecodeerd naar het Base64-formaat!", + "mode": "Beveiligingsconfiguratiemodus", + "client-tab": "Configuratie voor clientbeveiliging", + "client-certificate": "Certificaat van de klant", + "bootstrap-tab": "Bootstrap-client", + "bootstrap-server": "Bootstrap-server", + "lwm2m-server": "LwM2M-server", + "client-publicKey-or-id": "Openbare sleutel of id van de client", + "client-publicKey-or-id-required": "De openbare sleutel of id van de client is vereist.", + "client-publicKey-or-id-tooltip-psk": "De PSK-identifier is een willekeurige PSK-identifier van maximaal 128 bytes, zoals beschreven in de standaard [RFC7925].\nDe PSK-id MOET eerst worden geconverteerd naar een tekenreeks en vervolgens worden gecodeerd in octetten met behulp van UTF-8.", + "client-publicKey-or-id-tooltip-rpk": "RPK openbare sleutel of id moet in de standaard [RFC7250] en gecodeerd zijn naar Base64-indeling!", + "client-publicKey-or-id-tooltip-x509": "De openbare X509-sleutel moet in DER-gecodeerd X509v3-formaat zijn en uitsluitend het EC-algoritme ondersteunen en vervolgens worden gecodeerd in Base64-indeling", + "client-secret-key": "Geheime sleutel van de client", + "client-secret-key-required": "Client Secret Key is vereist.", + "client-secret-key-tooltip-psk": "PSK-sleutel moet in het standaard [RFC4279] en HexDec-formaat zijn: 32, 64, 128 tekens!", + "client-secret-key-tooltip-prk": "De geheime RPK-sleutel moet in PKCS_8 formaat zijn (DER-codering, standaard [RFC5958]) en vervolgens worden gecodeerd in Base64-formaat!", + "client-secret-key-tooltip-x509": "De geheime sleutel X509 moet in PKCS_8 formaat zijn (DER-codering, standaard [RFC5958]) en vervolgens worden gecodeerd in Base64-formaat!" + }, + "client-id": "Client-ID", + "client-id-pattern": "Bevat een ongeldig teken.", + "user-name": "Gebruikersnaam", + "user-name-required": "Gebruikersnaam is vereist.", + "client-id-or-user-name-necessary": "Client-ID en/of gebruikersnaam zijn noodzakelijk", + "password": "Wachtwoord", + "secret": "Geheim", + "secret-required": "Geheim is vereist.", + "device-type": "Device type", + "device-type-required": "Device type is vereist.", + "select-device-type": "Selecteer device type", + "enter-device-type": "Voer het device type in", + "any-device": "Elk device", + "no-device-types-matching": "Er zijn geen device typen gevonden die overeenkomen met '{{entitySubtype}}'.", + "device-type-list-empty": "Geen device typen geselecteerd.", + "device-types": "Device sorrten", + "name": "Naam", + "name-required": "Naam is verplicht.", + "name-max-length": "Naam moet kleiner zijn dan 256 tekens tekens", + "label-max-length": "Etiket moet kleiner zijn dan 256 tekens tekens", + "description": "Omschrijving: __________", + "label": "Etiket", + "events": "Events", + "details": "Details", + "copyId": "Device-ID kopiëren", + "copyAccessToken": "Toegangstoken kopiëren", + "copy-mqtt-authentication": "MQTT-inloggegevens kopiëren", + "idCopiedMessage": "Device-ID is gekopieerd naar klembord", + "accessTokenCopiedMessage": "Token voor apparaattoegang is gekopieerd naar het klembord", + "mqtt-authentication-copied-message": "MQTT-verificatie van device is gekopieerd naar klembord", + "assignedToCustomer": "Toegewezen aan klant", + "unable-delete-device-alias-title": "Kan apparaatalias niet verwijderen", + "unable-delete-device-alias-text": "Device alias '{{deviceAlias}}' kan niet worden verwijderd omdat deze wordt gebruikt door de volgende widget(s):
{{widgetsList}}", + "is-gateway": "Is gateway", + "overwrite-activity-time": "Activiteitstijd overschrijven voor verbonden device", + "device-filter": "Device filter", + "device-filter-title": "Device filter", + "filter-title": "Filter", + "device-state": "Status van het device", + "state": "Staat", + "any": "Enig", + "active": "Actief", + "inactive": "Inactief", + "public": "Publiek", + "device-public": "Device is openbaar", + "select-device": "Selecteer device", + "select-group-to-add": "Selecteer de doelgroep om geselecteerde devices toe te voegen", + "select-group-to-move": "Selecteer de doelgroep om geselecteerde devices te verplaatsen", + "remove-devices-from-group": "Weet je zeker dat je { count, plural, =1 {1 device} andere {# devices} } uit groep '{{entityGroup}}' wilt verwijderen?", + "group": "Device groep", + "list-of-groups": "{ count, plural, =1 {One device group} andere {List of # device groups} }", + "group-name-starts-with": "Asset groepen waarvan de naam begint met '{{prefix}}'", + "import": "Device importeren", + "device-file": "Device bestand", + "search": "Devices zoeken", + "selected-devices": "{ count, plural, =1 {1 device} andere {# devices} } geselecteerd", + "device-configuration": "Configuratie van het device", + "transport-configuration": "Configuratie van het transport", + "wizard": { + "device-wizard": "Device Wizard", + "device-details": "Gegevens van het device", + "new-device-profile": "Nieuw device profiel maken", + "existing-device-profile": "Bestaand device profiel selecteren", + "specific-configuration": "Specifieke configuratie", + "customer-to-assign-device": "Klant om het device toe te wijzen", + "add-credentials": "Inloggegevens toevoegen" + }, + "unassign-devices-from-edge-title": "Weet u zeker dat u de toewijzing van { count, plural, =1 {1 device} andere {# devices} } wilt opheffen?", + "unassign-devices-from-edge-text": "Na de bevestiging worden alle geselecteerde devices ongedaan gemaakt en zijn ze niet toegankelijk via de edge." + }, + "asset-profile": { + "asset-profile": "Asset profiel", + "asset-profiles": "Asset profielen", + "all-asset-profiles": "Alle", + "add": "Asset profiel toevoegen", + "edit": "Asset profiel bewerken", + "asset-profile-details": "Details van de asset profiel", + "no-asset-profiles-text": "Geen assetprofielen gevonden", + "search": "Assetprofielen zoeken", + "selected-asset-profiles": "{ count, plural, =1 {1 asset profile} andere {# asset profiles} } geselecteerd", + "no-asset-profiles-matching": "Er zijn geen asset profielen gevonden die overeenkomen met '{{entity}}'.", + "asset-profile-required": "Asset profiel is vereist", + "idCopiedMessage": "De ID van het itemprofiel is gekopieerd naar het klembord", + "set-default": "Itemprofiel instellen als standaard", + "delete": "Asset profiel verwijderen", + "copyId": "Itemprofiel-ID kopiëren", + "name-max-length": "Naam moet kleiner zijn dan 256 tekens", + "new-device-profile-name": "Naam van itemprofiel", + "new-device-profile-name-required": "De naam van de asset profiel is vereist.", + "name": "Naam", + "name-required": "Naam is verplicht.", + "image": "Afbeelding van assetprofiel", + "description": "Omschrijving: __________", + "default": "Verstek", + "default-rule-chain": "Keten van standaardregels", + "default-edge-rule-chain": "Standaard rule chain", + "default-edge-rule-chain-hint": "Wordt aan de edge gebruikt als rule chain om inkomende gegevens voor asset van dit asset profiel te verwerken", + "mobile-dashboard": "Mobiel dashboard", + "mobile-dashboard-hint": "Gebruikt door mobiele applicatie als dashboard met activagegevens", + "select-queue-hint": "Maak een keuze uit een vervolgkeuzelijst.", + "delete-asset-profile-title": "Weet je zeker dat je de asset profiel '{{assetProfileName}}' wilt verwijderen?", + "delete-asset-profile-text": "Let op, na de bevestiging worden de asset profiel en alle gerelateerde gegevens onherstelbaar.", + "delete-asset-profiles-title": "Weet u zeker dat u { count, plural, =1 {1 asset profile} andere {# asset profiles} } wilt verwijderen?", + "delete-asset-profiles-text": "Opgelet, na de bevestiging worden alle geselecteerde asset profielen verwijderd en worden alle gerelateerde gegevens onherstelbaar.", + "set-default-asset-profile-title": "Weet u zeker dat u de asset profiel standaard op '{{assetProfileName}}' wilt zetten?", + "set-default-asset-profile-text": "Na de bevestiging wordt de asset profiel gemarkeerd als standaard en wordt het gebruikt voor nieuwe asset waarvoor geen profiel is opgegeven.", + "no-asset-profiles-found": "Geen assetprofielen gevonden.", + "create-new-asset-profile": "Maak een nieuwe aan!", + "create-asset-profile": "Nieuw asset profiel maken", + "import": "Asset profiel importeren", + "export": "Asset profiel exporteren", + "export-failed-error": "Kan itemprofiel niet exporteren: {{error}}", + "asset-profile-file": "Asset profiel bestand", + "invalid-asset-profile-file-error": "Kan itemprofiel niet importeren: Ongeldige gegevensstructuur van asset profiel." + }, + "device-profile": { + "device-profile": "Device profiel", + "device-profiles": "Device profielen", + "all-device-profiles": "Alle", + "add": "Device profiel toevoegen", + "edit": "Device profiel bewerken", + "device-profile-details": "Details van device profiel", + "no-device-profiles-text": "Geen device profielen gevonden", + "search": "Device profielen zoeken", + "selected-device-profiles": "{ count, plural, =1 {1 device profile} andere {# device profiles} } geselecteerd", + "no-device-profiles-matching": "Er zijn geen device profielen gevonden die overeenkomen met '{{entity}}'.", + "device-profile-required": "Device profiel is vereist", + "idCopiedMessage": "Device profiel-ID is gekopieerd naar klembord", + "set-default": "Device profiel standaard instellen", + "delete": "Device profiel verwijderen", + "copyId": "Device profiel-ID kopiëren", + "name-max-length": "Naam moet kleiner zijn dan 256 tekens tekens", + "new-device-profile-name": "Profielnaam device", + "new-device-profile-name-required": "De naam van het device profiel is vereist.", + "name": "Naam", + "name-required": "Naam is verplicht.", + "type": "Type profiel", + "type-required": "Profieltype is vereist.", + "type-default": "Verstek", + "image": "Profielafbeelding van device", + "transport-type": "Soort vervoer", + "transport-type-required": "Transporttype is vereist.", + "transport-type-default": "Verstek", + "transport-type-default-hint": "Ondersteunt standaard MQTT-, HTTP- en CoAP-transport", + "transport-type-mqtt": "MQTT", + "transport-type-mqtt-hint": "Maakt geavanceerde MQTT-transportinstellingen mogelijk", + "transport-type-coap": "CoAP", + "transport-type-coap-hint": "Maakt geavanceerde CoAP-transportinstellingen mogelijk", + "transport-type-lwm2m": "LWM2M", + "transport-type-lwm2m-hint": "LWM2M transporttype", + "transport-type-snmp": "SNMP", + "transport-type-snmp-hint": "SNMP-transportconfiguratie opgeven", + "description": "Omschrijving: __________", + "default": "Verstek", + "profile-configuration": "Profiel configuratie", + "transport-configuration": "Configuratie van het transport", + "default-rule-chain": "Standaard rule chain", + "default-edge-rule-chain": "Standaard edge rule chain", + "default-edge-rule-chain-hint": "Wordt aan de edge rule chain om inkomende gegevens te verwerken voor devices met dit device profiel", + "mobile-dashboard": "Mobiel dashboard", + "mobile-dashboard-hint": "Gebruikt door mobiele applicatie als dashboard met device details", + "select-queue-hint": "Maak een keuze uit een vervolgkeuzelijst.", + "delete-device-profile-title": "Weet u zeker dat u het device profiel '{{deviceProfileName}}' wilt verwijderen?", + "delete-device-profile-text": "Opgelet, na de bevestiging worden het device profiel en alle gerelateerde gegevens, inclusief bijbehorende OTA-updates, onherstelbaar.", + "delete-device-profiles-title": "Weet u zeker dat u { count, plural, =1 {1 device profile} andere {# device profiles} } wilt verwijderen?", + "delete-device-profiles-text": "Opgelet, na de bevestiging worden alle geselecteerde device profielen verwijderd en kunnen alle gerelateerde gegevens, inclusief bijbehorende OTA-updates, niet meer worden hersteld.", + "set-default-device-profile-title": "Weet u zeker dat u het device profiel standaard '{{deviceProfileName}}' wilt maken?", + "set-default-device-profile-text": "Na de bevestiging wordt het device profiel als standaard gemarkeerd en wordt het gebruikt voor nieuwe devices waarvoor geen profiel is opgegeven.", + "no-device-profiles-found": "Geen device profielen gevonden.", + "create-new-device-profile": "Maak een nieuwe aan!", + "mqtt-device-topic-filters": "Onderwerpfilters voor MQTT-Devices", + "mqtt-device-topic-filters-unique": "Onderwerpfilters voor MQTT-Devices moeten uniek zijn.", + "mqtt-device-topic-filters-spark-plug": "MQTT Bougie B Edge van het netwerk (EoN) knooppunt.", + "mqtt-device-topic-filters-spark-plug-hint": "Sta verbindingen toe vanaf EoN-rule nodes met Sparkplug B-payload en onderwerpindeling.", + "mqtt-device-topic-filters-spark-plug-attribute-metric-names": "SparkPlug-statistieken om op te slaan als attributen.", + "mqtt-device-topic-filters-spark-plug-attribute-metric-names-hint": "Namen van SparkPlug-statistieken die worden opgeslagen als device attributen. Alle andere metrische gegevens worden opgeslagen als device telemetrie.", + "mqtt-device-payload-type": "Nuttige waarde van het MQTT-device", + "mqtt-device-payload-type-json": "JSON", + "mqtt-device-payload-type-proto": "Protobuf", + "mqtt-enable-compatibility-with-json-payload-format": "Schakel compatibiliteit met andere payload-indelingen in.", + "mqtt-enable-compatibility-with-json-payload-format-hint": "Indien ingeschakeld, gebruikt het platform standaard een Protobuf payload-indeling. Als parsen mislukt, probeert het platform de JSON-payloadindeling te gebruiken. Handig voor achterwaartse compatibiliteit tijdens firmware-updates. De eerste release van de firmware gebruikt bijvoorbeeld Json, terwijl de nieuwe release Protobuf gebruikt. Tijdens het proces van firmware-update voor de vloot van devices, is het vereist om zowel Protobuf als JSON tegelijkertijd te ondersteunen. De compatibiliteitsmodus introduceert een lichte prestatievermindering, dus het wordt aanbevolen om deze modus uit te schakelen zodra alle devices zijn bijgewerkt.", + "mqtt-use-json-format-for-default-downlink-topics": "Json-indeling gebruiken voor standaard downlink-onderwerpen", + "mqtt-use-json-format-for-default-downlink-topics-hint": "Indien ingeschakeld, gebruikt het platform de Json-payloadindeling om attributen en RPC te pushen 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 kenmerk- en rpc-abonnementen die worden verzonden met behulp van nieuwe (v2) onderwerpen: v2/a/res/$request_id, v2/a, v2/r/req/$request_id, v2/r/res/$request_id. Waarbij $request_id een id van een geheel getal is.", + "mqtt-send-ack-on-validation-exception": "PUBACK verzenden bij mislukte validatie van PUBLISH-bericht", + "mqtt-send-ack-on-validation-exception-hint": "Standaard sluit het platform de MQTT-sessie bij mislukte berichtvalidatie. Indien ingeschakeld, stuurt het platform een publicatiebevestiging in plaats van de sessie te sluiten.", + "snmp-add-mapping": "SNMP-toewijzing toevoegen", + "snmp-mapping-not-configured": "Geen toewijzing voor OID aan tijdreeks/telemetrie geconfigureerd", + "snmp-timseries-or-attribute-name": "Tijdreeks-/kenmerknaam voor toewijzing", + "snmp-timseries-or-attribute-type": "Tijdreeks/kenmerktype voor toewijzing", + "snmp-method-pdu-type-get-request": "GetRequest (GetAanvraag)", + "snmp-method-pdu-type-get-next-request": "VolgendeAanvraag", + "snmp-oid": "OID", + "transport-device-payload-type-json": "JSON", + "transport-device-payload-type-proto": "Protobuf", + "mqtt-payload-type-required": "Payload-type is vereist.", + "coap-device-type": "Type CoAP-device", + "coap-device-payload-type": "Nuttige lading van CoAP-device", + "coap-device-type-required": "Het type CoAP-device is vereist.", + "coap-device-type-default": "Verstek", + "coap-device-type-efento": "Efento NB-IoT", + "support-level-wildcards": "Enkele [+] en multi-level [#] jokertekens worden ondersteund.", + "telemetry-topic-filter": "Onderwerpfilter voor telemetrie", + "telemetry-topic-filter-required": "Telemetrie-onderwerpfilter is vereist.", + "attributes-topic-filter": "Attributen topic filter", + "attributes-subscribe-topic-filter": "Attributen topic subscribe filter", + "attributes-topic-filter-required": "Attributen topic filter is vereist.", + "attributes-subscribe-topic-filter-required": "Attributen topic subscribe is vereist", + "telemetry-proto-schema": "Telemetrie proto-schema", + "telemetry-proto-schema-required": "Telemetrie proto-schema is vereist.", + "attributes-proto-schema": "Attributen proto-schema", + "attributes-proto-schema-required": "Attributen proto-schema is vereist.", + "rpc-response-proto-schema": "RPC-respons proto-schema", + "rpc-response-proto-schema-required": "RPC-respons proto-schema is vereist.", + "rpc-response-topic-filter": "Onderwerpfilter voor RPC-reacties", + "rpc-response-topic-filter-required": "RPC-responsonderwerpfilter is vereist.", + "rpc-request-proto-schema": "RPC-aanvraag proto-schema", + "rpc-request-proto-schema-required": "RPC-aanvraag proto-schema is vereist.", + "rpc-request-proto-schema-hint": "RPC-aanvraagbericht moet altijd velden bevatten: tekenreeksmethode = 1; int32 requestId = 2; en params = 3 van elk gegevenstype.", + "not-valid-pattern-topic-filter": "Ongeldig topic pattern filter", + "not-valid-single-character": "Ongeldig gebruik van een jokerteken op één niveau", + "not-valid-multi-character": "Ongeldig gebruik van een jokerteken met meerdere niveaus", + "single-level-wildcards-hint": "[+] is geschikt voor elk topic filter niveau. Bijv.: v1/devices/+/telemetry of +/devices/+/attributen.", + "multi-level-wildcards-hint": "[#] kan de topic filter zelf vervangen en moet het laatste symbool van de topic zijn. Bijv.: # of v1/Devices/ik/#.", + "alarm-rules": "Alarm regels", + "alarm-rules-with-count": "Alarmregels ({{count}})", + "no-alarm-rules": "Geen alarmregels geconfigureerd", + "add-alarm-rule": "Alarmregel toevoegen", + "edit-alarm-rule": "Alarmregel bewerken", + "alarm-type": "Soort alarm", + "alarm-type-required": "Alarmtype is vereist.", + "alarm-type-unique": "Het alarmtype moet uniek zijn binnen de alarmregels van het device profiel.", + "alarm-type-max-length": "Alarmtype moet kleiner zijn dan 256 tekens tekens", + "create-alarm-pattern": "Creëer {{alarmType}} alarm", + "create-alarm-rules": "Alarmregels maken", + "no-create-alarm-rules": "Geen voorwaarden voor het creëren van alarmen+ geconfigureerd", + "add-create-alarm-rule-prompt": "Voeg een alarmregel toe", + "clear-alarm-rule": "Duidelijke alarmregel", + "no-clear-alarm-rule": "Geen duidelijke voorwaarde geconfigureerd", + "add-create-alarm-rule": "Voorwaarde voor maken toevoegen", + "add-clear-alarm-rule": "Duidelijke voorwaarde toevoegen", + "select-alarm-severity": "Selecteer de ernst van het alarm", + "alarm-severity-required": "De ernst van het alarm is vereist.", + "condition-duration": "Duur van de conditie", + "condition-duration-value": "Duur waarde", + "condition-duration-time-unit": "Tijdseenheid", + "condition-duration-value-range": "De duurwaarde moet tussen 1 en 2147483647 liggen.", + "condition-duration-value-pattern": "De waarde van de duur moet gehele getallen zijn.", + "condition-duration-value-required": "Duurwaarde is vereist.", + "condition-duration-time-unit-required": "Tijdseenheid is vereist.", + "advanced-settings": "Geavanceerde instellingen", + "alarm-rule-details": "Details", + "alarm-rule-details-hint": "Tip: gebruik ${keyName} om waarden van de attribuut- of telemetriesleutels te vervangen die worden gebruikt in de alarmregelvoorwaarde.", + "add-alarm-rule-details": "Voeg details toe", + "alarm-rule-mobile-dashboard": "Mobiel dashboard", + "alarm-rule-mobile-dashboard-hint": "Gebruikt door mobiele applicatie als dashboard met alarmdetails", + "alarm-rule-no-mobile-dashboard": "Geen dashboard geselecteerd", + "propagate-alarm": "Alarm doorgeven aan verwante entiteiten", + "alarm-rule-relation-types-list": "Relatietypen die moeten worden gepropageerd", + "alarm-rule-relation-types-list-hint": "Als Relatietypen doorgeven niet is geselecteerd, worden alarmen doorgegeven zonder te filteren op relatietype.", + "propagate-alarm-to-owner": "Alarm doorgeven aan entiteitseigenaar (klant of tenant)", + "propagate-alarm-to-owner-hierarchy": "Alarm doorgeven aan de hiërarchie van entiteitseigenaren", + "propagate-alarm-to-tenant": "Alarm doorgeven aan tenant", + "alarm-details": "Details van het alarm", + "alarm-rule-condition": "Voorwaarde van de alarmregel", + "enter-alarm-rule-condition-prompt": "Voeg de voorwaarde van de alarmregel toe", + "edit-alarm-rule-condition": "Voorwaarde van de alarmregel bewerken", + "device-provisioning": "Inrichting van Devices", + "provision-strategy": "Provisioning-strategie", + "provision-strategy-required": "Provisioning-strategie is vereist.", + "provision-strategy-disabled": "Provisioning-strategie uitgeschakeld ", + "provision-strategy-created-new": "Toestaan om nieuwe provisioning-strategie aan te maken", + "provision-strategy-check-pre-provisioned": "Controleren op vooraf geprovisioneerde devices", + "provision-device-key": "Provision device sleutel", + "provision-device-key-required": "Provision device sleutel is vereist.", + "copy-provision-key": "Provisioningsleutel kopiëren", + "provision-key-copied-message": "Provisioningsleutel is gekopieerd naar klembord", + "provision-device-secret": "Provion device geheim", + "provision-device-secret-required": "Provision device geheim is vereist.", + "copy-provision-secret": "Provisioning geheim kopiëren", + "provision-secret-copied-message": "Provisioningsgeheim is gekopieerd naar klembord", + "provision-strategy-x509": { + "certificate-chain": "X509 Certificaten Keten", + "certificate-chain-hint": "De X.509-certificatenstrategie wordt gebruikt om devices in te richten op clientcertificaten in tweerichtings-TLS-communicatie.", + "allow-create-new-devices": "Nieuwe devices maken", + "allow-create-new-devices-hint": "Indien geselecteerd, worden nieuwe devices gemaakt en wordt het clientcertificaat gebruikt als apparaatreferenties.", + "certificate-value": "Certificaat in PEM-formaat", + "certificate-value-required": "Certificaat in PEM-formaat is vereist", + "cn-regex-variable": "CN Reguliere expressie variabele", + "cn-regex-variable-required": "CN Regular Expression variabele is vereist", + "cn-regex-variable-hint": "Vereist om de device naam op te halen uit de algemene naam van het X509-certificaat van het device." + }, + "condition": "Conditie", + "condition-type": "Conditie type", + "condition-type-simple": "Eenvoudig", + "condition-type-duration": "Duur", + "condition-during": "Tijdens {{during}}", + "condition-during-dynamic": "Tijdens \"{{ attribute }}\" ({{during}})", + "condition-type-repeating": "Herhalende", + "condition-type-required": "Conditietype is vereist.", + "condition-repeating-value": "Aantal gebeurtenissen", + "condition-repeating-value-range": "Het aantal gebeurtenissen moet tussen 1 en 2147483647 liggen.", + "condition-repeating-value-pattern": "Het aantal gebeurtenissen moet gehele getallen zijn.", + "condition-repeating-value-required": "Het aantal gebeurtenissen is vereist.", + "condition-repeat-times": "Herhalingen { count, plural, =1 {1 time} andere {# times} }", + "condition-repeat-times-dynamic": "Herhaalt \"{ attribute }\" ({ count, plural, =1 {1 time} andere {# times} })", + "schedule-type": "Type planner", + "schedule-type-required": "Het type planner is vereist.", + "schedule": "Rooster", + "edit-schedule": "Alarmschema bewerken", + "schedule-any-time": "Altijd actief", + "schedule-specific-time": "Actief op een bepaald tijdstip", + "schedule-custom": "Gewoonte", + "schedule-day": { + "monday": "Maandag", + "tuesday": "Dinsdag", + "wednesday": "Woensdag", + "thursday": "Donderdag", + "friday": "Vrijdag", + "saturday": "Zaterdag", + "sunday": "Zondag" + }, + "schedule-days": "Dagen", + "schedule-time": "Tijd", + "schedule-time-from": "Van", + "schedule-time-to": "Aan", + "schedule-days-of-week-required": "Er moet ten minste één dag van de week worden geselecteerd.", + "create-device-profile": "Nieuw device profiel maken", + "import": "Device profiel importeren", + "export": "Device profiel exporteren", + "export-failed-error": "Device profiel kan niet worden geëxporteerd: {{error}}", + "device-profile-file": "Bestand met device profiel", + "invalid-device-profile-file-error": "Kan device profiel niet importeren: Ongeldige gegevensstructuur van het device profiel.", + "power-saving-mode": "Energiebesparende modus", + "power-saving-mode-type": { + "default": "Energiebesparende modus voor device profiel gebruiken", + "psm": "Energiebesparende modus (PSM)", + "drx": "Discontinue ontvangst (DRX)", + "edrx": "Uitgebreide discontinue ontvangst (eDRX)" + }, + "edrx-cycle": "eDRX-cyclus", + "edrx-cycle-required": "eDRX-cyclus is vereist.", + "edrx-cycle-pattern": "De eDRX-cyclus moet een positief geheel getal zijn.", + "edrx-cycle-min": "Het minimale aantal eDRX-cycli is {{ min }} seconden.", + "paging-transmission-window": "Transmissievenster voor oproepen", + "paging-transmission-window-required": "Oproeptransmissievenster is vereist.", + "paging-transmission-window-pattern": "Het zendvenster van de paging-transmissie moet een positief geheel getal zijn.", + "paging-transmission-window-min": "Het minimale aantal paging-transmissievensters is {{ min }} seconden.", + "psm-activity-timer": "PSM-activiteitstimer", + "psm-activity-timer-required": "PSM-activiteitstimer is vereist.", + "psm-activity-timer-pattern": "PSM-activiteitstimer moet een positief geheel getal zijn.", + "psm-activity-timer-min": "Het minimale aantal PSM-activiteitstimers is {{ min }} seconden.", + "lwm2m": { + "object-list": "Lijst met objecten", + "object-list-empty": "Geen objecten geselecteerd.", + "no-objects-found": "Geen objecten gevonden.", + "no-objects-matching": "Er zijn geen objecten gevonden die overeenkomen met '{{object}}'.", + "model-tab": "LWM2M Model", + "add-new-instances": "Nieuwe instanties toevoegen", + "instances-list": "Lijst met instanties", + "instances-list-required": "Een lijst met instanties is vereist.", + "instance-id-pattern": "Instantie-id moet een positief geheel getal zijn.", + "instance-id-max": "Maximale exemplaar-id-waarde {{max}}.", + "instance": "Voorbeeld", + "resource-label": "#ID Naam van de bron", + "observe-label": "Waarnemen", + "attribute-label": "Attribuut", + "telemetry-label": "Telemetrie", + "edit-observe-select": "Telemetrie of attribuut bewerken om te bewerken, te observeren", + "edit-attributes-select": "Als u attributen wilt bewerken, selecteert u telemetrie of kenmerk", + "no-attributes-set": "Geen attributen ingesteld", + "key-name": "Naam van de sleutel", + "key-name-required": "Sleutelnaam is vereist", + "attribute-name": "Naam attribuut", + "attribute-name-required": "Naamattribuut is vereist.", + "attribute-value": "Attribuutwaarde", + "attribute-value-required": "Kenmerkwaarde is vereist.", + "attribute-value-pattern": "De kenmerkwaarde moet een positief geheel getal zijn.", + "edit-attributes": "Attributen bewerken: {{ name }}", + "view-attributes": "Bekijk attributen: {{ name }}", + "add-attribute": "Attribuut toevoegen", + "edit-attribute": "Attribuut bewerken", + "view-attribute": "Bekijk attribuut", + "remove-attribute": "Attribuut verwijderen", + "delete-server-text": "Opgelet, na de bevestiging wordt de serverconfiguratie onherstelbaar.", + "delete-server-title": "Weet je zeker dat je de server wilt verwijderen?", + "mode": "Beveiligingsconfiguratiemodus", + "bootstrap-tab": "Opstarten", + "bootstrap-server-legend": "Bootstrap-server (ShortId...)", + "lwm2m-server-legend": "LwM2M-server (ShortId...)", + "server": "Server", + "short-id": "Korte server-ID", + "short-id-tooltip": "Server-id kort Id. Wordt gebruikt als koppeling naar het Object-exemplaar van de koppeling.\nDeze id identificeert elke LwM2M-server die is geconfigureerd voor de LwM2M-client op unieke wijze.\nResource MOET worden ingesteld wanneer de Bootstrap-Server Resource een waarde van 'false' heeft.\nDe waarden ID:0 en ID:65535 mogen NIET worden gebruikt voor het identificeren van de LwM2M-server.", + "short-id-required": "Een korte server-ID is vereist.", + "short-id-range": "Korte server-ID moet tussen 1 en 65534 liggen.", + "short-id-pattern": "Korte server-ID moet een positief geheel getal zijn.", + "lifetime": "Levensduur klantregistratie", + "lifetime-required": "Levenslange registratie van klanten is vereist.", + "lifetime-pattern": "De levensduur van clientregistratie moet een positief geheel getal zijn.", + "default-min-period": "Min. periode tussen twee kennisgeving(en)", + "default-min-period-tooltip": "De standaardwaarde die de LwM2M-client moet gebruiken voor de minimale periode van een waarneming als deze parameter niet in een waarneming is opgenomen.", + "default-min-period-required": "Minimumperiode is vereist.", + "default-min-period-pattern": "De minimumperiode moet een positief geheel getal zijn.", + "notification-storing": "Melding opslaan wanneer uitgeschakeld of offline", + "binding": "Bindend", + "binding-type": { + "u": "U: Cliënt is te allen tijde bereikbaar via de UDP-binding.", + "m": "M: Opdrachtgever is te allen tijde bereikbaar via de MQTT-binding.", + "h": "H: Client is op elk moment bereikbaar via de HTTP-binding.", + "t": "T: Cliënt is te allen tijde bereikbaar via de TCP-binding.", + "s": "S: Cliënt is te allen tijde bereikbaar via de SMS-binding.", + "n": "N: Client MOET het antwoord op een dergelijk verzoek verzenden via de niet-IP-binding (wordt ondersteund sinds LWM2M 1.1).", + "uq": "UQ: UDP-verbinding in wachtrijmodus (wordt niet meer ondersteund sinds LWM2M 1.1)", + "uqs": "UQS: zowel UDP- als SMS-verbindingen actief; UDP in wachtrijmodus, SMS in standaardmodus (wordt niet ondersteund sinds LWM2M 1.1)", + "tq": "TQ: TCP-verbinding in wachtrijmodus (wordt niet meer ondersteund sinds LWM2M 1.1)", + "tqs": "TQS: zowel TCP- als SMS-verbindingen actief; TCP in wachtrijmodus, SMS in standaardmodus (wordt niet ondersteund sinds LWM2M 1.1)", + "sq": "SQ: SMS-verbinding in wachtrijmodus (wordt niet meer ondersteund sinds LWM2M 1.1)" + }, + "binding-tooltip": "Dit is de lijst in de \"bindende\" bron van het LwM2M-serverobject - /1/x/7.\nGeeft de ondersteunde bindingsmodi in de LwM2M-client aan.\nDeze waarde MOET hetzelfde zijn als de waarde in de bron \"Ondersteunde bindingen en modi\" in het apparaatobject (/3/0/16).\nHoewel meerdere transporten worden ondersteund, kan er slechts één transportbinding worden gebruikt tijdens de gehele transportsessie.\nWanneer bijvoorbeeld UDP en SMS beide worden ondersteund, kunnen de LwM2M-client en de LwM2M-server ervoor kiezen om tijdens de gehele transportsessie via UDP of sms te communiceren.", + "bootstrap-server": "Bootstrap-server", + "lwm2m-server": "LwM2M-server", + "include-bootstrap-server": "Bootstrap-serverupdates opnemen", + "bootstrap-update-title": "U hebt Bootstrap Server al geconfigureerd. Weet je zeker dat je de updates wilt uitsluiten?", + "bootstrap-update-text": "Opgelet, na de bevestiging worden de configuratiegegevens van de Bootstrap-server onherstelbaar.", + "server-host": "Server host", + "server-host-required": "Server host is vereist.", + "server-port": "Haven", + "server-port-required": "Poort is vereist.", + "server-port-pattern": "Poort moet een positief geheel getal zijn.", + "server-port-range": "De poort moet tussen 1 en 65535 liggen.", + "server-public-key": "Openbare sleutel van de server", + "server-public-key-required": "De openbare sleutel van de server is vereist.", + "client-hold-off-time": "Wacht met de tijd", + "client-hold-off-time-required": "Wachttijd is vereist.", + "client-hold-off-time-pattern": "Hold Off Time moet een positief geheel getal zijn.", + "client-hold-off-time-tooltip": "Client Hold Off Time alleen voor gebruik met een Bootstrap-Server", + "account-after-timeout": "Account na de time-out", + "account-after-timeout-required": "Account na de time-out is vereist.", + "account-after-timeout-pattern": "Account na de time-out moet een positief geheel getal zijn.", + "account-after-timeout-tooltip": "Bootstrap-Server-account na de time-outwaarde die door deze resource wordt opgegeven.", + "server-type": "Type server", + "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": "Klantstrategie bij het verbinden", + "client-strategy-label": "Strategie", + "client-strategy-only-observe": "Observeer het verzoek aan de client pas na de eerste verbinding", + "client-strategy-read-all": "Lees alle bronnen en observeer het verzoek aan de klant na registratie", + "fw-update": "Firmware-update", + "fw-update-strategy": "Strategie voor firmware-updates", + "fw-update-strategy-data": "Firmware-update pushen als binair bestand met behulp van Object 19 en Resource 0 (gegevens)", + "fw-update-strategy-package": "Firmware-update pushen als binair bestand met behulp van Object 5 en Resource 0 (pakket)", + "fw-update-strategy-package-uri": "Genereer automatisch een unieke CoAP-URL om het pakket te downloaden en de firmware-update te pushen als Object 5 en Resource 1 (pakket-URI)", + "sw-update": "Bijwerken van de software", + "sw-update-strategy": "Strategie voor software-updates", + "sw-update-strategy-package": "Binair bestand pushen met Object 9 en Resource 2 (pakket)", + "sw-update-strategy-package-uri": "Genereer automatisch een unieke CoAP-URL om het pakket te downloaden en software-update te pushen met behulp van Object 9 en Resource 3 (pakket-URI)", + "fw-update-resource": "CoAP-bron voor firmware-update", + "fw-update-resource-required": "CoAP-bron voor firmware-update is vereist.", + "sw-update-resource": "CoAP-bron voor software-update", + "sw-update-resource-required": "Software-update CoAP-bron is vereist.", + "config-json-tab": "Json Config Profile-device", + "attributes-name": { + "min-period": "Minimale periode", + "max-period": "Maximale periode", + "greater-than": "Groter dan", + "less-than": "Minder dan", + "step": "Stap", + "min-evaluation-period": "Minimale evaluatieperiode", + "max-evaluation-period": "Maximale evaluatieperiode" + }, + "composite-operations-support": "Ondersteunt samengestelde lees-/schrijf-/observatiebewerkingen" + }, + "snmp": { + "add-communication-config": "Communicatieconfiguratie toevoegen", + "add-mapping": "Toewijzing toevoegen", + "authentication-passphrase": "Wachtwoordzin voor verificatie", + "authentication-passphrase-required": "Wachtwoordzin voor verificatie is vereist.", + "authentication-protocol": "Authenticatie protocol", + "authentication-protocol-required": "Verificatieprotocol is vereist.", + "communication-configs": "Communicatie configs", + "community": "Tekenreeks van de gemeenschap", + "community-required": "Community-tekenreeks is vereist.", + "context-name": "Naam van de context", + "data-key": "Gegevenssleutel", + "data-key-required": "Gegevenssleutel is vereist.", + "data-type": "Soort gegevens", + "data-type-required": "Gegevenstype is vereist.", + "engine-id": "Motor-ID", + "host": "Server host", + "host-required": "Server host is vereist.", + "oid": "OID", + "oid-pattern": "Ongeldige OID-indeling.", + "oid-required": "OID is vereist.", + "please-add-communication-config": "Gelieve communicatieconfiguratie toe te voegen", + "please-add-mapping-config": "Voeg a.u.b. toewijzingsconfiguratie toe", + "port": "Haven", + "port-format": "Ongeldige poortindeling.", + "port-required": "Poort is vereist.", + "privacy-passphrase": "Wachtwoordzin voor privacy", + "privacy-passphrase-required": "Privacywachtwoordzin is vereist.", + "privacy-protocol": "Privacybeleid protocol", + "privacy-protocol-required": "Privacyprotocol is vereist.", + "protocol-version": "Protocolversie", + "protocol-version-required": "Protocolversie is vereist.", + "querying-frequency": "Frequentie van vragen, ms", + "querying-frequency-invalid-format": "De frequentie van query's moet een positief geheel getal zijn.", + "querying-frequency-required": "Queryfrequentie is vereist.", + "retries": "Pogingen", + "retries-invalid-format": "Pogingen voor nieuwe pogingen moeten een positief geheel getal zijn.", + "retries-required": "Opnieuw proberen is vereist.", + "scope": "Draagwijdte", + "scope-required": "Scope is vereist.", + "security-name": "Naam van de beveiliging", + "security-name-required": "Beveiligingsnaam is vereist.", + "timeout-ms": "Time-out, ms", + "timeout-ms-invalid-format": "Time-out moet een positief geheel getal zijn.", + "timeout-ms-required": "Er is een time-out vereist.", + "user-name": "Gebruikersnaam", + "user-name-required": "Gebruikersnaam is vereist." + } + }, + "dialog": { + "close": "Dialoogvenster sluiten", + "error-message-title": "Foutmelding:", + "error-details-title": "Details van de fout" + }, + "direction": { + "column": "Kolom", + "row": "Rijen" + }, + "edge": { + "all": "Alle", + "all-edges": "Alle edges", + "groups": "Groepen", + "shared": "Gedeeld", + "edge": "Edge", + "edge-instances": "Edge-instanties", + "instances": "Exemplaren", + "edge-file": "Edge-bestand", + "name-max-length": "Naam moet kleiner zijn dan 256 tekens", + "label-max-length": "Etiket moet kleiner zijn dan 256 tekens", + "type-max-length": "Type moet kleiner zijn dan 256 tekens", + "management": "Edge-beheer", + "no-edges-matching": "Er zijn geen edges gevonden die overeenkomen met '{{entity}}'.", + "add": "Edge toevoegen", + "no-edges-text": "Geen edges gevonden", + "edge-details": "Details van de edge", + "add-edge-text": "Nieuwe edge toevoegen", + "delete": "Edge verwijderen", + "delete-edge-title": "Weet je zeker dat je de edge '{{edgeName}}' wilt verwijderen?", + "delete-edge-text": "Opgelet, na de bevestiging worden de edge en alle gerelateerde gegevens onherstelbaar.", + "delete-edges-title": "Weet je zeker dat je { count, plural, =1 {1 edge} andere {# edges} } wilt bevoordelen?", + "delete-edges-text": "Opgelet, na de bevestiging worden alle geselecteerde edges verwijderd en kunnen alle gerelateerde gegevens niet meer worden hersteld.", + "name": "Naam", + "name-starts-with": "Edge naam begint met", + "name-required": "Naam is verplicht.", + "edge-license-key": "Edge-licentiesleutel", + "edge-license-key-required": "Edge-licentiecode is vereist.", + "edge-license-key-max-length": "Edge-licentiesleutel moet kleiner zijn dan 31", + "edge-license-key-hint": "BELANGRIJKE OPMERKING: standaard edge-licentiesleutel wordt alleen verstrekt voor evaluatiedoeleinden.
Deze sleutel is slechts 30 dagen na activering actief. De whitelabeling-functie is uitgeschakeld.
Om uw licentiesleutel te verkrijgen, navigeert u naar de pagina pricing en selecteert u de beste licentieoptie voor uw geval.", + "cloud-endpoint": "Cloud-eindpunt", + "cloud-endpoint-required": "Cloud Endpoint is vereist.", + "cloud-endpoint-max-length": "Cloud-eindpunt moet kleiner zijn dan 256 tekens", + "cloud-endpoint-hint": "Edge vereist HTTP(s)-toegang tot Cloud (ThingsBoard PE) om de licentiesleutel te verifiëren. Geef de cloud-URL op waarmee Edge verbinding kan maken.", + "description": "Omschrijving: __________", + "details": "Details", + "events": "Events", + "copy-id": "Edge-ID kopiëren", + "id-copied-message": "Edge Id is gekopieerd naar klembord", + "sync": "Edge synchroniseren", + "edge-required": "Edge vereist", + "edge-type": "Type edge", + "edge-type-required": "Edge type is vereist.", + "event-action": "Actie voor event", + "entity-id": "Entiteit-ID", + "select-edge-type": "Edge type selecteren", + "assign-to-customer": "Toewijzen aan klant", + "assign-to-customer-text": "Selecteer de klant om de edge(en) toe te wijzen", + "assign-edge-to-customer": "Edge(s) toewijzen aan klant", + "assign-edge-to-customer-text": "Selecteer de edges die u aan de klant wilt toewijzen", + "assignedToCustomer": "Toegewezen aan klant", + "edge-public": "Edge is openbaar", + "assigned-to-customer": "Toegewezen aan: {{customerTitle}}", + "unassign-from-customer": "Toewijzing van klant ongedaan maken", + "unassign-edge-title": "Weet u zeker dat u de toewijzing van de edge '{{edgeName}}' wilt opheffen?", + "unassign-edge-text": "Na de bevestiging wordt de toewijzing van de edge ongedaan gemaakt en is deze niet toegankelijk voor de klant.", + "unassign-edges-title": "Weet u zeker dat u de toewijzing van { count, plural, =1 {1 edge} andere {# edges} } wilt opheffen?", + "unassign-edges-text": "Na de bevestiging worden alle geselecteerde edges ongedaan gemaakt en zijn ze niet toegankelijk voor de klant.", + "make-public": "Edge openbaar maken", + "make-public-edge-title": "Weet je zeker dat je de edge '{{edgeName}}' openbaar wilt maken?", + "make-public-edge-text": "Na de bevestiging worden de edge en al zijn gegevens openbaar gemaakt en toegankelijk gemaakt voor anderen.", + "make-private": "Maak edge privé", + "public": "Publiek", + "make-private-edge-title": "Weet je zeker dat je de edge '{{edgeName}}' privé wilt maken?", + "make-private-edge-text": "Na de bevestiging worden de edge en al zijn gegevens privé gemaakt en zijn ze niet toegankelijk voor anderen.", + "import": "Edge importeren", + "install-connect-instructions": "Installatie- en verbindingsinstructies", + "label": "Etiket", + "load-entity-error": "Gegevens kunnen niet worden geladen. Entiteit is verwijderd.", + "assign-new-edge": "Nieuwe edge toewijzen", + "unassign-from-edge": "Toewijzing van edge ongedaan maken", + "edge-key": "Edge sleutel", + "copy-edge-key": "Edge sleutel kopiëren", + "edge-key-copied-message": "Edge sleutel is gekopieerd naar klembord", + "edge-secret": "Het geheim van de edge", + "copy-edge-secret": "Kopieer Edge geheim", + "edge-secret-copied-message": "Edge-geheim is gekopieerd naar klembord", + "manage-assets": "Assets beheren", + "manage-devices": "Devices beheren", + "manage-entity-views": "Entiteitsweergaven beheren", + "manage-dashboards": "Dashboards beheren", + "manage-rulechains": "Rule chains beheren", + "assets": "Edge-asset", + "devices": "Edge-Devices", + "entity-views": "Edge-entiteitsweergaven", + "dashboard": "Edge-dashboard", + "dashboards": "Edge-dashboards", + "rulechain-templates": "Sjablonen voor rule chains", + "edge-rulechain-templates": "Sjablonen voor edge rule chains", + "converter-templates": "Converter sjablonen", + "edge-converter-templates": "Sjablonen voor edge-converters", + "integration-templates": "Integratie sjablonen", + "edge-integration-templates": "Sjablonen voor edge-integratie", + "rulechains": "Edge rule chains", + "integrations": "Integraties", + "search": "Edge zoeken", + "selected-edges": "{ count, plural, =1 {1 edge} andere {# edges} } geselecteerd", + "any-edge": "Elke edge", + "no-edge-types-matching": "Er zijn geen edge typen gevonden die overeenkomen met '{{entitySubtype}}'.", + "edge-type-list-empty": "Geen edge typen geselecteerd.", + "edge-types": "Soorten edges", + "enter-edge-type": "Voer edge type in", + "deployed": "Ingezet", + "pending": "In behandeling", + "downlinks": "Downlinks", + "no-downlinks-prompt": "Geen downlinks gevonden", + "sync-process-started-successfully": "Het synchronisatieproces is succesvol gestart!", + "missing-related-rule-chains-title": "Edge heeft ontbrekende gerelateerde rule chain(s)", + "missing-related-rule-chains-text": "Toegewezen aan rule chain(s) Gebruik rule nodes die bericht(en) doorsturen naar rule chain(s) die niet aan deze edge zijn toegewezen.

Lijst met ontbrekende rule chain(s):
{{missingRuleChains}}", + "widget-datasource-error": "Deze widget ondersteunt alleen de gegevensbron van de EDGE-entiteit", + "assign-to-edge": "Toewijzen aan edge", + "assign-to-edge-title": "Entiteitsgroep(en) toewijzen aan Edge", + "manage-edge-user-groups": "Edge-gebruikersgroepen beheren", + "manage-edge-asset-groups": "Edge-activagroepen beheren", + "manage-edge-device-groups": "Edge-apparaatgroepen beheren", + "manage-edge-entity-view-groups": "Edge-entiteitsweergavegroepen beheren", + "manage-edge-dashboard-groups": "Edge-dashboardgroepen beheren", + "manage-edge-rule-chains": "Ketens van randregels beheren", + "manage-edge-integrations": "Edge-integraties beheren", + "manage-edge-scheduler-events": "Edge-scheduler events beheren", + "select-group-to-add": "Selecteer de doelgroep om geselecteerde edges toe te voegen", + "select-group-to-move": "Selecteer de doelgroep om geselecteerde edges te verplaatsen", + "remove-edges-from-group": "Weet je zeker dat je { count, plural, =1 {1 edge} andere {# edges} } uit groep '{entityGroup}' wilt verwijderen?", + "group": "Groep edges", + "list-of-groups": "{ count, plural, =1 {One edge group} andere {List of # edge groups} }", + "group-name-starts-with": "Edge-groepen waarvan de naam begint met '{{prefix}}'", + "unassign-entity-group-from-edge-title": "Weet u zeker dat u de toewijzing van de entiteitsgroep '{{ entityGroupName }}' wilt opheffen?", + "unassign-entity-group-from-edge-text": "Na de bevestiging wordt de toewijzing van de entiteitsgroep ongedaan gemaakt en is deze niet toegankelijk via de edge.", + "unassign-entity-group-from-edge": "Toewijzing van entiteitsgroep aan edge ongedaan maken", + "unassign-entity-groups-from-edge-title": "Weet u zeker dat u de toewijzing van {{count}} entiteitsgroepen wilt opheffen?", + "unassign-entity-groups-from-edge-text": "Na de bevestiging wordt de toewijzing van entiteitsgroepen ongedaan gemaakt en zijn ze niet toegankelijk via de edge.", + "unassign-entity-groups-from-edge": "Toewijzing van entiteitsgroepen aan de edge ongedaan maken", + "unassign-scheduler-events-from-edge": "Toewijzing van scheduler events van edge ongedaan maken", + "unassign-scheduler-event-from-edge-title": "Weet u zeker dat u de toewijzing van de '{{schedulerEventName}}' van de planningsgebeurtenis wilt intrekken?", + "unassign-scheduler-event-from-edge-text": "Na de bevestiging wordt de toewijzing van de planningsgebeurtenis ongedaan gemaakt en is deze niet toegankelijk via de edge.", + "unassign-scheduler-events-from-edge-title": "Weet u zeker dat u de toewijzing van { count, plural, =1 {1 scheduler event} andere {# scheduler events} } wilt opheffen?", + "unassign-scheduler-events-from-edge-text": "Na de bevestiging worden alle geselecteerde scheduler events ongedaan gemaakt en zijn ze niet toegankelijk voor de edge.", + "manage-user-groups": "Gebruikersgroepen beheren", + "manage-asset-groups": "Asset groepen beheren", + "manage-device-groups": "Asset groepen beheren", + "manage-dashboard-groups": "Dashboardgroepen beheren", + "manage-entity-view-groups": "Entiteitsweergavegroepen beheren", + "manage-scheduler-events": "Scheduler-events beheren", + "manage-integrations": "Integraties beheren", + "assign-scheduler-event-to-edge-title": "Scheduler-gebeurtenissen toewijzen aan Edge", + "assign-scheduler-event-to-edge-text": "Selecteer de scheduler events die u aan de edge wilt toewijzen", + "assign-entity-groups-to-edge-text": "Selecteer de entiteitsgroepen die u aan de edge wilt toewijzen", + "assign-integration-to-edge-title": "Integraties toewijzen aan Edge", + "assign-integration-to-edge-text": "Selecteer de integraties die u aan de edge wilt toewijzen", + "missing-attributes-title": "Edge heeft ontbrekende attribuut(en)", + "missing-attributes-text": "Integratie(s) die aan de edge zijn toegewezen, hebben tijdelijke aanduidingen voor attributen die niet beschikbaar zijn aan deze edge.

Lijst met ontbrekende edge kenmerken:
{{missingEdgeAttributes}}", + "missing-all-related-attributes-title": "Edge(en) hebben ontbrekende attribuut(en)", + "missing-all-related-attributes-text": "Edge(s), gerelateerd aan integratie, hebben geen attributen die aanwezig zijn in de integratieconfiguratie als tijdelijke aanduidingen voor attributen.

Lijst met ontbrekende edge kenmerken:
{{missingEdgeAttributes}}", + "quick-overview-widget-header": "{{edgeName}} Snel overzicht" + }, + "edge-event": { + "type-dashboard": "Dashboard", + "type-asset": "Asset", + "type-device": "Device", + "type-device-profile": "Device Profiel", + "type-asset-profile": "Asset Profiel", + "type-entity-view": "Entiteit Weergave", + "type-alarm": "Alarm", + "type-entity-group": "Entiteitsgroep", + "type-rule-chain": "Rule chain", + "type-rule-chain-metadata": "Metagegevens van rule chain", + "type-edge": "Edge", + "type-user": "Gebruiker", + "type-customer": "Klant", + "type-relation": "Relatie", + "type-widgets-bundle": "Widgets Bundel", + "type-widgets-type": "Widgets Type", + "type-admin-settings": "Admin-instellingen", + "type-scheduler-event": "Scheduler Evenement", + "type-white-labeling": "White labelling", + "type-login-white-labeling": "Inloggen White Labeling", + "type-custom-translation": "Aangepaste vertaling", + "type-role": "Rol", + "type-group-permission": "Toestemming voor groepen", + "type-integration": "Integratie", + "type-converter": "Conversie type", + "action-type-added": "Toegevoegd", + "action-type-deleted": "Verwijderd", + "action-type-updated": "Bijgewerkt", + "action-type-post-attributes": "Attributen posten", + "action-type-attributes-updated": "Attributen bijgewerkt", + "action-type-attributes-deleted": "Attributen verwijderd", + "action-type-timeseries-updated": "Tijdreeks bijgewerkt", + "action-type-credentials-updated": "Inloggegevens bijgewerkt", + "action-type-assigned-to-customer": "Toegewezen aan klant", + "action-type-unassigned-from-customer": "Toewijzing van klant ongedaan gemaakt", + "action-type-relation-add-or-update": "Relatie toevoegen of bijwerken", + "action-type-relation-deleted": "Relatie verwijderd", + "action-type-rpc-call": "RPC-oproep", + "action-type-alarm-ack": "Alarm Ack", + "action-type-alarm-clear": "Alarm wissen", + "action-type-assigned-to-edge": "Toegewezen aan Edge", + "action-type-unassigned-from-edge": "Toewijzing van Edge ongedaan gemaakt", + "action-type-credentials-request": "Inloggegevens aanvragen", + "action-type-entity-merge-request": "Aanvraag voor samenvoeging van entiteiten", + "action-type-added-to-entity-group": "Toegevoegd aan entiteitsgroep", + "action-type-removed-from-entity-group": "Verwijderd uit entiteitsgroep", + "action-type-change-owner": "Eigenaar wijzigen", + "action-type-relations-deleted": "Relaties verwijderd" + }, + "error": { + "unable-to-connect": "Kan geen verbinding maken met de server! Controleer uw internetverbinding.", + "unhandled-error-code": "Onverwerkte foutcode: {{errorCode}}", + "unknown-error": "Onbekende fout" + }, + "entity": { + "entity": "Entiteit", + "entities": "Entiteiten", + "entities-count": "Aantal entiteiten", + "alarms-count": "Aantal alarmen", + "aliases": "Aliassen van entiteiten", + "entity-alias": "Alias van entiteit", + "unable-delete-entity-alias-title": "Entiteitsalias kan niet worden verwijderd", + "unable-delete-entity-alias-text": "Entiteitsalias '{{entityAlias}}' kan niet worden verwijderd omdat deze wordt gebruikt door de volgende widget(s):
{{widgetsList}}", + "duplicate-alias-error": "Dubbele alias gevonden '{{alias}}'.
Aliassen van entiteiten moeten uniek zijn binnen het dashboard.", + "missing-entity-filter-error": "Filter ontbreekt voor alias '{{alias}}'.", + "configure-alias": "Configureer de alias '{{alias}}'", + "alias": "Alias", + "alias-required": "Entiteitsalias is vereist.", + "remove-alias": "Entiteitsalias verwijderen", + "add-alias": "Entiteitsalias toevoegen", + "entity-list": "Lijst met entiteiten", + "entity-type": "Type entiteit", + "entity-types": "Soorten entiteiten", + "entity-type-list": "Lijst met entiteitstypen", + "any-entity": "Elke entiteit", + "enter-entity-type": "Entiteitstype invoeren", + "no-entities-matching": "Er zijn geen entiteiten gevonden die overeenkomen met '{{entity}}'.", + "no-entity-types-matching": "Er zijn geen entiteitstypen gevonden die overeenkomen met '{{entityType}}'.", + "name-starts-with": "Naam expressie", + "help-text": "Gebruik '%' naar behoefte: '%entity_name_contains%', '%entity_name_ends', 'entity_starts_with'.", + "use-entity-name-filter": "Filter gebruiken", + "entity-list-empty": "Geen entiteiten geselecteerd.", + "entity-type-list-empty": "Er zijn geen entiteitstypen geselecteerd.", + "entity-name-filter-required": "Filter voor entiteitsnamen is vereist.", + "entity-name-filter-no-entity-matched": "Er zijn geen entiteiten gevonden die beginnen met '{{entity}}'.", + "all-subtypes": "Alle", + "select-entities": "Entiteiten selecteren", + "no-aliases-found": "Geen aliassen gevonden.", + "no-alias-matching": "'{{alias}}' niet gevonden.", + "create-new-alias": "Maak een nieuwe aan!", + "key": "Sleutel", + "key-name": "Naam van de sleutel", + "no-keys-found": "Geen sleutels gevonden.", + "no-key-matching": "'{{key}}' niet gevonden.", + "create-new-key": "Maak een nieuwe aan!", + "type": "Type", + "type-required": "Entiteitstype is vereist.", + "type-device": "Device", + "type-devices": "Devices", + "list-of-devices": "{ count, plural, =1 {One device} andere {List of # devices} }", + "device-name-starts-with": "Devices waarvan de naam begint met '{{prefix}}'", + "type-device-profile": "Device profiel", + "type-device-profiles": "Device profielen", + "list-of-device-profiles": "{ count, plural, =1 {One device profile} andere {List of # device profiles} }", + "device-profile-name-starts-with": "Device profielen waarvan de naam begint met '{{prefix}}'", + "type-asset-profile": "Asset profiel", + "type-asset-profiles": "Asset profielen", + "list-of-asset-profiles": "{ count, plural, =1 {One asset profile} andere {List of # asset profiles} }", + "asset-profile-name-starts-with": "Assetprofielen waarvan de naam begint met '{{prefix}}'", + "type-asset": "Asset", + "type-assets": "Assets", + "list-of-assets": "{ count, plural, =1 {One asset} andere {List of # assets} }", + "asset-name-starts-with": "Assets waarvan de naam begint met '{{prefix}}'", + "type-entity-view": "Entiteit Weergave", + "type-entity-views": "Entiteitsweergaven", + "list-of-entity-views": "{ count, plural, =1 {One entity view} andere {List of # entity views} }", + "entity-view-name-starts-with": "Entiteitsweergaven waarvan de naam begint met '{{prefix}}'", + "type-rule": "Regel", + "type-rules": "Reglement", + "list-of-rules": "{ count, plural, =1 {One rule} andere {List of # rules} }", + "rule-name-starts-with": "Regels waarvan de naam begint met '{{prefix}}'", + "type-plugin": "Plug-in", + "type-plugins": "Insteekplaatsen", + "list-of-plugins": "{ count, plural, =1 {One plugin} andere {List of # plugins} }", + "plugin-name-starts-with": "Plug-ins waarvan de naam begint met '{{prefix}}'", + "type-tenant": "Tenant", + "type-tenants": "Tenants", + "list-of-tenants": "{ count, plural, =1 {One tenant} andere {List of # tenants} }", + "tenant-name-starts-with": "Tenants van wie de naam begint met '{{prefix}}'", + "type-tenant-profile": "Profiel van de tenant", + "type-tenant-profiles": "Profielen van tenants", + "list-of-tenant-profiles": "{ count, plural, =1 {One tenant profile} andere {List of # tenant profiles} }", + "tenant-profile-name-starts-with": "Tentant profielen waarvan de naam begint met '{{prefix}}'", + "type-customer": "Klant", + "type-customers": "Klanten", + "list-of-customers": "{ count, plural, =1 {One customer} andere {List of # customers} }", + "customer-name-starts-with": "Klanten van wie de naam begint met '{{prefix}}'", + "type-user": "Gebruiker", + "type-users": "Gebruikers", + "list-of-users": "{ count, plural, =1 {One user} andere {List of # users} }", + "user-name-starts-with": "Gebruikers van wie de naam begint met '{{prefix}}'", + "type-dashboard": "Dashboard", + "type-dashboards": "Dashboards", + "list-of-dashboards": "{ count, plural, =1 {One dashboard} andere {List of # dashboards} }", + "dashboard-name-starts-with": "Dashboards waarvan de naam begint met '{{prefix}}'", + "type-alarm": "Alarm", + "type-alarms": "Alarmen", + "list-of-alarms": "{ count, plural, =1 {One alarm} andere {List of # alarms} }", + "alarm-name-starts-with": "Alarmen waarvan de naam begint met '{{prefix}}'", + "type-rulechain": "Rule chains", + "type-rulechains": "Rule chains", + "list-of-rulechains": "{ count, plural, =1 {One rule chain} andere {List of # rule chains} }", + "rulechain-name-starts-with": "Rule chains waarvan de naam begint met '{{prefix}}'", + "type-scheduler-event": "Scheduler-event", + "type-scheduler-events": "Scheduler-events", + "list-of-scheduler-events": "{ count, plural, =1 {One scheduler event} andere {List of # scheduler events} }", + "scheduler-event-name-starts-with": "Scheduler-events waarvan de naam begint met '{{prefix}}'", + "type-blob-entity": "Blob-entiteit", + "type-blob-entities": "Blob-entiteiten", + "list-of-blob-entities": "{ count, plural, =1 {One blob entity} andere {List of # blob entities} }", + "blob-entity-name-starts-with": "Blob-entiteiten waarvan de naam begint met '{{prefix}}'", + "type-rulenode": "Rule node", + "type-rulenodes": "Rule nodes", + "list-of-rulenodes": "{ count, plural, =1 {One rule node} andere {List of # rule nodes} }", + "rulenode-name-starts-with": "Rule node waarvan de naam begint met '{{prefix}}'", + "type-current-customer": "Huidige klant", + "type-current-tenant": "Huidige tenant", + "type-current-user": "Huidige gebruiker", + "type-current-user-owner": "Huidige gebruikerseigenaar", + "type-widgets-bundle": "Widgets bundel", + "type-widgets-bundles": "Widgets bundels", + "list-of-widgets-bundles": "{ count, plural, =1 {One widgets bundle} andere {List of # widget bundles} }", + "search": "Entiteiten zoeken", + "selected-entities": "{ count, plural, =1 {1 entity} andere {# entities} } geselecteerd", + "entity-name": "Naam van de entiteit", + "entity-label": "Entiteitslabel", + "details": "Gegevens van de entiteit", + "no-entities-prompt": "Geen entiteiten gevonden", + "no-data": "Geen gegevens om weer te geven", + "columns-to-display": "Weer te geven kolommen", + "type-api-usage-state": "Api-gebruiksstatus", + "type-entity-group": "Entiteitsgroep", + "type-converter": "Gegevens converteren", + "type-converters": "Data-converters", + "list-of-converters": "{ count, plural, =1 {One data converter} andere {List of # data converters} }", + "converter-name-starts-with": "Dataconverters waarvan de naam begint met \"{{prefix}}\"", + "type-integration": "Integratie", + "type-integrations": "Integraties", + "list-of-integrations": "{ count, plural, =1 {One integration} andere {List of # integrations} }", + "integration-name-starts-with": "Integraties waarvan de naam begint met '{{prefix}}'", + "type-role": "Rol", + "type-roles": "Rollen", + "list-of-roles": "{ count, plural, =1 {One role} andere {List of # roles} }", + "role-name-starts-with": "Rollen waarvan de naam begint met '{{prefix}}'", + "type-group-permission": "Toestemming voor groepen", + "type-edge": "Edge", + "type-edges": "Edge", + "list-of-edges": "{ count, plural, =1 {One edge} andere {List of # edges} }", + "edge-name-starts-with": "Edge waarvan de naam begint met '{{prefix}}'", + "type-tb-resource": "Hulpbron", + "type-ota-package": "OTA-pakket", + "type-rpc": "RPC", + "type-queue": "Rij", + "type-notification": "Bekendmaking", + "type-notification-rule": "Meldingsregel", + "type-notification-target": "Ontvanger van de melding", + "type-notification-request": "Verzoek om kennisgeving", + "type-notification-template": "Kennisgeving sjabloon", + "customer-name": "Naam van de klant", + "sub-customer-name": "Naam van de subklant", + "parent-customer-name": "Naam van bovenliggende klant", + "parent-sub-customer-name": "Naam van bovenliggende subklant", + "include-customer-entities": "Klantentiteiten opnemen", + "include-sub-customer-entities": "Entiteiten van subklanten opnemen", + "groups": "Groepen" + }, + "entity-group": { + "entity-group": "Entiteitsgroep", + "details": "Details", + "columns": "Kolommen", + "add-column": "Kolom toevoegen", + "column-value": "Waarde", + "column-value-required": "Kolomwaarde is vereist.", + "column-title": "Titel", + "default-sort-order": "Standaard sorteervolgorde", + "default-sort-order-required": "De standaard sorteervolgorde is vereist.", + "hide-in-mobile-view": "Mobiel verborgen", + "use-cell-style-function": "Celstijlfunctie gebruiken", + "use-cell-content-function": "De functie voor celinhoud gebruiken", + "edit-column": "Kolom bewerken", + "column-details": "Kolom details", + "actions": "Acties", + "settings": "Instellingen", + "search": "Entiteitsgroepen zoeken", + "delete": "Entiteitsgroep verwijderen", + "name": "Naam", + "name-required": "Naam is verplicht.", + "name-max-length": "Naam moet kleiner zijn dan 256 tekens", + "description": "Omschrijving: __________", + "add": "Entiteitsgroep toevoegen", + "open-entity-group": "Entiteitsgroep openen", + "add-entity-group-text": "Nieuwe entiteitsgroep toevoegen", + "no-entity-groups-text": "Geen entiteitsgroepen gevonden", + "entity-group-details": "Details van entiteitsgroep", + "selected-entity-groups": "{ count, plural, =1 {1 entity group} andere {# entity groups} } geselecteerd", + "delete-entity-groups": "Entiteitsgroepen verwijderen", + "delete-entity-group-title": "Weet u zeker dat u de entiteitsgroep '{{entityGroupName}}' wilt verwijderen?", + "delete-entity-group-text": "Let op, na de bevestiging worden de entiteitsgroep en alle gerelateerde gegevens onherstelbaar.", + "delete-entity-groups-title": "Weet u zeker dat u { count, plural, =1 {1 entity group} andere {# entity groups} } wilt verwijderen?", + "delete-entity-groups-action-title": "Verwijder { count, plural, =1 {1 entity group} andere {# entity groups} }", + "delete-entity-groups-text": "Opgelet, na de bevestiging worden alle geselecteerde entiteitsgroepen verwijderd en kunnen alle gerelateerde gegevens niet meer worden hersteld.", + "device-groups": "Asset groepen", + "shared-device-groups": "Groepen met gedeelde devices", + "asset-groups": "Asset groepen", + "shared-asset-groups": "Gedeelde activagroepen", + "customer-groups": "Klantengroepen", + "shared-customer-groups": "Gedeelde klantgroepen", + "device-group": "Apparaatgroep", + "asset-group": "Activagroep", + "user-group": "Gebruikersgroep", + "user-groups": "Gebruikersgroepen", + "customer-group": "Klantengroep", + "entity-view-groups": "Groepen voor entiteitsweergaven", + "shared-entity-view-groups": "Groepen met gedeelde entiteitsweergave", + "entity-view-group": "Groep voor entiteitsweergave", + "edge-groups": "Randgroepen", + "shared-edge-groups": "Gedeelde randgroepen", + "edge-group": "Edge groep", + "dashboard-groups": "Dashboard groepen", + "shared-dashboard-groups": "Gedeelde dashboardgroepen", + "dashboard-group": "Dashboard groep", + "fetch-more": "Haal meer op", + "column-type": { + "column-type": "Type kolom", + "client-attribute": "Cliënt attribuut", + "shared-attribute": "Gedeeld attribuut", + "server-attribute": "Server-attribuut", + "timeseries": "Timeseries", + "entity-field": "Entiteit veld" + }, + "column-type-required": "Kolomtype is vereist.", + "entity-field": { + "created-time": "Gecreëerde tijd", + "name": "Naam", + "type": "Type", + "device_profile": "Device profiel", + "asset_profile": "Asset profiel", + "assigned_customer": "Toegewezen klant", + "authority": "Autoriteit", + "first_name": "Voornaam", + "last_name": "Achternaam", + "email": "E-mail", + "title": "Titel", + "country": "Land", + "state": "Staat", + "city": "Stad", + "address": "Adres", + "address2": "Adres 2", + "zip": "Ritssluiting", + "phone": "Telefoon", + "label": "Etiket" + }, + "sort-order": { + "asc": "Oplopend", + "desc": "Aflopende", + "none": "Geen" + }, + "details-mode": { + "on-row-click": "Klik op rij", + "on-action-button-click": "Klik op de knop Details", + "disabled": "Invalide" + }, + "change-owner": "Eigenaar wijzigen", + "select-target-owner": "Selecteer doeleigenaar", + "no-owners-matching": "Er zijn geen eigenaren gevonden die overeenkomen met '{{owner}}'.", + "target-owner-required": "Doeleigenaar is vereist.", + "confirm-change-owner-title": "Weet u zeker dat u van eigenaar wilt veranderen voor { count, plural, =1 {1 selected entity} andere {# selected entities} }?", + "confirm-change-owner-text": "Opgelet, na de bevestiging worden alle geselecteerde entiteiten verwijderd van de huidige eigenaar en worden ze geplaatst in de groep 'Alle' van de doeleigenaar.", + "add-to-group": "Toevoegen aan groep", + "move-to-group": "Verplaatsen naar groep", + "select-entity-group": "Entiteitsgroep selecteren", + "no-entity-groups-matching": "Er zijn geen entiteitsgroepen gevonden die overeenkomen met '{{entityGroup}}'.", + "create-new-entity-group": "Maak een nieuwe aan!", + "target-entity-group-required": "Doelgroep is vereist.", + "select-user-group": "Selecteer gebruikersgroep", + "no-user-groups-matching": "Er zijn geen gebruikersgroepen gevonden die overeenkomen met '{{entityGroup}}'.", + "target-user-group-required": "Doelgroep is vereist.", + "remove-from-group": "Verwijderen uit groep", + "group-table-title": "Titel van groepstabel", + "enable-search": "Zoeken naar entiteiten inschakelen", + "enable-add": "Entiteiten toevoegen inschakelen", + "enable-delete": "Entiteiten verwijderen inschakelen", + "enable-selection": "Selectie van entiteiten inschakelen", + "enable-group-transfer": "Acties voor groepsoverdracht inschakelen", + "display-pagination": "Paginering weergeven", + "default-page-size": "Standaard paginaformaat", + "enable-assignment-actions": "Toewijzingsacties inschakelen", + "enable-credentials-management": "Beheer van referenties inschakelen", + "enable-login-as-user": "Inloggen als gebruikersactie inschakelen", + "enable-users-management": "Gebruikersbeheer inschakelen", + "enable-customers-management": "Klantenbeheer inschakelen", + "enable-assets-management": "Asset beheer inschakelen", + "enable-devices-management": "Device beheer inschakelen", + "enable-entity-views-management": "Beheer van entiteitsweergaven inschakelen", + "enable-edges-management": "Edge beheer inschakelen", + "enable-dashboards-management": "Dashboardbeheer inschakelen", + "enable-scheduler-events-management": "Beheer van scheduler events inschakelen", + "open-details-on": "Entiteitsdetails openen op", + "select-existing": "Bestaande entiteitsgroep selecteren", + "create-new": "Nieuwe entiteitsgroep maken", + "new-entity-group-name": "Naam van nieuwe entiteitsgroep", + "entity-group-list": "Lijst met entiteitsgroepen", + "entity-group-list-empty": "Geen entiteitsgroepen geselecteerd.", + "name-starts-with": "De naam van de entiteitsgroep begint met", + "entity-group-name-filter-required": "Filter voor de naam van de entiteitsgroep is vereist.", + "roles": "Rollen", + "permissions": "Machtigingen", + "public": "Publiek", + "entity-group-public": "Entiteitsgroep is openbaar", + "make-public": "Entiteitsgroep openbaar maken", + "make-private": "Entiteitsgroep privé maken", + "make-public-entity-group-title": "Weet u zeker dat u de entiteitsgroep '{{entityGroupName}}' openbaar wilt maken?", + "make-public-entity-group-text": "Na de bevestiging worden de entiteitengroep en al haar entiteiten openbaar gemaakt en toegankelijk gemaakt voor anderen.", + "make-private-entity-group-title": "Weet u zeker dat u de entiteitsgroep '{{entityGroupName}}' privé wilt maken?", + "make-private-entity-group-text": "Na de bevestiging worden de entiteitengroep en al zijn entiteiten privé gemaakt en zijn ze niet toegankelijk voor anderen.", + "share": "Entiteitsgroep delen", + "copyId": "Entiteitsgroep-id kopiëren", + "idCopiedMessage": "Entiteitsgroep-id is gekopieerd naar klembord", + "entity-group-name": "Naam van entiteitsgroep", + "all-users": "Alle gebruikers", + "owner": "Eigenaar", + "owner-required": "Eigenaar is verplicht.", + "manage-owner-and-groups": "Eigenaar en groepen beheren", + "owner-and-groups": "Eigenaar en groepen" + }, + "entity-field": { + "created-time": "Gecreëerde tijd", + "name": "Naam", + "type": "Type", + "first-name": "Voornaam", + "last-name": "Achternaam", + "email": "E-mail", + "title": "Titel", + "country": "Land", + "state": "Staat", + "city": "Stad", + "address": "Adres", + "address2": "Adres 2", + "zip": "Ritssluiting", + "phone": "Telefoon", + "label": "Etiket", + "configuration": "Configuratie", + "schedule": "Rooster", + "originatorId": "Initiator-ID", + "originatorType": "Type opsteller" + }, + "entity-view": { + "all": "Alle", + "all-entity-views": "Alle entiteitsweergaven", + "groups": "Groepen", + "shared": "Gedeeld", + "entity-view": "Entiteit Weergave", + "entity-view-required": "Entiteitsweergave is vereist.", + "entity-views": "Entiteitsweergaven", + "management": "Beheer van entiteitsweergaven", + "view-entity-views": "Entiteitsweergaven weergeven", + "entity-view-alias": "Alias voor entiteitsweergave", + "aliases": "Aliassen voor entiteitsweergave", + "no-alias-matching": "'{{alias}}' niet 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}}'.
Aliassen voor entiteitsweergave moeten uniek zijn binnen het dashboard.", + "configure-alias": "Configureer de alias '{{alias}}'", + "no-entity-views-matching": "Er zijn geen entiteitsweergaven gevonden die overeenkomen met '{{entity}}'.", + "public": "Publiek", + "alias": "Alias", + "alias-required": "Alias voor entiteitsweergave is vereist.", + "remove-alias": "Alias voor entiteitsweergave verwijderen", + "add-alias": "Alias voor entiteitsweergave toevoegen", + "name-starts-with": "Naamexpressie entiteitsweergave", + "help-text": "Gebruik '%' naar behoefte: '%entity-view_name_contains%', '%entity-view_name_ends', 'entity-view_starts_with'.", + "entity-view-list": "Lijst met entiteitsweergaven", + "use-entity-view-name-filter": "Filter gebruiken", + "entity-view-list-empty": "Geen entiteitsweergaven geselecteerd.", + "entity-view-name-filter-required": "Het naamfilter voor de entiteitsweergave is vereist.", + "entity-view-name-filter-no-entity-view-matched": "Er zijn geen entiteitsweergaven gevonden die beginnen met '{{entityView}}'.", + "add": "Entiteitsweergave toevoegen", + "entity-view-public": "Entiteitsweergave is openbaar", + "assign-to-customer": "Toewijzen aan klant", + "assign-entity-view-to-customer": "Entiteitsweergave(n) toewijzen aan klant", + "assign-entity-view-to-customer-text": "Selecteer de entiteitsweergaven die u aan de klant wilt toewijzen", + "no-entity-views-text": "Geen entiteitsweergaven gevonden", + "assign-to-customer-text": "Selecteer de klant om de entiteitsweergave(n) toe te wijzen", + "entity-view-details": "Details van entiteitsweergave", + "add-entity-view-text": "Nieuwe entiteitsweergave toevoegen", + "delete": "Entiteitsweergave verwijderen", + "assign-entity-views": "Entiteitsweergaven toewijzen", + "assign-entity-views-text": "Wijs { count, plural, =1 {1 entity view} andere {# entity views} } toe aan de klant", + "delete-entity-views": "Entiteitsweergaven verwijderen", + "make-public": "Entiteitsweergave openbaar maken", + "make-private": "Entiteitsweergave privé maken", + "unassign-from-customer": "Toewijzing van klant ongedaan maken", + "unassign-entity-views": "Toewijzing van entiteitsweergaven intrekken", + "unassign-entity-views-action-title": "Toewijzing { count, plural, =1 {1 entity view} andere {# entity views} } van klant ongedaan maken", + "assign-new-entity-view": "Nieuwe entiteitsweergave toewijzen", + "delete-entity-view-title": "Weet u zeker dat u de entiteitsweergave '{{entityViewName}}' wilt verwijderen?", + "delete-entity-view-text": "Opgelet, na de bevestiging worden de entiteitsweergave en alle gerelateerde gegevens onherstelbaar.", + "delete-entity-views-title": "Weet u zeker dat u { count, plural, =1 {1 entity view} andere {# entity views} } wilt verwijderen?", + "delete-entity-views-action-title": "Verwijder { count, plural, =1 {1 entity view} andere {# entity views} }", + "delete-entity-views-text": "Opgelet, na de bevestiging worden alle geselecteerde entiteitsweergaven verwijderd en kunnen alle gerelateerde gegevens niet meer worden hersteld.", + "make-public-entity-view-title": "Weet u zeker dat u de entiteitsweergave '{{entityViewName}}' openbaar wilt maken?", + "make-public-entity-view-text": "Na de bevestiging worden de entiteitsweergave en al haar gegevens openbaar en toegankelijk gemaakt voor anderen.", + "make-private-entity-view-title": "Weet u zeker dat u de entiteitsweergave '{{entityViewName}}' privé wilt maken?", + "make-private-entity-view-text": "Na de bevestiging worden de entiteitsweergave en al zijn gegevens privé gemaakt en zijn ze niet toegankelijk voor anderen.", + "unassign-entity-view-title": "Weet u zeker dat u de toewijzing van de entiteitsweergave '{{entityViewName}}' wilt opheffen?", + "unassign-entity-view-text": "Na de bevestiging wordt de toewijzing van de entiteitsweergave ongedaan gemaakt en is deze niet toegankelijk voor de klant.", + "unassign-entity-view": "Toewijzing van entiteitsweergave ongedaan maken", + "unassign-entity-views-title": "Weet u zeker dat u de toewijzing van { count, plural, =1 {1 entity view} andere {# entity views} } wilt opheffen?", + "unassign-entity-views-text": "Na de bevestiging worden alle geselecteerde entiteitsweergaven ongedaan gemaakt en zijn ze niet toegankelijk voor de klant.", + "entity-view-type": "Type entiteitsweergave", + "entity-view-type-required": "Het type Entiteitsweergave is vereist.", + "select-entity-view-type": "Weergavetype entiteit selecteren", + "enter-entity-view-type": "Entiteitsweergavetype invoeren", + "any-entity-view": "Elke entiteitsweergave", + "no-entity-view-types-matching": "Er zijn geen entiteitsweergavetypen gevonden die overeenkomen met '{{entitySubtype}}'.", + "entity-view-type-list-empty": "Er zijn geen types entiteitsweergaven geselecteerd.", + "entity-view-types": "Typen entiteitsweergaven", + "created-time": "Gecreëerde tijd", + "name": "Naam", + "name-required": "Naam is verplicht.", + "name-max-length": "Naam moet kleiner zijn dan 256 tekens", + "type-max-length": "Het type entiteitsweergave moet kleiner zijn dan 256 tekens", + "description": "Omschrijving: __________", + "events": "Events", + "details": "Details", + "copyId": "Entiteitsweergave-id kopiëren", + "idCopiedMessage": "Entiteitsweergave-id is gekopieerd naar klembord", + "assignedToCustomer": "Toegewezen aan klant", + "unable-entity-view-device-alias-title": "Kan alias voor entiteitsweergave niet verwijderen", + "unable-entity-view-device-alias-text": "Entiteitsweergave device alias '{{entityViewAlias}}' kan niet worden verwijderd omdat deze wordt gebruikt door de volgende widget(s):
{{widgetsList}}", + "select-entity-view": "Entiteitsweergave selecteren", + "start-date": "Begindatum", + "start-ts": "Begintijd", + "end-date": "Einddatum", + "end-ts": "Eindtijd", + "date-limits": "Datumlimieten", + "client-attributes": "Attributen van de klant", + "shared-attributes": "Gedeelde attributen", + "server-attributes": "Server-attributen", + "timeseries": "Timeseries", + "client-attributes-placeholder": "Attributen van de klant", + "shared-attributes-placeholder": "Gedeelde attributen", + "server-attributes-placeholder": "Server-attributen", + "timeseries-placeholder": "Timeseries", + "target-entity": "Doelentiteit", + "attributes-propagation": "Doorgifte van attributen", + "attributes-propagation-hint": "Entiteitsweergave kopieert automatisch gespecificeerde attributen van doelentiteit telkens wanneer u deze entiteitsweergave opslaat of bijwerkt. Om prestatieredenen worden de attributen van de doelentiteit niet doorgegeven aan de entiteitsweergave bij elke kenmerkwijziging. U kunt automatische doorgifte inschakelen door het rulenode 'kopiëren naar weergave' in uw rule chain te configureren en berichten 'Attributen posten' en 'Attributen bijgewerkt' te koppelen aan het nieuwe rule node.", + "timeseries-data": "Tijdreeksgegevens", + "timeseries-data-hint": "Configureer timeseries sleutels van de doelentiteit die toegankelijk zijn voor de entiteitsweergave. Deze timeseries gegevens zijn niet editeerbaar.", + "select-group-to-add": "Selecteer de doelgroep om geselecteerde entiteitsweergaven toe te voegen", + "select-group-to-move": "Selecteer de doelgroep om geselecteerde entiteitsweergaven te verplaatsen", + "remove-entity-views-from-group": "Weet je zeker dat je { count, plural, =1 {1 entity view} andere {# entity views} } uit groep '{{entityGroup}}' wilt verwijderen?", + "group": "Groep entiteitsweergaven", + "list-of-groups": "{ count, plural, =1 {One entity view group} andere {List of # entity view groups} }", + "group-name-starts-with": "Entiteitsweergavegroepen waarvan de naam begint met '{{prefix}}'", + "search": "Entiteitsweergaven zoeken", + "selected-entity-views": "{ count, plural, =1 {1 entity view} andere {# entity views} } geselecteerd", + "assign-entity-view-to-edge": "Entiteitsweergave(n) toewijzen aan edge", + "assign-entity-view-to-edge-text": "Selecteer de entiteitsweergaven die u aan de edge wilt toewijzen", + "unassign-entity-view-from-edge-title": "Weet u zeker dat u de toewijzing van de entiteitsweergave '{{entityViewName}}' wilt opheffen?", + "unassign-entity-view-from-edge-text": "Na de bevestiging wordt de toewijzing van de entiteitsweergave ongedaan gemaakt en is deze niet toegankelijk via de edge.", + "unassign-entity-views-from-edge-action-title": "Toewijzing { count, plural, =1 {1 entity view} andere {# entity views} } van edge ongedaan maken", + "unassign-entity-view-from-edge": "Toewijzing van entiteitsweergave ongedaan maken", + "unassign-entity-views-from-edge-title": "Weet u zeker dat u de toewijzing van { count, plural, =1 {1 entity view} andere {# entity views} } wilt opheffen?", + "unassign-entity-views-from-edge-text": "Na de bevestiging worden alle geselecteerde entiteitsweergaven ongedaan gemaakt en zijn ze niet toegankelijk via de edge." + }, + "event": { + "events": "Events", + "event-type": "Type event", + "events-filter": "Events filter", + "clean-events": "Events wissen", + "type-error": "Fout", + "type-lc-event": "Levens cyclus event", + "type-stats": "Statistiek", + "type-debug-converter": "Debuggen", + "type-debug-integration": "Debuggen", + "type-debug-rule-node": "Debuggen", + "type-debug-rule-chain": "Debuggen", + "no-events-prompt": "Geen events gevonden", + "error": "Fout", + "alarm": "Alarm", + "event-time": "Tijd voor de event", + "server": "Server", + "body": "Body", + "method": "Methode", + "type": "Type", + "in": "In", + "out": "Buiten", + "metadata": "Metagegevens", + "message": "Bericht", + "entity": "Entiteit", + "message-id": "Bericht-ID", + "copy-message-id": "Kopieer bericht-ID", + "message-type": "Type bericht", + "data-type": "Soort gegevens", + "relation-type": "Relatie Type", + "data": "Data", + "event": "Event", + "status": "Status", + "success": "Succes", + "failed": "Mislukt", + "messages-processed": "Verwerkte berichten", + "max-messages-processed": "Maximum aantal verwerkte berichten", + "min-messages-processed": "Minimaal aantal verwerkte berichten", + "errors-occurred": "Er zijn fouten opgetreden", + "max-errors-occurred": "Maximale fouten opgetreden", + "min-errors-occurred": "Er zijn minimale fouten opgetreden", + "min-value": "Minimale waarde is 0.", + "all-events": "Alle", + "has-error": "Heeft fout", + "entity-id": "Entiteit-ID", + "copy-entity-id": "Entiteits-ID kopiëren", + "entity-type": "Type entiteit", + "clear-filter": "Filter wissen", + "clear-request-title": "Wis alle events", + "clear-request-text": "Weet je zeker dat je alle events wilt wissen?", + "started": "Begon", + "updated": "Bijgewerkt", + "stopped": "Gestopt" + }, + "extension": { + "extensions": "Extensies", + "selected-extensions": "{ count, plural, =1 {1 extension} andere {# extensions} } geselecteerd", + "type": "Type", + "key": "Sleutel", + "value": "Waarde", + "id": "Legitimatiebewijs", + "extension-id": "Extensie-id", + "extension-type": "Type extensie", + "transformer-json": "JSON *", + "unique-id-required": "De huidige extensie-id bestaat al.", + "delete": "Extensie verwijderen", + "add": "Extensie toevoegen", + "edit": "Extensie bewerken", + "view": "Bekijk extensie", + "delete-extension-title": "Weet je zeker dat je de extensie '{{extensionId}}' wilt verwijderen?", + "delete-extension-text": "Opgelet, na de bevestiging worden de extensie en alle gerelateerde gegevens onherstelbaar.", + "delete-extensions-title": "Weet u zeker dat u { count, plural, =1 {1 extension} andere {# extensions} } wilt verwijderen?", + "delete-extensions-text": "Opgelet, na de bevestiging worden alle geselecteerde extensies verwijderd.", + "converters": "Converters", + "converter-id": "Converter-id", + "configuration": "Configuratie", + "converter-configurations": "Converter configuraties", + "token": "Beveiligingstoken", + "add-converter": "Converter toevoegen", + "add-config": "Converterconfiguratie toevoegen", + "device-name-expression": "Expressie van device naam", + "device-type-expression": "Expressie van device type", + "custom": "Gewoonte", + "to-double": "Verdubbelen", + "transformer": "Transformator", + "json-required": "Transformator json is vereist.", + "json-parse": "Kan transformator json niet parseren.", + "attributes": "Attributen", + "add-attribute": "Attribuut toevoegen", + "add-map": "Toewijzingselement toevoegen", + "timeseries": "Timeseries", + "add-timeseries": "Timeseries toevoegen", + "field-required": "Veld is verplicht", + "brokers": "Brokers", + "add-broker": "Broker toevoegen", + "host": "Server host", + "port": "Haven", + "port-range": "De poort moet tussen 1 en 65535 liggen.", + "ssl": "Ssl", + "credentials": "Inloggegevens", + "username": "Gebruikersnaam", + "password": "Wachtwoord", + "retry-interval": "Interval voor opnieuw proberen in milliseconden", + "sas": "Handtekening voor gedeelde toegang", + "anonymous": "Anoniem", + "basic": "Basis", + "pem": "PEM", + "ca-cert": "CA-certificaatbestand *", + "private-key": "Bestand met privésleutel *", + "cert": "Certificaat bestand *", + "no-file": "Geen bestand geselecteerd.", + "drop-file": "Zet een bestand neer of klik om een bestand te selecteren om te uploaden.", + "mapping": "Kartering", + "topic-filter": "Onderwerp filter", + "converter-type": "Type converter", + "converter-json": "Json", + "json-name-expression": "JSON-expressie voor device naam", + "topic-name-expression": "Topic expressie device naam", + "json-type-expression": "json-expressie van device type", + "topic-type-expression": "Topic expressie van device type", + "attribute-key-expression": "Expressie van kenmerksleutel", + "attr-json-key-expression": "Json-expressie van kenmerksleutel", + "attr-topic-key-expression": "Topic expressie van kenmerk", + "request-id-expression": "ID-expressie aanvragen", + "request-id-json-expression": "Aanvraag-id json-expressie", + "request-id-topic-expression": "Topic expressie voor aanvraag-id", + "response-topic-expression": "Expressie van topic response", + "value-expression": "Waarde expressie", + "topic": "Onderwerp", + "timeout": "Time-out in milliseconden", + "converter-json-required": "Converter json is vereist.", + "converter-json-parse": "Kan converter json niet parseren.", + "filter-expression": "Expressie filteren", + "connect-requests": "Verbind aanvragen", + "add-connect-request": "Verbindingsverzoek toevoegen", + "disconnect-requests": "Verzoeken om de verbinding te verbreken", + "add-disconnect-request": "Verzoek tot verbroken verbinding toevoegen", + "attribute-requests": "Attribuut aanvragen", + "add-attribute-request": "Attribuutaanvraag toevoegen", + "attribute-updates": "Updates van attributen", + "add-attribute-update": "Attribuutupdate toevoegen", + "server-side-rpc": "RPC aan de serverzijde", + "add-server-side-rpc-request": "RPC-verzoek aan serverzijde toevoegen", + "device-name-filter": "Filter voor device naam", + "attribute-filter": "Attribuut filter", + "method-filter": "Methode filter", + "request-topic-expression": "Topic expressie aanvragen", + "response-timeout": "Time-out voor respons in milliseconden", + "topic-expression": "Onderwerp expressie", + "client-scope": "Toepassingsgebied van de klant", + "add-device": "Device toevoegen", + "opc-server": "Servers", + "opc-add-server": "Server toevoegen", + "opc-add-server-prompt": "Gelieve server toe te voegen", + "opc-application-name": "Naam van de toepassing", + "opc-application-uri": "Applicatie uri", + "opc-scan-period-in-seconds": "Scanperiode in seconden", + "opc-security": "Veiligheid", + "opc-identity": "Identiteit", + "opc-keystore": "Sleutel opslag", + "opc-type": "Type", + "opc-keystore-type": "Type", + "opc-keystore-location": "Plaats*", + "opc-keystore-password": "Wachtwoord", + "opc-keystore-alias": "Alias", + "opc-keystore-key-password": "Sleutel wachtwoord", + "opc-device-node-pattern": "Knooppuntpatroon van het device", + "opc-device-name-pattern": "Patroon van device naam", + "modbus-server": "Servers", + "modbus-add-server": "Server toevoegen", + "modbus-add-server-prompt": "Gelieve server toe te voegen", + "modbus-transport": "Vervoer", + "modbus-tcp-reconnect": "Automatisch opnieuw verbinding maken", + "modbus-rtu-over-tcp": "RTU via TCP", + "modbus-port-name": "Naam seriële poort", + "modbus-encoding": "Codering", + "modbus-parity": "Pariteit", + "modbus-baudrate": "Baudrate", + "modbus-databits": "Data bits gegevens", + "modbus-stopbits": "Data bits stop", + "modbus-databits-range": "Data bits moeten tussen 7 en 8 liggen.", + "modbus-stopbits-range": "Stop bits moeten in een bereik van 1 tot 2 liggen.", + "modbus-unit-id": "Eenheid-ID", + "modbus-unit-id-range": "De eenheids-ID moet tussen 1 en 247 liggen.", + "modbus-device-name": "Naam van het device", + "modbus-poll-period": "Enquête periode (ms)", + "modbus-attributes-poll-period": "Attributen enquêteperiode (ms)", + "modbus-timeseries-poll-period": "Tijdreeks-enquêteperiode (ms)", + "modbus-poll-period-range": "De enquêteperiode moet een positieve waarde hebben.", + "modbus-tag": "Label", + "modbus-function": "Functie", + "modbus-register-address": "Adres registreren", + "modbus-register-address-range": "Het registratieadres moet tussen 0 en 65535 liggen.", + "modbus-register-bit-index": "De index van het bit", + "modbus-register-bit-index-range": "De bitindex moet tussen 0 en 15 liggen.", + "modbus-register-count": "Aantal registreren", + "modbus-register-count-range": "Het aantal registers moet een positieve waarde zijn.", + "modbus-byte-order": "Byte volgorde", + "sync": { + "status": "Status", + "sync": "Sync", + "not-sync": "Niet synchroniseren", + "last-sync-time": "Laatste synchronisatietijd", + "not-available": "Niet beschikbaar" + }, + "export-extensions-configuration": "Configuratie van extensies exporteren", + "import-extensions-configuration": "Configuratie van extensies importeren", + "import-extensions": "Extensies importeren", + "import-extension": "Extensie importeren", + "export-extension": "Export extensie", + "file": "Extensies bestand", + "invalid-file-error": "Ongeldig extensiebestand", + "text": "SMS", + "json": "JSON", + "binary": "BINAIR", + "hex": "HEX" + }, + "feature": { + "advanced-features": "Geavanceerde functies" + }, + "filter": { + "add": "Filter toevoegen", + "edit": "Filter bewerken", + "name": "Naam van filter", + "name-required": "Filternaam is vereist.", + "duplicate-filter": "Filter met dezelfde naam bestaat al.", + "filters": "Filters", + "unable-delete-filter-title": "Filter kan niet worden verwijderd", + "unable-delete-filter-text": "Filter '{{filter}}' kan niet worden verwijderd omdat het wordt gebruikt door de volgende widget(s):
{{widgetsList}}", + "duplicate-filter-error": "Duplicaatfilter gevonden '{{filter}}'.
Filters moeten uniek zijn binnen het dashboard.", + "missing-key-filters-error": "Sleutelfilters ontbreken voor filter '{{filter}}'.", + "filter": "Filter", + "editable": "Bewerkbaar", + "no-filters-found": "Geen filters gevonden.", + "no-filter-text": "Geen filter gespecificeerd", + "add-filter-prompt": "Filter toevoegen", + "no-filter-matching": "'{{filter}}' niet gevonden.", + "create-new-filter": "Maak een nieuwe aan!", + "filter-required": "Filter is vereist.", + "operation": { + "operation": "Operatie", + "equal": "gelijk", + "not-equal": "Niet gelijk", + "starts-with": "begint met", + "ends-with": "eindigt met", + "contains": "Bevat", + "not-contains": "Bevat niet", + "greater": "groter dan", + "less": "minder dan", + "greater-or-equal": "groter of gelijk", + "less-or-equal": "minder of gelijk aan", + "and": "en", + "or": "of", + "in": "in", + "not-in": "Niet in" + }, + "ignore-case": "Hoofdlettergebruik negeren", + "value": "Waarde", + "remove-filter": "Filter verwijderen", + "duplicate-filter-action": "Filter dupliceren", + "preview": "Voorbeeld van filter", + "no-filters": "Geen filters geconfigureerd", + "add-filter": "Filter toevoegen", + "add-complex-filter": "Complex filter toevoegen", + "add-complex": "Complex toevoegen", + "complex-filter": "Complex filter", + "edit-complex-filter": "Complex filter bewerken", + "edit-filter-user-params": "Gebruikersparameters voor filter predicate bewerken", + "filter-user-params": "Gebruikersparameters voor predicaten filteren", + "user-parameters": "Parameters van de gebruiker", + "display-label": "Label om weer te geven", + "autogenerated-label": "Automatisch label genereren", + "order-priority": "Prioriteit voor veldorders", + "key-filter": "Toets filter", + "key-filters": "Belangrijkste filters", + "key-name": "Naam van de sleutel", + "key-name-required": "De naam van de sleutel is vereist.", + "key-type": { + "key-type": "Type sleutel", + "attribute": "Attribuut", + "timeseries": "Timeseries", + "entity-field": "Entiteit veld", + "constant": "Constant" + }, + "value-type": { + "value-type": "Soort waarde", + "string": "Snaar", + "numeric": "Numeriek", + "boolean": "Booleaans", + "date-time": "Datum/tijd" + }, + "value-type-required": "Het type sleutelwaarde is vereist.", + "key-value-type-change-title": "Weet u zeker dat u het type sleutelwaarde wilt wijzigen?", + "key-value-type-change-message": "Als u het nieuwe waardetype bevestigt, worden alle ingevoerde toetsfilters verwijderd.", + "no-key-filters": "Geen toetsfilters geconfigureerd", + "add-key-filter": "Sleutelfilter toevoegen", + "remove-key-filter": "Sleutelfilter verwijderen", + "edit-key-filter": "Sleutelfilter bewerken", + "date": "Datum", + "time": "Tijd", + "current-tenant": "Huidige tenant", + "current-customer": "Huidige klant", + "current-user": "Huidige gebruiker", + "current-device": "Huidig device", + "default-value": "Standaardwaarde", + "dynamic-source-type": "Dynamisch brontype", + "dynamic-value": "Dynamische waarde", + "no-dynamic-value": "Geen dynamische waarde", + "source-attribute": "Bron attribuut", + "switch-to-dynamic-value": "Overschakelen naar dynamische waarde", + "switch-to-default-value": "Overschakelen naar standaardwaarde", + "inherit-owner": "Erven van eigenaar", + "source-attribute-not-set": "Als het bronkenmerk niet is ingesteld" + }, + "fullscreen": { + "expand": "Uitvouwen naar volledig scherm", + "exit": "Volledig scherm afsluiten", + "toggle": "Modus voor volledig scherm in- en uitschakelen", + "fullscreen": "Volledig scherm" + }, + "function": { + "function": "Functie" + }, + "gateway": { + "add-entry": "Configuratie toevoegen", + "connector-add": "Nieuwe connector toevoegen", + "connector-enabled": "Connector inschakelen", + "connector-name": "Naam van de connector", + "connector-name-required": "De naam van de connector is vereist.", + "connector-type": "Type aansluiting", + "connector-type-required": "Het type connector is vereist.", + "connectors": "Configuratie van connectoren", + "create-new-gateway": "Een nieuwe gateway maken", + "create-new-gateway-text": "Weet u zeker dat u een nieuwe gateway wilt maken met de naam: '{{gatewayName}}'?", + "delete": "Configuratie verwijderen", + "download-tip": "Configuratiebestand downloaden", + "gateway": "Gateway", + "gateway-exists": "Device met dezelfde naam bestaat al.", + "gateway-name": "Naam van de gateway", + "gateway-name-required": "De naam van de gateway is vereist.", + "gateway-saved": "Gatewayconfiguratie succesvol opgeslagen.", + "json-parse": "Ongeldige JSON.", + "json-required": "Het veld mag niet leeg zijn.", + "no-connectors": "Geen connectoren", + "no-data": "Geen configuraties", + "no-gateway-found": "Geen gateway gevonden.", + "no-gateway-matching": "'{{item}}' niet gevonden.", + "path-logs": "Pad naar logbestanden", + "path-logs-required": "Pad is vereist.", + "remote": "Configuratie op afstand", + "remote-logging-level": "Registratie niveau", + "remove-entry": "Configuratie verwijderen", + "save-tip": "Configuratiebestand opslaan", + "security-type": "Soort beveiliging", + "security-types": { + "access-token": "Toegang tot token", + "tls": "TLS (TLS)" + }, + "storage": "Opslag", + "storage-max-file-records": "Maximum aantal records in bestand", + "storage-max-files": "Maximaal aantal bestanden", + "storage-max-files-min": "Minimum aantal is 1.", + "storage-max-files-pattern": "Nummer is niet geldig.", + "storage-max-files-required": "Nummer is vereist.", + "storage-max-records": "Maximum aantal records in opslag", + "storage-max-records-min": "Minimum aantal records is 1.", + "storage-max-records-pattern": "Nummer is niet geldig.", + "storage-max-records-required": "Maximale records zijn vereist.", + "storage-pack-size": "Maximale pakketgrootte voor events", + "storage-pack-size-min": "Minimum aantal is 1.", + "storage-pack-size-pattern": "Nummer is niet geldig.", + "storage-pack-size-required": "De maximale pakketgrootte van het event is vereist.", + "storage-path": "Opslag pad", + "storage-path-required": "Opslagpad is vereist.", + "storage-type": "Type opslag", + "storage-types": { + "file-storage": "Opslag van bestanden", + "memory-storage": "Geheugen opslag" + }, + "thingsboard": "Dingen Bord", + "thingsboard-host": "ThingsBoard-gastheer", + "thingsboard-host-required": "Server host is vereist.", + "thingsboard-port": "ThingsBoard-poort", + "thingsboard-port-max": "Het maximale poortnummer is 65535.", + "thingsboard-port-min": "Het minimale poortnummer is 1.", + "thingsboard-port-pattern": "Poort is niet geldig.", + "thingsboard-port-required": "Poort is vereist.", + "tidy": "Ordelijk", + "tidy-tip": "Opgeruimde configuratie JSON", + "title-connectors-json": "Configuratie van connector {{typeName}}", + "tls-path-ca-certificate": "Pad naar CA-certificaat op gateway", + "tls-path-client-certificate": "Pad naar clientcertificaat op gateway", + "tls-path-private-key": "Pad naar privésleutel op gateway", + "toggle-fullscreen": "Volledig scherm in- en uitschakelen", + "transformer-json-config": "Configuratie JSON*", + "update-config": "Configuratie JSON toevoegen/bijwerken" + }, + "grid": { + "delete-item-title": "Weet u zeker dat u dit item wilt verwijderen?", + "delete-item-text": "Opgelet, na de bevestiging zullen dit item en alle gerelateerde gegevens onherstelbaar worden.", + "delete-items-title": "Weet u zeker dat u { count, plural, =1 {1 item} andere {# items} } wilt verwijderen?", + "delete-items-action-title": "Verwijder { count, plural, =1 {1 item} andere {# items} }", + "delete-items-text": "Opgelet, na de bevestiging worden alle geselecteerde items verwijderd en kunnen alle gerelateerde gegevens niet meer worden hersteld.", + "add-item-text": "Nieuw item toevoegen", + "no-items-text": "Geen items gevonden", + "item-details": "Details van het artikel", + "delete-item": "Item verwijderen", + "delete-items": "Items verwijderen", + "scroll-to-top": "Scroll naar bovenzijde" + }, + "help": { + "goto-help-page": "Ga naar de helppagina", + "show-help": "Hulp tonen" + }, + "home": { + "home": "Thuis", + "profile": "Profiel", + "logout": "Logout", + "menu": "Menu", + "avatar": "Avatar", + "open-user-menu": "Gebruikersmenu openen" + }, + "file-input": { + "browse-file": "Blader door het bestand", + "browse-files": "Blader door bestanden" + }, + "image-input": { + "drop-image-or": "Een afbeelding slepen en neerzetten of", + "drop-images-or": "Sleep een afbeelding of", + "no-images": "Geen afbeeldingen geselecteerd", + "images": "beelden" + }, + "import": { + "no-file": "Geen bestand geselecteerd", + "drop-file": "Zet een JSON-bestand neer of klik om een bestand te selecteren om te uploaden.", + "drop-csv-file": "Zet een CSV-bestand neer of klik om een bestand te selecteren om te uploaden.", + "drop-json-file-or": "Een JSON-bestand slepen en neerzetten of", + "drop-file-csv": "Zet een CSV-bestand neer of klik om een bestand te selecteren om te uploaden.", + "drop-file-csv-or": "Een CSV-bestand slepen en neerzetten of", + "column-value": "Waarde", + "column-title": "Titel", + "column-example": "Voorbeeld van waardegegevens", + "column-key": "Kenmerk-/telemetriesleutel", + "credentials": "Geloofsbrief", + "csv-delimiter": "CSV-scheidingsteken", + "csv-first-line-header": "De eerste rule bevat kolomnamen", + "csv-update-data": "Attributen/telemetrie bijwerken", + "details": "Details", + "import-csv-number-columns-error": "Een bestand moet ten minste twee kolommen bevatten", + "import-csv-invalid-format-error": "Ongeldige bestandsindeling. Regel: '{{line}}'", + "column-type": { + "name": "Naam", + "type": "Type", + "label": "Etiket", + "column-type": "Type kolom", + "client-attribute": "Cliënt attribuut", + "shared-attribute": "Gedeeld attribuut", + "server-attribute": "Server-attribuut", + "timeseries": "Timeseries", + "entity-field": "Entiteit veld", + "access-token": "Toegang token", + "x509": "X.509", + "mqtt": { + "client-id": "MQTT-client-id", + "user-name": "MQTT-gebruikersnaam", + "password": "MQTT-wachtwoord" + }, + "lwm2m": { + "client-endpoint": "Naam van de LwM2M-endpoint", + "security-config-mode": "LwM2M-modus voor beveiligingsconfiguratie", + "client-identity": "Identiteit van LwM2M-client", + "client-key": "LwM2M-clientsleutel", + "client-cert": "Openbare sleutel van LwM2M-client", + "bootstrap-server-security-mode": "LwM2M bootstrap-serverbeveiligingsmodus", + "bootstrap-server-secret-key": "LwM2M bootstrap server geheime sleutel", + "bootstrap-server-public-key-id": "LwM2M opstarttrap, server openbare sleutel of id", + "lwm2m-server-security-mode": "LwM2M-server beveiligingsmodus", + "lwm2m-server-secret-key": "Geheime sleutel van de LwM2M-server", + "lwm2m-server-public-key-id": "Openbare sleutel of id van de LwM2M-server" + }, + "isgateway": "Is Gateway", + "activity-time-from-gateway-device": "Activiteitstijd vanaf gateway-device", + "description": "Omschrijving: __________", + "edge-license-key": "Licentiesleutel", + "cloud-endpoint": "Cloud-eindpunt", + "routing-key": "Edge routing sleutel", + "secret": "Edge geheim" + }, + "stepper-text": { + "select-file": "Selecteer een bestand", + "configuration": "Configuratie importeren", + "column-type": "Kolomtype selecteren", + "creat-entities": "Nieuwe entiteiten maken" + }, + "message": { + "create-entities": "{{count}} zijn met succes nieuwe entiteiten gecreëerd.", + "update-entities": "{{count}} entiteiten zijn bijgewerkt.", + "error-entities": "Er is een fout opgetreden bij het maken van {{count}} entiteiten." + } + }, + "integration": { + "integration": "Integratie", + "integrations": "Integraties", + "integrations-center": "Integratiecentrum", + "select-integration": "Selecteer integratie", + "no-integrations-matching": "Er zijn geen integraties gevonden die overeenkomen met '{{entity}}'.", + "integration-required": "Integratie is vereist", + "delete": "Integratie verwijderen", + "management": "Beheer van integraties", + "add-integration-text": "Nieuwe integratie toevoegen", + "no-integrations-text": "Geen integraties gevonden", + "selected-integrations": "{ count, plural, =1 {1 integration} andere {# integrations} } geselecteerd", + "delete-integration-title": "Weet je zeker dat je de integratie '{{integrationName}}' wilt verwijderen?", + "delete-integration-text": "Opgelet, na de bevestiging worden de integratie en alle gerelateerde gegevens onherstelbaar.", + "delete-integrations-title": "Weet u zeker dat u { count, plural, =1 {1 integration} andere {# integrations} } wilt verwijderen?", + "delete-integrations-action-title": "Verwijder { count, plural, =1 {1 integration} andere {# integrations} }", + "delete-integrations-text": "Opgelet, na de bevestiging worden alle geselecteerde integraties verwijderd en worden alle gerelateerde gegevens onherstelbaar.", + "events": "Events", + "enabled": "Integratie inschakelen", + "allow-create-devices-or-assets": "Devices of assets maken toestaan", + "all-types": "Alle integratietypes", + "add": "Integratie toevoegen", + "search": "Integraties zoeken", + "integration-details": "Details van de integratie", + "details": "Details", + "copyId": "Integratie-ID kopiëren", + "idCopiedMessage": "Integratie-id is gekopieerd naar klembord", + "debug-mode": "Foutopsporingsmodus", + "enable-security": "Beveiliging inschakelen", + "enable-security-new": "Beveiliging inschakelen voor automatische tokenupdates", + "headers-filter": "Filter voor kopteksten", + "header": "Rubriek", + "no-headers-filter": "Geen headers filter", + "downlink-url": "Downlink URL", + "downlink-url-required": "Downlink-URL is vereist", + "create-loriot-output": "Uitvoer van Loriot-toepassingen maken", + "send-downlink": "Downlink verzenden", + "server": "Server", + "server-required": "Server is vereist", + "domain": "Domein", + "app-id": "Toepassings-ID", + "app-id-required": "Toepassings-ID is vereist", + "app-token": "Token voor toegang tot toepassing", + "app-token-required": "Application Access Token is vereist", + "email": "E-mail", + "email-required": "E-mail is verplicht", + "application-uri": "Toepassings-URI", + "as-id": "AS ID", + "as-id-required": "AS-ID is vereist.", + "as-key": "AS-toets", + "as-key-required": "AS-sleutel is vereist.", + "client-id-new": "Client-ID", + "client-id-new-required": "Client-ID (login) is vereist (login).", + "client-secret": "Geheim van de klant", + "client-secret-required": "Client Secret (wachtwoord) is vereist (wachtwoord).", + "max-time-diff-in-seconds": "Maximaal tijdsverschil (seconden)", + "max-time-diff-in-seconds-required": "Maximaal tijdsverschil is vereist.", + "created-time": "Gecreëerde tijd", + "name": "Naam", + "name-required": "Naam is verplicht.", + "name-max-length": "Naam moet kleiner zijn dan 256 tekens", + "description": "Omschrijving: __________", + "base-url": "Basis-URL", + "base-url-required": "Basis-URL is vereist", + "security-key": "Beveiligingssleutel", + "http-endpoint": "URL van HTTP-eindpunt", + "replace-no-content-to-ok": "Vervang de reactiestatus van 'Geen inhoud' naar 'OK'", + "copy-http-endpoint-url": "Kopieer de URL van het HTTP-eindpunt", + "http-endpoint-url-copied-message": "De URL van het HTTP-eindpunt is gekopieerd naar het klembord", + "host": "Server host", + "host-required": "Server host is vereist.", + "host-private": "De host moet zich in het openbare netwerk bevinden.", + "url-private": "De URL moet zich in het openbare netwerk bevinden.", + "host-type": "Type host", + "host-type-required": "Hosttype is vereist.", + "api-version": "API v3 gebruiken", + "custom-host": "Aangepaste host", + "custom-host-required": "Aangepaste host is vereist.", + "port": "Poort", + "port-required": "Poort is vereist.", + "port-range": "De poort moet tussen 1 en 65535 liggen.", + "connect-timeout": "Time-out verbinding (sec)", + "connect-timeout-required": "Er is een time-out voor de verbinding vereist.", + "connect-timeout-range": "De time-out van de verbinding moet tussen 1 en 200 liggen.", + "client-id": "Client-ID", + "client-id-required": "Client-ID is vereist.", + "client-id-range": "Client-ID moet tussen de 1 en 23 tekens lang zijn. [MQTT-3.1.3-5]", + "client-id-pattern": "Client-ID moet bestaan uit cijfers, hoofdletters en kleine letters. [MQTT-3.1.3-5]", + "client-id-hint": "Tip: Optioneel. Laat dit veld leeg voor automatisch gegenereerde client-ID. Opgelet bij het opgeven van de Client ID. De meerderheid van de MQTT-brokers staat niet toe dat meerdere verbindingen met dezelfde client-ID worden gebruikt. Om verbinding te maken met dergelijke makelaars, moet uw MQTT-klant-ID uniek zijn.", + "max-bytes-in-message": "Max. aantal bytes in bericht", + "max-bytes-in-message-range": "Het maximale aantal bytes in een bericht moet tussen 1 en 256000000 liggen.", + "device-id": "Device-ID", + "device-id-required": "Device-ID is vereist.", + "device-id-range": "Device-ID moet tussen 1 en 65535 tekens bestaan.", + "device-id-pattern": "Device-ID moet bestaan uit cijfers, hoofdletters en kleine letters. [MQTT-3.1.3-5]", + "group-id": "Groeps-ID", + "group-id-required": "Groeps-ID is vereist.", + "topics": "Onderwerpen", + "topics-required": "Onderwerp is vereist.", + "routing-keys": "Routing sleutels", + "routing-keys-required": "Routingsleutel is vereist.", + "queues": "Queues", + "queues-required": "De naam van de queue is vereist.", + "durable": "Duurzaam", + "exclusive": "Exclusief", + "autoDelete": "Automatisch verwijderen", + "exchange-name": "Naam van de uitwisseling", + "exchange-name-required": "De naam van de uitwisseling is vereist.", + "downlink-topic": "Downlink-onderwerp", + "connection-timeout": "Time-out van de verbinding, ms", + "connection-timeout-min": "Ongeldige time-outwaarde voor verbinding.", + "handshake-timeout": "Time-out voor handdruk, ms", + "handshake-timeout-min": "Ongeldige time-outwaarde voor handdruk.", + "virtual-host": "Virtuele gastheer", + "rabbit-mq-poll-interval": "Polling-interval, ms", + "rabbit-mq-poll-interval-min": "Ongeldige waarde voor de polling-interval.", + "application-server-url": "URL van applicatieserver", + "application-server-url-required": "De URL van de toepassingsserver is vereist.", + "application-server-api-token": "API-token voor toepassingsserver", + "application-server-api-token-required": "API-token van toepassingsserver is vereist.", + "bootstrap-servers": "Bootstrap-servers", + "bootstrap-servers-required": "Bootstrap-servers zijn vereist.", + "poll-interval": "Poll-interval", + "poll-interval-required": "Poll-interval is vereist.", + "poll-interval-min-value": "De waarde van het pollinterval mag niet kleiner zijn dan 1", + "auto-create-topics": "Onderwerpen automatisch maken", + "clean-session": "Vernieuwde sessie", + "enable-ssl": "SSL inschakelen", + "credentials": "Inloggegevens", + "credentials-type": "Type referenties", + "credentials-type-required": "Het type referentie is vereist.", + "username": "Gebruikersnaam", + "username-required": "Gebruikersnaam is vereist.", + "password": "Wachtwoord", + "password-required": "Wachtwoord is vereist.", + "azure-ca-cert": "CA-certificaatbestand", + "ca-cert": "CA-certificaatbestand", + "private-key": "Bestand met privésleutel", + "private-key-password": "Wachtwoord voor privésleutel", + "cert": "Certificaat bestand", + "no-file": "Geen bestand geselecteerd.", + "drop-file": "Zet een bestand neer of klik om een bestand te selecteren om te uploaden.", + "drop-file-or": "Een bestand slepen en neerzetten of", + "check-connection": "Verbinding controleren", + "check-success": "Verbinding tot stand gebracht.", + "topic-filters": "Onderwerp filters", + "remove-topic-filter": "Onderwerpfilter verwijderen", + "add-topic-filter": "Onderwerpfilter toevoegen", + "add-topic-filter-prompt": "Voeg een onderwerpfilter toe", + "topic": "Onderwerp", + "mqtt-qos": "QoS", + "mqtt-qos-at-most-once": "Hoogstens één keer", + "mqtt-qos-at-least-once": "Minstens één keer", + "mqtt-qos-exactly-once": "Precies één keer", + "downlink-topic-pattern": "Patroon voor downlinkonderwerpen", + "downlink-topic-pattern-required": "Downlink-onderwerppatroon is vereist.", + "retained-message": "Behouden", + "aws-access-key-id": "AWS-toegangssleutel-ID", + "aws-secret-access-key": "Geheime AWS-toegangssleutel", + "aws-region": "Regio", + "aws-iot-endpoint": "AWS IoT-eindpunt", + "aws-iot-endpoint-required": "AWS IoT Endpoint is vereist.", + "aws-iot-credentials": "AWS IoT-referenties", + "aws-sqs-polling-period-in-seconds": "Pollingperiode in seconden", + "aws-sqs-queue-url": "URL van SQS-queue", + "aws-sqs-queue-url-required": "SQS Queue URL is vereist", + "aws-sqs-access-key-id-required": "Toegangssleutel-ID is vereist", + "aws-sqs-secret-access-key-required": "Geheime toegangssleutel is vereist", + "application-credentials": "Aanmeldingsgegevens van de toepassing", + "api-key": "API-sleutel", + "api-key-required": "API-sleutel is vereist.", + "api-key-format": "Ongeldige API-sleutelindeling.", + "auth-token": "Authenticatie token", + "auth-token-required": "Verificatietoken is vereist.", + "region": "Regio", + "region-required": "Regio is vereist.", + "application-id": "Toepassings-ID", + "application-id-required": "Toepassings-ID is vereist.", + "access-id": "Toegangs-ID", + "access-id-required": "Toegangs-ID is vereist.", + "access-key": "Toegangssleutel", + "access-key-required": "Toegangssleutel is vereist.", + "access-key-min-length": "Toegangssleutel is te kort.", + "access-key-max-length": "Toegangssleutel is te lang.", + "connection-parameters": "Verbinding parameters", + "service-bus-namespace-name": "Naam van Service Bus-namespace", + "service-bus-namespace-name-required": "Service Bus-namespace naam is vereist.", + "connection-string": "Connectionstring", + "consumer-group": "Consumentengroep", + "connection-string-required": "Aansluitreeks vereist!", + "event-hub-name": "Naam Event Hub", + "event-hub-name-required": "Event Hub-naam is vereist.", + "event-iot-hub-name-required": "Iot Hub-naam is vereist voor downlink", + "sas-key-name": "SAS-sleutelnaam", + "sas-key-name-required": "SAS-sleutelnaam is vereist.", + "sas-key": "SAS-toets", + "sas-key-required": "SAS-sleutel is vereist.", + "iot-hub-name": "IoT Hub-naam (vereist voor downlink)", + "hostname": "Hostnaam", + "hostname-required": "Hostnaam is vereist", + "integration-clazz": "Integratie klasse", + "integration-clazz-required": "Integratie klasse is vereist", + "integration-configuration": "Integratie JSON-configuratie", + "metadata": "Metagegevens", + "type": "Type integratie", + "select-integration-type": "Selecteer integratietype", + "type-required": "Integratietype is vereist.", + "type-not-found": "Integratietype niet gevonden", + "uplink-converter": "Uplink data converter", + "uplink-converter-required": "Uplink-gegevensconverter is vereist.", + "downlink-converter": "Downlink data converter", + "type-http": "HTTP (HTTP)", + "type-http-description": "Protocol voor het overbrengen van tekst- of multimediabestanden.", + "type-ocean-connect": "Oceaan verbinden", + "type-ocean-connect-description": "Integratie van devices met verschillende mogelijkheden met het IoT-platform.", + "type-sigfox": "SigFox", + "type-sigfox-description": "Lichtgewicht protocol voor het verwerken van kleine gegevensoverdrachten.", + "type-thingpark": "ThingPark", + "type-thingpark-description": "Berichtgeoriënteerd protocol voor transportlagen.", + "type-loriot": "Loriot", + "type-loriot-description": "Gedistribueerde LoRaWAN-infrastructuur.", + "type-thingpark-enterprise": "ThingParkEnterprise", + "type-thingpark-enterprise-description": "Berichtenplatform voor het LPWA-netwerk.", + "type-tmobile-iot-cdp": "iotcreators.com (T-Mobile – IoT CDP)", + "type-tmobile-iot-cdp-description": "Mobiele IoT-connectiviteitsservice.", + "type-mqtt": "MQTT", + "type-mqtt-description": "Netwerkprotocol van machine naar machine.", + "type-aws-iot": "AWS IoT", + "type-aws-iot-description": "Beheer-, opslag- en analyseservice.", + "type-aws-sqs": "AWS SQS", + "type-aws-sqs-description": "Volledig beheerde message queuing-service.", + "type-aws-kinesis": "AWS-kinesis", + "type-aws-kinesis-description": "Service voor real-time video- en datastreams.", + "type-ibm-watson-iot": "IBM Watson IoT", + "type-ibm-watson-iot-description": "Volledig beheerde, in de cloud gehoste service.", + "type-ttn": "De Things Stack-gemeenschap", + "type-ttn-description": "Open en gedecentraliseerd LoRaWAN-netwerk.", + "type-tti": "De dingen stapelen industrieën", + "type-tti-description": "Software om private LoRaWAN-netwerken op grote schaal te exploiteren.", + "type-chirpstack": "ChirpStack", + "type-chirpstack-description": "LoRaWAN-netwerkconfiguratieserver.", + "type-azure-event-hub": "Azure Event Hub", + "type-azure-event-hub-description": "Big data-streamingplatform en service voor het opnemen van events.", + "type-azure-iot-hub": "Azure IoT Hub", + "type-azure-iot-hub-description": "In de cloud gehoste berichtenservice.", + "type-opc-ua": "OPC-UA", + "type-opc-ua-description": "Cross-platform voor gegevensuitwisseling van sensoren naar cloud-apps.", + "type-custom": "Gewoonte", + "type-coap": "CoAP", + "type-coap-description": "Netwerkprotocol van machine naar machine voor beperkte Devices.", + "type-udp": "UDP", + "type-udp-description": "Berichtgeoriënteerd protocol voor transportlagen.", + "type-tcp": "TCP", + "type-tcp-description": "Verbindingsgericht protocol.", + "type-kafka": "Kafka", + "type-kafka-description": "Streaming analytics, data-integratie streaming platform.", + "type-rabbitmq": "KonijnMQ", + "type-rabbitmq-description": "Berichtenbroker die ondersteuning biedt voor meerdere berichtenprotocollen.", + "type-pubsub": "Kroeg/Sub", + "type-pubsub-description": "Service voor asynchrone berichten tussen apps.", + "type-apache-pulsar": "Apache Pulsar", + "type-apache-pulsar-description": "Gedistribueerd pub-sub berichten- en streamingplatform.", + "type-tuya": "Tuya", + "type-tuya-description": "In de cloud gehoste berichten. platform van het device.", + "type-azure-service-bus": "Azure Service Bus", + "type-azure-service-bus-description": "Volledig beheerde berichtenmakelaar voor ondernemingen met berichtwachtrijen en onderwerpen voor publiceren en abonneren.", + "opc-ua-application-name": "Naam van de toepassing", + "opc-ua-application-uri": "Applicatie uri", + "opc-ua-scan-period-in-seconds": "Scanperiode in seconden", + "opc-ua-scan-period-in-seconds-required": "Scanperiode is vereist", + "opc-ua-timeout": "Time-out in milliseconden", + "opc-ua-timeout-required": "Time-out is vereist", + "opc-ua-security": "Veiligheid", + "opc-ua-security-required": "Beveiliging is vereist", + "opc-ua-identity": "Identiteit", + "opc-ua-identity-required": "Legitimatie is vereist", + "opc-ua-keystore": "Sleutel opslag", + "add-opc-ua-keystore-prompt": "Gelieve keystore-bestand toe te voegen", + "opc-ua-keystore-required": "Keystore is vereist", + "opc-ua-type": "Type", + "opc-ua-keystore-type": "Type", + "opc-ua-keystore-type-required": "Type is vereist", + "opc-ua-keystore-location": "Plaats*", + "opc-ua-keystore-password": "Wachtwoord", + "opc-ua-keystore-password-required": "Wachtwoord is vereist", + "opc-ua-keystore-alias": "Alias", + "opc-ua-keystore-alias-required": "Alias is vereist", + "opc-ua-keystore-key-password": "Sleutel wachtwoord", + "opc-ua-keystore-key-password-required": "Sleutelwachtwoord is vereist", + "opc-ua-mapping": "Kartering", + "add-opc-ua-mapping-prompt": "Gelieve kaarten toe te voegen", + "opc-ua-mapping-type": "Type toewijzing", + "opc-ua-mapping-type-required": "Toewijzingstype is vereist", + "opc-ua-device-node-pattern": "Patroon van apparaatknooppunten", + "opc-ua-device-node-pattern-required": "Apparaatknooppuntpatroon is vereist", + "opc-ua-namespace": "Naamruimte", + "opc-ua-add-map": "Toewijzingselement toevoegen", + "kinesis-stream-name": "Naam van de stream", + "kinesis-stream-name-required": "Streamnaam is vereist", + "kinesis-region": "Regio", + "kinesis-region-required": "Regio is vereist", + "kinesis-access-key-id": "Toegangssleutel-ID", + "kinesis-access-key-id-required": "Toegangssleutel-ID is vereist", + "kinesis-secret-access-key": "Geheime toegangssleutel", + "kinesis-secret-access-key-required": "Geheime toegangssleutel is vereist", + "kinesis-use-consumers-with-enhanced-fan-out": "Gebruik consumenten met verbeterde fan-out", + "kinesis-use-credentials-from-instance-metadata": "Referenties van de Amazon EC2 Instance Metadata Service gebruiken", + "kinesis-application-name": "Toepassingsnaam (standaard gelijk aan Streamnaam)", + "kinesis-initial-position-in-stream": "Beginpositie in stream", + "kinesis-initial-position-in-stream-required": "Beginpositie in stream vereist", + "kinesis-max-records": "Max. records", + "kinesis-max-records-required": "Max. records is vereist", + "kinesis-max-records-length-range": "De maximale recordlengte moet tussen 1 en 10000 liggen", + "kinesis-request-timeout": "Time-out aanvragen in enkele seconden", + "kinesis-request-timeout-required": "Time-out voor aanvraag is vereist", + "other-properties": "Overige eigenschappen", + "subscription-tags": "Tags voor abonnementen", + "remove-subscription-tag": "Abonnementstag verwijderen", + "add-subscription-tag": "Abonnementstag toevoegen", + "add-subscription-tag-prompt": "Voeg een abonnementstag toe", + "key": "Sleutel", + "path": "Pad", + "required": "Vereist", + "integration-key": "Integratiesleutel", + "copy-integration-key": "Integratiesleutel kopiëren", + "integration-key-copied-message": "Integratiesleutel is gekopieerd naar klembord", + "integration-secret": "Integratie geheim", + "copy-integration-secret": "Integratiegeheim kopiëren", + "integration-secret-copied-message": "Integratiegeheim is gekopieerd naar klembord", + "execute-remotely": "Op afstand uitvoeren", + "remote": "Afgelegen", + "handler-configuration": "Configuratie van de handler", + "handler-configuration-type": "Handler Type", + "so-broadcast": "Uitzending inschakelen - integratie accepteert uitzendadrespakketten", + "so-keepalive-option": "Verzenden van keep-alive-berichten op verbindingsgeoriënteerde stopcontacten mogelijk maken", + "so-reuse-addr": "Bind het proces aan een poort", + "tcp-no-delay": "Dwingt een socket om de gegevens te verzenden zonder buffering (schakel het bufferalgoritme van Nagle uit)", + "fail-fast": "Gegooide uitzondering zodra de decoder merkt dat de lengte van het frame de maximale grootte zal overschrijden", + "strip-delimiter": "Scheidingsteken voor stroken", + "length-field-offset": "Lengte veld offset", + "length-field-offset-required": "Lengte veldverschuiving is vereist.", + "length-field-offset-range": "De lengteveldverschuiving moet tussen 0 en 8 liggen.", + "length-field-length": "Lengte Veldlengte", + "length-field-length-required": "Lengte Veldlengte is vereist.", + "length-field-length-range": "Lengte Veldlengte moet tussen 0 en 8 liggen.", + "length-adjustment": "Lengteaanpassing (de compensatiewaarde die moet worden toegevoegd aan de waarde van het lengteveld)", + "length-adjustment-required": "Lengteaanpassing is vereist.", + "length-adjustment-range": "De lengte-aanpassing moet tussen 0 en 8 liggen.", + "byte-order": "Byte Volgorde van het lengteveld", + "initial-bytes-to-strip": "Aantal eerste bytes dat uit het gedecodeerde frame moet worden verwijderd", + "initial-bytes-to-strip-required": "Het aantal eerste bytes dat uit het gedecodeerde frame moet worden verwijderd, is vereist.", + "initial-bytes-to-strip-range": "Het aantal eerste bytes dat uit het gedecodeerde frame moet worden verwijderd, moet tussen 0 en 8 liggen.", + "so-backlog-option": "Max. aantal in behandeling zijnde verbindingen op het stopcontact", + "so-backlog-option-required": "Het maximale aantal in behandeling zijnde verbindingen op het stopcontact is vereist.", + "so-backlog-option-range": "Het maximale aantal in behandeling zijnde verbindingen op het stopcontact moet tussen 1 en 65535 liggen.", + "so-rcv-buf": "Grootte van de buffer voor inkomende socket (in KB)", + "so-rcv-buf-required": "De grootte van de buffer voor de inkomende socket (in KB) is vereist.", + "so-rcv-buf-range": "De grootte van de buffer voor inkomende socket (in KB) moet tussen 1 en 65535 liggen.", + "so-snd-buf": "Grootte van de buffer voor uitgaande socket (in KB)", + "so-snd-buf-required": "De grootte van de buffer voor uitgaande socket (in KB) is vereist.", + "so-snd-buf-range": "De grootte van de buffer voor uitgaande socket (in KB) moet tussen 1 en 65535 liggen.", + "charset-name": "Naam van de set", + "charset-name-required": "Charset-naam is vereist.", + "message-separator": "Scheidingsteken voor berichten", + "message-separator-required": "Berichtenscheidingsteken is vereist.", + "character-sequence": "Karakter Volgorde", + "character-sequence-required": "Tekenvolgorde is vereist.", + "max-frame-length": "Maximale framelengte (in bytes)", + "max-frame-length-required": "Maximale framelengte (in bytes) is vereist.", + "max-frame-length-range": "De maximale framelengte (in bytes) moet tussen 1 en 65535 liggen.", + "handler-type": "Handler Type", + "message-size": "Grootte van het bericht", + "message-size-required": "Berichtgrootte is vereist.", + "service-url": "URL van de dienst", + "service-url-required": "Service-URL is vereist.", + "subscription-name": "Naam van het abonnement", + "subscription-name-required": "De naam van het abonnement is vereist.", + "max-num-messages": "Max. aantal berichten", + "max-num-messages-required": "Het maximale aantal berichten is vereist.", + "max-num-bytes": "Max. aantal bytes", + "max-num-bytes-required": "Maximaal aantal bytes vereist.", + "timeout-in-ms": "Time-out in milliseconden", + "timeout-in-ms-required": "Time-out in milliseconden is vereist.", + "user-id": "Gebruikersnaam", + "user-id-required": "Gebruikersnaam is vereist.", + "token": "Teken", + "token-required": "Token is vereist.", + "project-id": "Project-ID", + "project-id-required": "Project-ID is vereist.", + "subscription-id": "Abonnements-ID", + "subscription-id-required": "Abonnements-ID is vereist.", + "service-account-key": "Sleutelbestand voor serviceaccount", + "service-account-key-required": "Het sleutelbestand van het serviceaccount is vereist.", + "tcp": { + "system-line-separator": "Systeem Lijnscheider", + "nul-delimiter": "Nul-scheidingsteken", + "byte-order-little-endian": "Kleine Endian", + "byte-order-big-endian": "Grote Endian" + }, + "cache-size": "Cache-grootte", + "cache-time-to-live": "Cachetijd om in minuten te leven", + "min-cache-size": "Cachegrootte kan niet lager zijn 0", + "min-cache-time-to-live": "Cache tijd om te leven kan niet lager zijn 0", + "max-cache-time-to-live": "Ongeldige tijd van cache live, kies tussen 0 en 525600", + "coap-security-mode": "Beveiligingsmodus", + "coap-security-mode-required": "CoAP-beveiligingsmodus is vereist", + "coap-security-mode-no-secure": "NIET VEILIG", + "coap-security-mode-dtls": "DTLS", + "coap-security-mode-mixed": "GEMENGD", + "coap-endpoint": "URL van CoAP-eindpunt", + "coap-endpoint-url-copied-message": "De URL van het CoAP-eindpunt is gekopieerd naar het klembord", + "copy-coap-endpoint-url": "Kopieer de URL van het CoAP-eindpunt", + "copy-coap-dtls-endpoint-url": "Kopieer de URL van het CoAP DTLS-eindpunt", + "coap-dtls-base-url": "DTLS-basis-URL", + "coap-dtls-base-url-required": "DTLS-basis-URL is vereist", + "coap-dtls-endpoint": "URL van CoAP DTLS-eindpunt", + "coap-dtls-endpoint-url-copied-message": "De URL van het CoAP DTLS-eindpunt is gekopieerd naar het klembord", + "unassign-integration-title": "Weet je zeker dat je de toewijzing van de integratie '{{integrationName}}' ongedaan wilt maken?", + "unassign-integration-from-edge-text": "Na de bevestiging wordt de toewijzing van de integratie ongedaan gemaakt en is deze niet toegankelijk voor de edge.", + "unassign-integrations-from-edge-title": "Weet u zeker dat u de toewijzing van { count, plural, =1 {1 integration} andere {# integrations} } wilt opheffen?", + "unassign-integrations-from-edge-text": "Na de bevestiging worden alle geselecteerde integraties ongedaan gemaakt en zijn ze niet toegankelijk voor de edge.", + "unassign-integrations": "Toewijzing van integraties ongedaan maken", + "edge-placeholder-hint": "U kunt tijdelijke aanduiding ${{ATTRIBUTE_KEY}} gebruiken om het integratieveld te vervangen door de kenmerkwaarde van een specifieke Edge-entiteit. 'Edge A' heeft bijvoorbeeld het kenmerk 'baseUrl' dat gelijk is aan 'http://localhost:9999'. U kunt $ {{baseUrl}} instellen als een van de integratievelden, en het wordt vervangen door 'http://localhost:9999' tijdens de toewijzing van deze integratie aan 'Edge A'. Bovendien, als 'Edge A' attribuut 'baseUrl' wordt bijgewerkt, wordt de integratie met de nieuwe bijgewerkte waarde automatisch ingericht voor 'Edge A'.", + "status": { + "status": "Status", + "active": "Actief", + "disabled": "Invalide", + "failed": "Mislukt", + "pending": "In behandeling" + }, + "daily-activity": "Dagelijkse activiteit", + "enable-debug-mode": "Foutopsporingsmodus inschakelen", + "disable-debug-mode": "Schakel de foutopsporingsmodus uit", + "advanced-settings": "Geavanceerde instellingen", + "basic-settings": "Basisinstellingen", + "existing-uplink-converter": "Selecteer een bestaande uplink-gegevensconverter", + "new-uplink-converter": "Maak een nieuwe uplink-gegevensconverter", + "existing-downlink-converter": "Selecteer een bestaande downlink-gegevensconverter", + "new-downlink-converter": "Maak een nieuwe downlink-gegevensconverter", + "connection": "Verbinding", + "connected": "Verbonden", + "not-connected": "Niet verbonden", + "environment": "Milieu", + "environment-required": "Omgeving is vereist.", + "region-cn": "China", + "region-us": "Verenigde Staten", + "region-eu": "Europa", + "region-in": "India", + "topic-name": "Naam van het onderwerp", + "topic-name-required": "Onderwerpnaam is verplicht", + "sub-name": "Naam van het abonnement", + "sub-name-required": "De naam van het abonnement is vereist", + "downlink-connection-string": "Downlink-verbindingsreeks", + "downlink-connection-string-required": "Downlink-verbindingsreeks is vereist", + "downlink-topic-name": "Naam van downlink-onderwerp", + "downlink-topic-name-required": "De naam van het downlink-onderwerp is vereist" + }, + "item": { + "selected": "Geselecteerd" + }, + "js-func": { + "no-return-error": "Functie moet waarde teruggeven.", + "return-type-mismatch": "Functie moet waarde van het type '{{type}}' teruggeven.", + "tidy": "Ordelijk", + "mini": "Mini" + }, + "key-val": { + "key": "Sleutel", + "value": "Waarde", + "remove-entry": "Invoer verwijderen", + "add-entry": "Invoer toevoegen", + "no-data": "Geen inzendingen" + }, + "layout": { + "layout": "Indeling", + "manage": "Lay-outs beheren", + "settings": "Lay-out instellingen", + "color": "Kleur", + "main": "Voornaamste", + "right": "Rechts", + "left": "Links", + "select": "Doellay-out selecteren", + "percentage-width": "Percentage breedte (%)", + "fixed-width": "Vaste breedte (px)", + "left-width": "Linkerkolom (%)", + "right-width": "Rechterkolom (%)", + "pick-fixed-side": "Vaste zijde:", + "layout-fixed-width": "Vaste breedte (px)", + "value-min-error": "Waarde moet meer zijn dan {{min}}{{unit}}", + "value-max-error": "De waarde moet lager zijn dan {{max}}{{unit}}", + "layout-fixed-width-required": "Vaste breedte is vereist", + "right-width-percentage-required": "Het juiste percentage is vereist", + "left-width-percentage-required": "Linker percentage is vereist", + "divider": "Scheidingslijn", + "right-side": "Indeling rechterkant", + "left-side": "Lay-out aan de linkerkant" + }, + "legend": { + "direction": "Richting van de legende", + "position": "Legende positie", + "sort-legend": "Datakeys sorteren in legende", + "show-max": "Maximale waarde weergeven", + "show-min": "Minimale waarde weergeven", + "show-avg": "Gemiddelde waarde weergeven", + "show-total": "Totale waarde weergeven", + "show-latest": "Toon laatste waarde", + "settings": "Legende-instellingen", + "min": "Min", + "max": ".max", + "avg": "Avg", + "total": "totaal", + "latest": "laatst", + "comparison-time-ago": { + "previousInterval": "(vorig interval)", + "customInterval": "(aangepast interval)", + "days": "(dag geleden)", + "weeks": "(week geleden)", + "months": "(maand geleden)", + "years": "(jaar geleden)" + } + }, + "login": { + "login": "Inloggen", + "request-password-reset": "Verzoek om wachtwoordreset", + "reset-password": "Wachtwoord opnieuw instellen", + "create-password": "Wachtwoord maken", + "two-factor-authentication": "Twee-factor-authenticatie", + "passwords-mismatch-error": "Ingevoerde wachtwoorden moeten hetzelfde zijn.", + "password-again": "Wachtwoord opnieuw ingeven", + "sign-in": "Gelieve in te loggen", + "username": "Gebruikersnaam (e-mail)", + "remember-me": "Onthoud mij", + "forgot-password": "Wachtwoord vergeten?", + "password-reset": "Wachtwoord opnieuw instellen", + "expired-password-reset-message": "Uw inloggegevens zijn verlopen. Gelieve een nieuwe wachtwoord aan te maken.", + "new-password": "Nieuw wachtwoord", + "new-password-again": "Bevestig nieuw wachtwoord", + "password-link-sent-message": "Reset-link is verzonden", + "email": "E-mail", + "no-account": "Heb je nog geen account?", + "create-account": "Maak een account aan", + "login-with": "Log in met {{name}}", + "or": "of", + "error": "Fout bij inloggen", + "verify-your-identity": "Verifieer uw identiteit", + "select-way-to-verify": "Selecteer een manier om te verifiëren", + "resend-code": "Code opnieuw verzenden", + "resend-code-wait": "Code opnieuw verzenden in { time, plural, =1 {1 second} andere {# seconds} }", + "try-another-way": "Probeer een andere manier", + "totp-auth-description": "Voer de beveiligingscode van je authenticator-app in.", + "totp-auth-placeholder": "Code", + "sms-auth-description": "Er is een beveiligingscode naar je telefoon gestuurd om {{contact}}.", + "sms-auth-placeholder": "SMS-code", + "email-auth-description": "Er is een beveiligingscode verzonden naar uw e-mailadres op {{contact}}.", + "email-auth-placeholder": "E-mail code", + "backup-code-auth-description": "Voer een van uw back-upcodes in.", + "backup-code-auth-placeholder": "Back-up code" + }, + "signup": { + "firstname": "Voornaam", + "lastname": "Achternaam", + "email": "E-mail", + "signup": "Inschrijven", + "create-password": "Maak een wachtwoord aan", + "repeat-password": "Herhaal je wachtwoord", + "have-account": "Heb je al een account?", + "signin": "Aanmelden", + "no-captcha-message": "U moet bevestigen dat u geen robot bent", + "password-length-message": "Uw wachtwoord moet minimaal 6 tekens lang zijn", + "email-verification": "E-mail verificatie", + "email-verification-message": "Er is een e-mail met verificatiegegevens verzonden naar het opgegeven e-mailadres.
Volg de instructies in de e-mail om uw aanmeldingsprocedure te voltooien.
Let op: als je de e-mail al een tijdje niet hebt gezien, controleer dan je map 'spam' of probeer de e-mail opnieuw te verzenden door op de knop 'Opnieuw verzenden' te klikken.", + "account-activation-title": "Account activeren", + "account-activated": "Account succesvol geactiveerd!", + "account-activated-text": "Gefeliciteerd!
Uw account is geactiveerd.", + "resend": "Verzenden", + "inactive-user-exists-title": "Inactieve gebruiker bestaat al", + "inactive-user-exists-text": "Er is al een geregistreerde gebruiker met een niet-geverifieerd e-mailadres.
Klik op de knop 'Opnieuw verzenden' als u de verificatie-e-mail opnieuw wilt verzenden.", + "activating-account": "Account activeren...", + "activating-account-text": "Uw account wordt momenteel geactiveerd. Een ogenblik geduld...", + "accept-privacy-policy": "Accepteer het privacybeleid", + "accept": "Accepteren", + "privacy-policy": "Privacybeleid", + "accept-privacy-policy-message": "U moet ons privacybeleid accepteren", + "recaptcha-title": "reCAPTCHA", + "terms-of-use": "Gebruiksvoorwaarden", + "accept-terms-of-use-message": "U moet onze Gebruiksvoorwaarden accepteren" + }, + "notification": { + "action-button": "Actieknop", + "action-type": "Soort actie", + "active": "Actief", + "add-notification-recipients-group": "Groep voor ontvangers van meldingen toevoegen", + "add-notification-template": "Meldingssjabloon toevoegen", + "add-recipient": "Ontvanger toevoegen", + "add-recipients": "Geadresseerden toevoegen", + "add-rule": "Regel toevoegen", + "add-stage": "Fase toevoegen", + "add-template": "Sjabloon toevoegen", + "after": "Na", + "alarm-assignment-trigger-settings": "Triggerinstellingen voor alarmtoewijzing", + "alarm-comment-trigger-settings": "Instellingen voor triggers voor alarmreacties", + "alarm-trigger-settings": "Instellingen alarmtrigger", + "all": "Alle", + "api-feature-hint": "Als het veld leeg is, wordt de trigger toegepast op alle api-functies", + "api-usage-trigger-settings": "Instellingen voor API-gebruikstrigger", + "new-platform-version-trigger-settings": "Triggerinstellingen voor nieuwe platformversie", + "at-least-one-should-be-selected": "Er moet er ten minste één worden geselecteerd", + "basic-settings": "Basisinstellingen", + "button-text": "Tekst van de knop", + "button-text-required": "Knoptekst is vereist", + "button-text-max-length": "De tekst van de knop moet kleiner zijn dan of gelijk zijn aan {{ length }} tekens", + "compose": "Samenstellen", + "conversation": "Gesprek", + "conversation-required": "Gesprek is vereist", + "copy-notification-template": "Meldingssjabloon kopiëren", + "copy-rule": "Regel kopiëren", + "copy-template": "Kopieer sjabloon", + "create-new": "Nieuwe maken", + "created": "Geschapen", + "delete-notification-text": "Opgelet, na de bevestiging wordt de melding onherstelbaar.", + "delete-notification-title": "Weet je zeker dat je de melding wilt verwijderen?", + "delete-notifications-text": "Opgelet, na de bevestiging worden meldingen onherstelbaar.", + "delete-notifications-title": "Weet u zeker dat u { count, plural, =1 {1 notification} andere {# notifications} } wilt verwijderen?", + "delete-recipient-text": "Let op, na de bevestiging wordt de ontvanger onherstelbaar.", + "delete-recipient-title": "Weet u zeker dat u de '{{recipientName}}' van de ontvanger wilt verwijderen?", + "delete-recipients-text": "Opgelet, na de bevestiging worden ontvangers onherstelbaar.", + "delete-recipients-title": "Weet u zeker dat u { count, plural, =1 {1 recipient} andere {# recipients} } wilt verwijderen?", + "delete-request-text": "Opgelet, na het bevestigingsverzoek wordt het onherstelbaar.", + "delete-request-title": "Weet je zeker dat je een verzoek wilt verwijderen?", + "delete-requests-text": "Opgelet, na de bevestiging worden verzoeken onherstelbaar.", + "delete-requests-title": "Weet u zeker dat u { count, plural, =1 {1 request} andere {# requests} } wilt verwijderen?", + "delete-rule-text": "Opgelet, nadat de bevestigingsregel onherstelbaar wordt.", + "delete-rule-title": "Weet u zeker dat u rule '{{ruleName}}' wilt verwijderen?", + "delete-rules-text": "Opgelet, na de bevestiging worden de regels onherstelbaar.", + "delete-rules-title": "Weet u zeker dat u { count, plural, =1 {1 rule} andere {# rules} } wilt verwijderen?", + "delete-template-text": "Opgelet, nadat de bevestigingssjabloon onherstelbaar wordt.", + "delete-template-title": "Weet u zeker dat u sjabloon '{{templateName}}' wilt verwijderen?", + "delete-templates-text": "Opgelet, nadat de bevestigingssjablonen onherstelbaar zijn geworden.", + "delete-templates-title": "Weet u zeker dat u { count, plural, =1 {1 template} andere {# templates} } wilt verwijderen?", + "deleted": "Verwijderd", + "delivery-method": { + "delivery-method": "Wijze van levering", + "email": "E-mail", + "email-preview": "Voorbeeld van e-mailmelding", + "slack": "Los", + "slack-preview": "Voorbeeld van Slack-melding", + "sms": "SMS", + "sms-preview": "Voorbeeld van sms-melding", + "web": "Web", + "web-preview": "Voorbeeld van webmelding" + }, + "delivery-method-not-configure-click": "De leveringsmethode is niet geconfigureerd. Klik om in te stellen.", + "delivery-method-not-configure-contact": "De leveringsmethode is niet geconfigureerd. Neem contact op met uw systeembeheerder.", + "delivery-methods": "Levering methodes", + "description": "Omschrijving: __________", + "device-activity-trigger-settings": "Triggerinstellingen voor actieve devices", + "device-list-rule-hint": "Als het veld leeg is, wordt de trigger toegepast op alle devices", + "device-profiles-list-rule-hint": "Als het veld leeg is, wordt de trigger toegepast op alle device profielen", + "disabled": "Uitgeschakeld", + "edit-notification-recipients-group": "Groep geadresseerden van meldingen bewerken", + "edit-notification-template": "Meldingssjabloon bewerken", + "edit-rule": "Regel bewerken", + "edit-template": "Sjabloon bewerken", + "enabled": "Ingeschakeld", + "entities-limit-trigger-settings": "Entiteiten beperken triggerinstellingen", + "entity-action-trigger-settings": "Instellingen voor triggers voor entiteitsacties", + "entity-type": "Type entiteit", + "escalation-chain": "Escalatie keten", + "failed-send": "Fouten verzenden", + "fails": "{ count, plural, =1 {1 fail} andere {# fails} }", + "filter": "Filter", + "first-recipient": "Eerste ontvanger", + "inactive": "Inactief", + "inbox": "Postvak IN", + "notification-inbox": "Meldingen / Postvak IN", + "input-field-support-templatization": "Ondersteuning voor invoervelden sjabloonisatie.", + "input-fields-support-templatization": "Invoervelden ondersteunen sjabloonisatie.", + "integration-action-trigger-settings": "Activeringsinstellingen voor integratiegebeurtenissen", + "integration-list-rule-hint": "Als het veld leeg is, wordt de trigger toegepast op alle integraties", + "link": "Verbinden", + "link-required": "Link is verplicht", + "link-type": { + "dashboard": "Dashboard openen", + "link": "URL-link openen" + }, + "management": "Beheer van meldingen", + "mark-all-as-read": "Alles markeren als gelezen", + "mark-as-read": "Markeren als gelezen", + "message": "Bericht", + "message-required": "Bericht is vereist", + "message-max-length": "Het bericht moet kleiner zijn dan of gelijk zijn aan {{ length }} tekens", + "name": "Naam", + "name-required": "Naam is verplicht", + "new-notification": "Nieuwe melding", + "no-inbox-notification": "Geen melding gevonden", + "no-notification-request": "Geen meldingsverzoek", + "no-notification-templates": "Geen meldingssjablonen gevonden", + "no-notifications-yet": "Nog geen meldingen", + "no-recipients-notification": "Geen melding van ontvangers", + "no-rule": "Geen rule geconfigureerd", + "no-rules-notification": "Geen melding van regels", + "no-severity-found": "Geen ernst gevonden", + "no-severity-matching": "'{{severity}}' niet gevonden.", + "no-template-matching": "Er zijn geen '{{template}}' gevonden die overeenkomen met de bron.", + "not-found-slack-recipient": "Slack-ontvanger niet gevonden", + "notification": "Bekendmaking", + "notification-center": "Meldingscentrum", + "notify": "aankondigen", + "notify-again": "Opnieuw melden", + "notify-alarm-action": { + "acknowledged": "Alarm bevestigd", + "assigned": "Alarm toegewezen", + "cleared": "Alarm gewist", + "created": "Alarm gemaakt", + "severity-changed": "Alarmernst gewijzigd", + "unassigned": "Alarm niet toegewezen" + }, + "notify-on": "Melden op", + "notify-on-comment-update": "Bericht over commentaarupdate", + "notify-on-required": "Melden op is vereist", + "notify-on-unassign": "Melden bij toewijzing ongedaan maken", + "notify-only-integrations-errors": "Alleen melden bij fout", + "notify-only-user-comments": "Alleen opmerkingen van gebruikers op de hoogte stellen", + "only-rule-chain-lifecycle-failures": "Alleen fouten in de levenscyclus van de rule chain", + "only-rule-node-lifecycle-failures": "Alleen fouten in de levenscyclus van rule nodes", + "platform-users": "Gebruikers van het platform", + "recipient": "Ontvanger", + "recipient-group": "Groep ontvangers", + "recipient-type": { + "affected-tenant-administrators": "Betrokken tenantbeheerders", + "affected-user": "Betrokken gebruiker", + "all-users": "Alle gebruikers", + "customer-users": "Klant-gebruikers", + "system-administrators": "Systeembeheerders", + "tenant-administrators": "Tenant beheerders", + "user-filters": "Gebruiker filter", + "user-group-list": "Lijst met gebruikersgroepen", + "user-list": "Lijst met gebruikers", + "user-role": "Rol van de gebruiker", + "users-entity-owner": "Gebruikers van de entiteitseigenaar" + }, + "recipients": "Ontvangers", + "notification-recipients": "Meldingen / Ontvangers", + "recipients-count": "{ count, plural, =1 {1 recipient} andere {# recipients} }", + "recipients-required": "Ontvangers zijn verplicht", + "refresh-allow-delivery-method": "Vernieuwen Bezorgmethode toestaan", + "request-search": "Zoekopdracht aanvragen", + "request-status": { + "processing": "Verwerking", + "scheduled": "Gepland", + "sent": "Verzonden" + }, + "review": "Recensie", + "rule": "Regel", + "rule-chain-list-rule-hint": "Als het veld leeg is, wordt de trigger toegepast op alle rule chains", + "rule-engine-events-trigger-settings": "Events in de rule engine activeren instellingen", + "rule-engine-filter": "Rule engine filter", + "rule-name": "Naam van rule", + "rule-name-required": "Naam is verplicht", + "rule-node-filter": "Filter voor rule nodes", + "rules": "Reglement", + "notification-rules": "Meldingen / Regels", + "scheduler-later": "Plannen voor later", + "search-notification": "Meldingen zoeken", + "search-recipients": "Ontvangers zoeken", + "search-rules": "Zoekregels", + "search-templates": "Sjablonen zoeken", + "see-documentation": "Zie documentatie", + "selected-notifications": "{ count, plural, =1 {1 notification} andere {# notifications} } geselecteerd", + "selected-recipients": "{ count, plural, =1 {1 recipient} andere {# recipients} } geselecteerd", + "selected-requests": "{ count, plural, =1 {1 request} andere {# requests} } geselecteerd", + "selected-rules": "{ count, plural, =1 {1 rule} andere {# rules} } geselecteerd", + "selected-template": "{ count, plural, =1 {1 template} andere {# templates} } geselecteerd", + "send-notification": "Notificatie versturen", + "sent": "Verzonden", + "notification-sent": "Notificaties / Verzonden", + "set-entity-from-notification": "Entiteit instellen van melding naar dashboardstatus", + "slack-chanel-type": "Type Slack-kanaal", + "slack-chanel-types": { + "direct": "Direct bericht", + "private-channel": "Privé-kanaal", + "public-channel": "Publieke zender" + }, + "start-from-scratch": "Begin vanaf nul", + "status": "Status", + "stop-escalation-alarm-status-become": "Stop de escalatie van de alarmstatus wordt:", + "subject": "Onderwerp", + "subject-required": "Onderwerp is verplicht", + "template": "Sjabloon", + "template-name": "Naam van sjabloon", + "template-required": "Sjabloon is vereist", + "template-type": { + "alarm": "Alarm", + "alarm-assignment": "Alarm toewijzing", + "alarm-comment": "Alarm commentaar", + "api-usage-limit": "Limiet voor API-gebruik", + "device-activity": "Activiteit van het device", + "entities-limit": "Limieten voor entiteiten", + "entity-action": "Actie van entiteit", + "general": "Algemeen", + "integration-lifecycle-event": "Levens cyclus event van integratie", + "rule-engine-lifecycle-event": "Levens cyclus event van rule engine", + "rule-node": "Regel knooppunt", + "new-platform-version": "Nieuwe platformversie" + }, + "templates": "Sjablonen", + "notification-templates": "Meldingen / Sjablonen", + "tenant-profiles-list-rule-hint": "Als het veld leeg is, wordt de trigger toegepast op alle tenantprofielen", + "tenants-list-rule-hint": "Als het veld leeg is, wordt de trigger toegepast op alle tenants", + "threshold": "Drempel", + "time": "Tijd", + "track-rule-node-events": "Regelknooppuntgebeurtenissen bijhouden", + "trigger": { + "alarm": "Alarm", + "alarm-assignment": "Alarm toewijzing", + "alarm-comment": "Alarm commentaar", + "api-usage-limit": "Limiet voor API-gebruik", + "device-activity": "Activiteit van het device", + "entities-limit": "Limieten voor entiteiten", + "entity-action": "Actie van entiteit", + "integration-lifecycle-event": "Levens cyclus event van integratie", + "rule-engine-lifecycle-event": "Levens cyclus event van rule engine", + "new-platform-version": "Nieuwe platformversie", + "trigger": "Trigger", + "trigger-required": "Trigger is vereist" + }, + "type": "Type", + "unread": "Ongelezen", + "updated": "Bijgewerkt", + "use-template": "Sjabloon gebruiken", + "view-all": "Alles weergeven", + "view-notification-recipients-group": "Groep geadresseerden van meldingen weergeven", + "view-notification-template": "Meldingssjabloon weergeven", + "view-rule": "Bekijk rule", + "warning": "Waarschuwing" + }, + "ota-update": { + "add": "Pakket toevoegen", + "assign-firmware": "Toegewezen firmware", + "assign-firmware-required": "Toegewezen firmware is vereist", + "assign-software": "Toegewezen software", + "assign-software-required": "Toegewezen software is vereist", + "auto-generate-checksum": "Automatisch controlesom genereren", + "cant-applied-group-all": "Kan niet worden aangevraagd voor groep Alle", + "checksum": "Checksum", + "checksum-hint": "Als de checksum leeg is, wordt deze automatisch gegenereerd", + "checksum-algorithm": "Checksum-algoritme", + "checksum-copied-message": "De controlesom van het pakket is gekopieerd naar het klembord", + "change-firmware": "Wijziging van de firmware kan leiden tot een update van { count, plural, =1 {1 device} andere {# devices} }.", + "change-software": "Wijziging van de software kan leiden tot een update van { count, plural, =1 {1 device} andere {# devices} }.", + "chose-compatible-device-profile": "Het geüploade pakket is alleen beschikbaar voor devices met het gekozen profiel.", + "chose-firmware-distributed-device": "Kies firmware die naar de devices wordt gedistribueerd", + "chose-software-distributed-device": "Kies software die naar de devices wordt gedistribueerd", + "content-type": "Inhoudstype", + "copy-checksum": "Controlesom kopiëren", + "copy-direct-url": "Directe URL kopiëren", + "copyId": "Kopieer pakket-ID", + "copied": "Gekopieerd!", + "delete": "Pakket verwijderen", + "delete-ota-update-text": "Opgelet, na de bevestiging wordt de OTA-update onherstelbaar.", + "delete-ota-update-title": "Weet je zeker dat je de OTA-update '{{title}}' wilt verwijderen?", + "delete-ota-updates-text": "Opgelet, na de bevestiging worden alle geselecteerde OTA-updates verwijderd.", + "delete-ota-updates-title": "Weet u zeker dat u { count, plural, =1 {1 OTA update} andere {# OTA updates} } wilt verwijderen?", + "description": "Omschrijving: __________", + "direct-url": "Directe URL", + "direct-url-copied-message": "De directe URL van het pakket is gekopieerd naar het klembord", + "direct-url-required": "Directe URL is vereist", + "download": "Pakket downloaden", + "drop-file": "Zet een pakketbestand neer of klik om een bestand te selecteren om te uploaden.", + "drop-package-file-or": "Sleep een pakketbestand of", + "file-name": "Bestandsnaam", + "file-size": "Bestandsgrootte", + "file-size-bytes": "Bestandsgrootte in bytes", + "idCopiedMessage": "Pakket-ID is gekopieerd naar klembord", + "no-firmware-matching": "Er zijn geen compatibele OTA-updatepakketten gevonden die overeenkomen met '{{entity}}'.", + "no-firmware-text": "Er zijn geen compatibele OTA-updatepakketten voor firmware ingericht.", + "no-packages-text": "Geen pakketten gevonden", + "no-software-matching": "Er zijn geen compatibele Software OTA Update-pakketten gevonden die overeenkomen met '{{entity}}'.", + "no-software-text": "Er zijn geen compatibele OTA-updatepakketten voor software geleverd.", + "ota-update": "OTA-update", + "ota-update-details": "Details van OTA-update", + "ota-updates": "OTA-updates", + "package-type": "Soort verpakking", + "packages-repository": "Pakketten repository", + "search": "Pakketten zoeken", + "selected-package": "{ count, plural, =1 {1 package} andere {# packages} } geselecteerd", + "title": "Titel", + "title-required": "Titel is vereist.", + "title-max-length": "Titel moet kleiner zijn dan 256 tekens", + "types": { + "firmware": "Firmware", + "software": "Software" + }, + "upload-binary-file": "Binair bestand uploaden", + "use-external-url": "Externe URL gebruiken", + "version": "Versie", + "version-required": "Versie is vereist.", + "version-tag": "Versie Tag", + "version-tag-hint": "De aangepaste tag moet overeenkomen met de pakketversie die door uw device wordt gerapporteerd.", + "version-max-length": "Versie moet kleiner zijn dan 256 tekens", + "warning-after-save-no-edit": "Zodra het pakket is geüpload, kunt u de titel, versie, device profiel en pakkettype niet meer wijzigen." + }, + "position": { + "top": "Boven", + "bottom": "Bodem", + "left": "Links", + "right": "Rechts" + }, + "profile": { + "profile": "Profiel", + "last-login-time": "Laatste keer inloggen", + "change-password": "Wachtwoord wijzigen", + "current-password": "Huidig wachtwoord", + "copy-jwt-token": "JWT-token kopiëren", + "jwt-token": "JWT-token", + "token-valid-till": "Token is geldig tot", + "tokenCopiedSuccessMessage": "JWT-token is gekopieerd naar klembord", + "tokenCopiedWarnMessage": "JWT-token is verlopen! Vernieuw de pagina." + }, + "profiles": { + "profiles": "Profielen" + }, + "security": { + "security": "Veiligheid", + "general-settings": "Algemene beveiligingsinstellingen", + "2fa": { + "2fa": "Twee-factor-authenticatie", + "2fa-description": "Tweefactorauthenticatie beschermt uw account tegen ongeoorloofde toegang. Het enige wat je hoeft te doen is een beveiligingscode in te voeren wanneer je inlogt.", + "authenticate-with": "U kunt zich authenticeren met:", + "disable-2fa-provider-text": "Als u {{name}} uitschakelt, wordt uw account minder veilig", + "disable-2fa-provider-title": "Weet u zeker dat u {{name}} wilt uitschakelen?", + "get-new-code": "Nieuwe code ophalen", + "main-2fa-method": "Gebruik als belangrijkste tweefactorauthenticatiemethode", + "dialog": { + "activation-step-description-email": "De volgende keer dat u inlogt, wordt u gevraagd de beveiligingscode in te voeren die naar uw e-mailadres wordt verzonden.", + "activation-step-description-sms": "De volgende keer dat u inlogt, wordt u gevraagd de beveiligingscode in te voeren die naar het telefoonnummer wordt verzonden.", + "activation-step-description-totp": "De volgende keer dat u inlogt, moet u een tweefactorauthenticatiecode opgeven.", + "activation-step-label": "Activering", + "backup-code-description": "Print de codes uit, zodat je ze bij de hand hebt wanneer je ze moet gebruiken om in te loggen op je account. U kunt elke back-upcode één keer gebruiken.", + "backup-code-warn": "Zodra u deze pagina verlaat, kunnen deze codes niet meer worden weergegeven. Bewaar ze veilig met behulp van de onderstaande opties.", + "download-txt": "Downloaden (txt)", + "email-step-description": "Voer een e-mailadres in dat u als authenticator wilt gebruiken.", + "email-step-label": "E-mail", + "enable-email-title": "E-mailauthenticator inschakelen", + "enable-sms-title": "SMS-authenticator inschakelen", + "enable-totp-title": "Authenticator-app inschakelen", + "enter-verification-code": "Vul hier de 6-cijferige code in", + "get-backup-code-title": "Back-upcode ophalen", + "next": "Volgend", + "scan-qr-code": "Scan deze QR-code met je verificatie-app", + "send-code": "Verstuur code", + "sms-step-description": "Voer een telefoonnummer in dat u als authenticator wilt gebruiken.", + "sms-step-label": "Telefoonnummer", + "success": "Succes!", + "totp-step-description-install": "U kunt apps zoals Google Authenticator, Authy of Duo installeren.", + "totp-step-description-open": "Open de authenticator-app op je mobiele telefoon.", + "totp-step-label": "Download de app", + "verification-code": "6-cijferige code", + "verification-code-invalid": "Ongeldige indeling van de verificatiecode", + "verification-code-incorrect": "Verificatiecode is onjuist", + "verification-code-many-request": "Te veel verzoeken om verificatiecode te controleren", + "verification-step-description": "Voer een 6-cijferige code in die we zojuist naar {{address}} hebben gestuurd", + "verification-step-label": "Verificatie" + }, + "provider": { + "email": "E-mail", + "email-description": "Gebruik een beveiligingscode die naar uw e-mailadres is verzonden om u te verifiëren.", + "email-hint": "Authenticatiecodes worden per e-mail verzonden naar {{ info }}", + "sms": "SMS", + "sms-description": "Gebruik je telefoon om je te authenticeren. We sturen je een beveiligingscode via sms wanneer je inlogt.", + "sms-hint": "Authenticatiecodes worden per sms verzonden naar {{ info }}", + "totp": "Authenticator-app", + "totp-description": "Gebruik apps zoals Google Authenticator, Authy of Duo op je telefoon om te verifiëren. Het genereert een beveiligingscode om in te loggen.", + "totp-hint": "De Authenticator-app is ingesteld voor uw account", + "backup_code": "Back-up code", + "backup-code-description": "Met deze afdrukbare eenmalige toegangscodes kunt u zich aanmelden wanneer u uw telefoon niet bij de hand hebt, bijvoorbeeld wanneer u op reis bent.", + "backup-code-hint": "{{ info }} codes voor eenmalig gebruik zijn op dit moment actief" + } + }, + "password-requirement": { + "at-least": "Minstens:", + "character": "{ count, plural, =1 {1 character} andere {# characters} }", + "digit": "{ count, plural, =1 {1 digit} andere {# digits} }", + "incorrect-password-try-again": "Onjuist wachtwoord. Probeer het opnieuw", + "lowercase-letter": "{ count, plural, =1 {1 lowercase letter} andere {# lowercase letters} }", + "new-passwords-not-match": "Nieuw wachtwoord komt niet overeen", + "password-should-not-contain-spaces": "Uw wachtwoord mag geen spaties bevatten", + "password-not-meet-requirements": "Wachtwoord voldeed niet aan de vereisten", + "password-requirements": "Vereisten voor wachtwoorden", + "password-should-difference": "Het nieuwe wachtwoord moet anders zijn dan het huidige", + "special-character": "{ count, plural, =1 {1 special character} andere {# special characters} }", + "uppercase-letter": "{ count, plural, =1 {1 uppercase letter} andere {# uppercase letters} }" + } + }, + "relation": { + "relations": "Betrekkingen", + "direction": "Richting", + "search-direction": { + "FROM": "Van", + "TO": "Aan" + }, + "direction-type": { + "FROM": "Van", + "TO": "Aan" + }, + "from-relations": "Uitgaande relaties", + "to-relations": "Inkomende relaties", + "selected-relations": "{ count, plural, =1 {1 relation} andere {# relations} } geselecteerd", + "type": "Type", + "to-entity-type": "Naar entiteitstype", + "to-entity-name": "Naar entiteitsnaam", + "from-entity-type": "Van entiteitstype", + "from-entity-name": "Van entiteitsnaam", + "to-entity": "Naar entiteit", + "from-entity": "Van entiteit", + "delete": "Relatie verwijderen", + "relation-type": "Relatie type", + "relation-type-required": "Relatietype is vereist.", + "relation-type-max-length": "Relatietype moet kleiner zijn dan 256 tekens", + "any-relation-type": "Elk type", + "add": "Relatie toevoegen", + "edit": "Relatie bewerken", + "view": "Bekijk relatie", + "delete-to-relation-title": "Weet u zeker dat u de relatie met de entiteit '{{entityName}}' wilt verwijderen?", + "delete-to-relation-text": "Let op, na de bevestiging is de entiteit '{{entityName}}' niet meer gerelateerd aan de huidige entiteit.", + "delete-to-relations-title": "Weet u zeker dat u { count, plural, =1 {1 relation} andere {# relations} } wilt verwijderen?", + "delete-to-relations-text": "Opgelet, na de bevestiging worden alle geselecteerde relaties verwijderd en worden de bijbehorende entiteiten losgekoppeld van de huidige entiteit.", + "delete-from-relation-title": "Weet u zeker dat u de relatie uit de entiteit '{{entityName}}' wilt verwijderen?", + "delete-from-relation-text": "Opgelet, na de bevestiging zal de huidige entiteit niet meer gerelateerd zijn aan de entiteit '{{entityName}}'.", + "delete-from-relations-title": "Weet u zeker dat u { count, plural, =1 {1 relation} andere {# relations} } wilt verwijderen?", + "delete-from-relations-text": "Opgelet, na de bevestiging worden alle geselecteerde relaties verwijderd en wordt de huidige entiteit losgekoppeld van de corresponderende entiteiten.", + "remove-relation-filter": "Relatiefilter verwijderen", + "add-relation-filter": "Relatiefilter toevoegen", + "any-relation": "Elke relatie", + "relation-filters": "Relatie filters", + "additional-info": "Aanvullende informatie (JSON)", + "invalid-additional-info": "Kan aanvullende informatie json niet parseren.", + "no-relations-text": "Geen relaties gevonden" + }, + "resource": { + "add": "Bron toevoegen", + "copyId": "Resource-ID kopiëren", + "delete": "Bron verwijderen", + "delete-resource-text": "Opgelet, na de bevestiging wordt de bron onherstelbaar.", + "delete-resource-title": "Weet u zeker dat u de bron '{{resourceTitle}}' wilt verwijderen?", + "delete-resources-action-title": "Verwijder { count, plural, =1 {1 resource} andere {# resources} }", + "delete-resources-text": "Houd er rekening mee dat de geselecteerde bronnen, zelfs als ze in device profielen worden gebruikt, worden verwijderd.", + "delete-resources-title": "Weet u zeker dat u { count, plural, =1 {1 resource} andere {# resources} } wilt verwijderen?", + "download": "Bron downloaden", + "drop-file": "Zet een bronbestand neer of klik om een bestand te selecteren om te uploaden.", + "drop-resource-file-or": "Sleep een bronbestand of", + "empty": "Bron is leeg", + "file-name": "Bestandsnaam", + "idCopiedMessage": "Bron-id is gekopieerd naar klembord", + "no-resource-matching": "Er zijn geen '{{widgetsBundle}}' gevonden die overeenkomen met de bron.", + "no-resource-text": "Geen bronnen gevonden", + "open-widgets-bundle": "Widgets-bundel openen", + "resource": "Hulpbron", + "resource-library-details": "Details van de bron", + "resource-type": "Type bron", + "resources-library": "Bibliotheek met bronnen", + "search": "Bronnen zoeken", + "selected-resources": "{ count, plural, =1 {1 resource} andere {# resources} } geselecteerd", + "system": "Systeem", + "title": "Titel", + "title-required": "Titel is vereist.", + "title-max-length": "Titel moet kleiner zijn dan 256 tekens" + }, + "rulechain": { + "rulechain": "Rule chains", + "rulechain-events": "Events in de rule chain", + "rulechains": "Rule chains", + "root": "Bron", + "delete": "Rule chain verwijderen", + "name": "Naam", + "name-required": "Naam is verplicht.", + "name-max-length": "Naam moet kleiner zijn dan 256 tekens", + "description": "Omschrijving: __________", + "add": "Rule chain toevoegen", + "set-root": "Bron rule chain aanmaken", + "set-root-rulechain-title": "Weet u zeker dat u de rule chain '{{ruleChainName}}' als bron wilt maken?", + "set-root-rulechain-text": "Na de bevestiging wordt de rule chain de bron en worden alle inkomende transportberichten afgehandeld.", + "delete-rulechain-title": "Weet u zeker dat u de rule chain '{{ruleChainName}}' wilt verwijderen?", + "delete-rulechain-text": "Opgelet, na de bevestiging worden de rule chain en alle gerelateerde gegevens onherstelbaar.", + "delete-rulechains-title": "Weet u zeker dat u { count, plural, =1 {1 rule chain} andere {# rule chains} } wilt verwijderen?", + "delete-rulechains-action-title": "Verwijder { count, plural, =1 {1 rule chain} andere {# rule chains} }", + "delete-rulechains-text": "Opgelet, na de bevestiging worden alle geselecteerde rule chains verwijderd en worden alle gerelateerde gegevens onherstelbaar.", + "add-rulechain-text": "Nieuwe rule chain toevoegen", + "no-rulechains-text": "Geen rule chains gevonden", + "rulechain-details": "Details van de rule chain", + "details": "Details", + "events": "Events", + "system": "Systeem", + "import": "Rule chain importeren", + "export": "Rule chain exporteren", + "export-failed-error": "Rule chain kan niet worden geëxporteerd: {{error}}", + "create-new-rulechain": "Nieuwe rule chain maken", + "rulechain-file": "Rule chain bestand", + "invalid-rulechain-file-error": "Rule chain kan niet worden geïmporteerd: Ongeldige gegevensstructuur van de rule chain.", + "copyId": "Rule chain-id kopiëren", + "idCopiedMessage": "Rule chain-id is gekopieerd naar klembord", + "select-rulechain": "Rule chain selecteren", + "no-rulechains-matching": "Er zijn geen rule chains gevonden die overeenkomen met '{{entity}}'.", + "rulechain-required": "Rule chain is vereist", + "management": "Beheer van rule chains", + "debug-mode": "Foutopsporingsmodus", + "search": "Rule chains zoeken", + "selected-rulechains": "{ count, plural, =1 {1 rule chain} andere {# rule chains} } geselecteerd", + "open-rulechain": "Rule chain openen", + "edge-template-root": "Sjabloon Wortel", + "assign-to-edge": "Toewijzen aan Edge", + "edge-rulechain": "Edge rule chain", + "unassign-rulechain-from-edge-text": "Na de bevestiging wordt de toewijzing van de rule chain ongedaan gemaakt en is deze niet toegankelijk voor de edge.", + "unassign-rulechains-from-edge-title": "Weet u zeker dat u de toewijzing van { count, plural, =1 {1 rulechain} andere {# rulechains} } wilt opheffen?", + "unassign-rulechains-from-edge-text": "Na de bevestiging worden alle geselecteerde rule chains ongedaan gemaakt en zijn ze niet toegankelijk via de edge.", + "assign-rulechain-to-edge-title": "Regel Chain(s) toewijzen aan Edge", + "assign-rulechain-to-edge-text": "Selecteer de rule chains die u aan de edge wilt toewijzen", + "set-edge-template-root-rulechain": "Rule chain maken als hoofdmap van de randsjabloon", + "set-edge-tscheduler-eventemplate-root-rulechain": "Rule chain maken als hoofdmap van de randsjabloon", + "set-edge-template-root-rulechain-title": "Weet u zeker dat u de rule chain '{{ruleChainName}}' randsjabloon root wilt maken?", + "set-edge-template-root-rulechain-text": "Na de bevestiging wordt de rule chain de hoofdstructuur van de randsjabloon en wordt deze de hoofdregelketen voor een nieuw aangemaakte edges.", + "invalid-rulechain-type-error": "Kan rule chain niet importeren: Ongeldig type rule chain. Verwacht type is {{expectedRuleChainType}}.", + "set-auto-assign-to-edge": "Rule chain toewijzen aan edge(en) bij het maken", + "set-auto-assign-to-edge-title": "Weet u zeker dat u de rule chain '{{ruleChainName}}' wilt toewijzen aan edge(en) bij het maken?", + "set-auto-assign-to-edge-text": "Na de bevestiging wordt de rule chain automatisch toegewezen aan edge(en) bij het aanmaken.", + "unset-auto-assign-to-edge": "Wijs geen rule chain toe aan edge(en) bij het maken", + "unset-auto-assign-to-edge-title": "Weet u zeker dat u de rule chain '{{ruleChainName}}' niet wilt toewijzen aan edge(en) bij het maken?", + "unset-auto-assign-to-edge-text": "Na de bevestiging wordt de rule chain niet langer automatisch toegewezen aan edge(en) bij het aanmaken.", + "unassign-rulechain-title": "Weet u zeker dat u de toewijzing van de rule chain '{{ruleChainName}}' wilt opheffen?", + "unassign-rulechains": "Toewijzing van rule chains ongedaan maken" + }, + "rulenode": { + "rule-node-events": "Events met rule nodes", + "details": "Details", + "events": "Events", + "search": "Rule nodes zoeken", + "open-node-library": "Knooppuntbibliotheek openen", + "add": "Rule node toevoegen", + "name": "Naam", + "name-required": "Naam is verplicht.", + "name-max-length": "Naam moet kleiner zijn dan 256 tekens", + "type": "Type", + "description": "Omschrijving: __________", + "delete": "Rule node verwijderen", + "select-all-objects": "Selecteer alle rule nodes en verbindingen", + "deselect-all-objects": "Deselecteer alle rule nodes en verbindingen", + "delete-selected-objects": "Geselecteerde rule nodes en verbindingen verwijderen", + "delete-selected": "Selectie verwijderen", + "create-nested-rulechain": "Geneste rule chain maken", + "select-all": "Alles selecteren", + "copy-selected": "Geselecteerde tekst kopiëren", + "deselect-all": "Alles deselecteren", + "rulenode-details": "Details van rule nodes", + "debug-mode": "Foutopsporingsmodus", + "singleton-mode": "Singleton-modus", + "configuration": "Configuratie", + "link": "Verbinden", + "link-details": "Details van rule nodes links", + "add-link": "Link toevoegen", + "link-label": "Label koppelen", + "link-label-required": "Linklabel is vereist.", + "custom-link-label": "Aangepast linklabel", + "custom-link-label-required": "Aangepast linklabel is vereist.", + "link-labels": "Labels koppelen", + "link-labels-required": "Labels koppelen is vereist.", + "no-link-labels-found": "Geen linklabels gevonden", + "no-link-label-matching": "'{{label}}' niet gevonden.", + "create-new-link-label": "Maak een nieuwe aan!", + "type-filter": "Filter", + "type-filter-details": "Inkomende berichten filteren met geconfigureerde voorwaarden", + "type-enrichment": "Verrijking", + "type-enrichment-details": "Aanvullende informatie toevoegen aan de metagegevens van berichten", + "type-transformation": "Transformatie", + "type-transformation-details": "De payload en metagegevens van berichten wijzigen", + "type-action": "Actie", + "type-action-details": "Speciale actie uitvoeren", + "type-analytics": "Analytics", + "type-analytics-details": "Analyse uitvoeren van gestreamde of persistente gegevens", + "type-external": "Extern", + "type-external-details": "Werkt samen met extern systeem", + "type-rule-chain": "Rule chain", + "type-rule-chain-details": "Inkomende berichten worden doorgestuurd naar een opgegeven rule chain", + "type-flow": "Vloeien", + "type-flow-details": "Organiseert de berichtenstroom", + "type-input": "Invoer", + "type-input-details": "Logische invoer van rule chain, stuurt inkomende berichten door naar het volgende gerelateerde rule node", + "type-unknown": "Onbekend", + "type-unknown-details": "Onopgelost rule node", + "directive-is-not-loaded": "Gedefinieerde configuratierichtlijn '{{directiveName}}' is niet beschikbaar.", + "ui-resources-load-error": "Het laden van de bronnen van de configuratie-gebruikersinterface is mislukt.", + "invalid-target-rulechain": "Kan doelregelketen niet oplossen!", + "test-script-function": "Test script functie", + "script-lang-java-script": "Java-schrift", + "script-lang-tbel": "TBEL", + "message": "Bericht", + "message-type": "Soort bericht", + "select-message-type": "Selecteer berichttype", + "message-type-required": "Berichttype is vereist", + "metadata": "Metagegevens", + "metadata-required": "Metagegevensvermeldingen mogen niet leeg zijn.", + "output": "Uitvoer", + "test": "Test", + "help": "Help", + "reset-debug-mode": "Foutopsporingsmodus resetten in alle rule nodes" + }, + "role": { + "role": "Rol", + "roles": "Rollen", + "management": "Rollen beheer", + "view-roles": "Rollen weergeven", + "no-roles-matching": "Er zijn geen rollen gevonden die overeenkomen met '{{entity}}'.", + "role-list": "Lijst met rollen", + "role-list-required": "Rollenlijst is verplicht", + "add": "Rol toevoegen", + "view": "Bekijk rol", + "search": "Rollen zoeken", + "selected-roles": "{ count, plural, =1 {1 role} andere {# roles} } geselecteerd", + "no-roles-text": "Geen rollen gevonden", + "role-details": "Details van de rol", + "add-role-text": "Nieuwe rol toevoegen", + "delete": "Rol verwijderen", + "delete-roles": "Rollen verwijderen", + "delete-role-title": "Weet je zeker dat je de rol '{{roleName}}' wilt verwijderen?", + "delete-role-text": "Opgelet, na de bevestiging worden de rol en alle gerelateerde gegevens onherstelbaar.", + "delete-roles-title": "Weet u zeker dat u { count, plural, =1 {1 role} andere {# roles} } wilt verwijderen?", + "delete-roles-action-title": "Verwijder { count, plural, =1 {1 role} andere {# roles} }", + "delete-roles-text": "Opgelet, na de bevestiging worden alle geselecteerde rollen verwijderd en worden alle gerelateerde gegevens onherstelbaar.", + "role-type": "Soort rol", + "role-type-required": "Roltype is vereist.", + "select-role-type": "Roltype selecteren", + "enter-role-type": "Roltype invoeren", + "any-role": "Elke rol", + "no-role-types-matching": "Er zijn geen roltypen gevonden die overeenkomen met '{{entitySubtype}}'.", + "role-type-list-empty": "Geen roltypen geselecteerd.", + "role-types": "Soorten rollen", + "created-time": "Gecreëerde tijd", + "name": "Naam", + "name-required": "Naam is verplicht.", + "name-max-length": "Naam moet kleiner zijn dan 256 tekens", + "description": "Omschrijving: __________", + "events": "Events", + "details": "Details", + "copyId": "Rol-ID kopiëren", + "idCopiedMessage": "Rol-ID is gekopieerd naar het klembord", + "permissions": "Machtigingen", + "role-required": "Vereiste rol", + "roles-required": "Vereiste rollen", + "display-type": { + "GENERIC": "Generiek", + "GROUP": "Groep" + } + }, + "group-permission": { + "user-group-roles": "Rollen voor gebruikersgroepen", + "entity-group-permissions": "Machtigingen voor entiteitsgroepen", + "role-type": "Soort rol", + "role-name": "Naam van de rol", + "group-type": "Soort groep", + "group-name": "Naam van de groep", + "group-owner": "Eigenaar van de groep", + "user-group-name": "Naam van de gebruikersgroep", + "user-group-owner": "Eigenaar van gebruikersgroep", + "edit": "Machtigingen bewerken", + "delete": "Machtigingen verwijderen", + "selected-group-permissions": "{ count, plural, =1 {1 group permission} andere {# group permissions} } geselecteerd", + "delete-group-permission-title": "Weet je zeker dat je de groepsrechten '{{roleName}}' wilt verwijderen?", + "delete-group-permission-text": "Opgelet, na de bevestiging worden de groepstoestemming en alle gerelateerde gegevens onherstelbaar.", + "delete-group-permission": "Groepsmachtiging verwijderen", + "delete-group-permissions-title": "Weet u zeker dat u { count, plural, =1 {1 group permission} andere {# group permission} } wilt verwijderen?", + "delete-group-permissions-text": "Opgelet, na de bevestiging worden alle geselecteerde groepsmachtigingen verwijderd en verliezen de bijbehorende gebruikers de toegang tot gespecificeerde bronnen.", + "delete-group-permissions": "Groepsmachtigingen verwijderen", + "add-group-permission": "Groepsmachtiging toevoegen", + "edit-group-permission": "Groepsmachtiging bewerken", + "entity-group": "Entiteitsgroep", + "user-group": "Gebruikersgroep", + "no-owners-matching": "Er zijn geen eigenaren gevonden die overeenkomen met '{{owner}}'.", + "target-owner-required": "Eigenaar van entiteitsgroep is vereist.", + "target-user-group-owner-required": "Eigenaar van gebruikersgroep is vereist.", + "no-group-permissions-text": "Geen groepsmachtigingen gevonden" + }, + "permission": { + "permissions-required": "Er moet ten minste één machtigingsvermelding worden opgegeven.", + "remove-permission": "Machtigingsinvoer verwijderen", + "add-permission": "Machtigingsinvoer toevoegen", + "other": "Anders __________", + "resource": { + "resource": "Hulpbron", + "select-resource": "Bron selecteren", + "resource-required": "Resource is vereist", + "no-resources-matching": "Er zijn geen bronnen gevonden die overeenkomen met '{{resource}}'.", + "display-type": { + "ALL": "Alle", + "PROFILE": "Profiel", + "ADMIN_SETTINGS": "Admin-instellingen", + "ALARM": "Alarm", + "DEVICE": "Device", + "DEVICE_PROFILE": "Device profiel", + "ASSET": "Asset", + "CUSTOMER": "Klant", + "DASHBOARD": "Dashboard", + "ENTITY_VIEW": "Entiteit Weergave", + "EDGE": "Edge", + "TENANT": "Tenant", + "TENANT_PROFILE": "Profiel van de tenant", + "RULE_CHAIN": "Rule chain", + "USER": "Gebruiker", + "WIDGETS_BUNDLE": "Widgets Bundel", + "WIDGET_TYPE": "Widget Type", + "CONVERTER": "Conversieprogramma", + "INTEGRATION": "Integratie", + "SCHEDULER_EVENT": "Scheduler Evenement", + "BLOB_ENTITY": "Blob-entiteit", + "CUSTOMER_GROUP": "Klantengroep", + "DEVICE_GROUP": "Device Groep", + "ASSET_GROUP": "Activagroep", + "USER_GROUP": "Gebruikersgroep", + "ENTITY_VIEW_GROUP": "Groep Entiteitsweergave", + "DASHBOARD_GROUP": "Dashboard Groep", + "ROLE": "Rol", + "GROUP_PERMISSION": "Toestemming voor groepen", + "WHITE_LABELING": "White labelling", + "AUDIT_LOG": "Controle logboek", + "API_USAGE_STATE": "Status API-gebruik", + "TB_RESOURCE": "Hulpbron", + "EDGE_GROUP": "Edge-groep", + "OTA_PACKAGE": "Ota-pakket", + "QUEUE": "Rij", + "VERSION_CONTROL": "Versiebeheer", + "ASSET_PROFILE": "Asset Profiel", + "NOTIFICATION": "Bekendmaking" + } + }, + "operation": { + "operation": "Operatie", + "operations": "Operaties", + "operations-required": "Er moet ten minste één bewerking worden opgegeven.", + "enter-operation": "Operatie invoeren", + "no-operations-matching": "Er zijn geen bewerkingen gevonden die overeenkomen met '{{operation}}'.", + "display-type": { + "ALL": "Alle", + "CREATE": "Nieuw", + "READ": "Lezen", + "WRITE": "Schrijven", + "DELETE": "Verwijderen", + "ASSIGN_TO_CUSTOMER": "Toewijzen aan klant", + "UNASSIGN_FROM_CUSTOMER": "Toewijzing van klant ongedaan maken", + "RPC_CALL": "RPC-oproep", + "READ_CREDENTIALS": "Inloggegevens lezen", + "WRITE_CREDENTIALS": "Referenties schrijven", + "READ_ATTRIBUTES": "Attributen lezen", + "WRITE_ATTRIBUTES": "Attributen schrijven", + "READ_TELEMETRY": "Telemetrie lezen", + "WRITE_TELEMETRY": "Telemetrie schrijven", + "CLAIM_DEVICES": "Devices claimen", + "IMPERSONATE": "Imiteren", + "CHANGE_OWNER": "Eigenaar wijzigen", + "ADD_TO_GROUP": "Voeg toe aan groep", + "REMOVE_FROM_GROUP": "Verwijderen uit groep", + "SHARE_GROUP": "Groep delen", + "ASSIGN_TO_TENANT": "Toewijzen aan tenant" + } + } + }, + "scheduler": { + "scheduler": "Scheduler", + "scheduler-event": "Scheduler-event", + "select-scheduler-event": "Scheduler event selecteren", + "no-scheduler-events-matching": "Er zijn geen scheduler events gevonden die overeenkomen met '{{entity}}'.", + "scheduler-event-required": "Scheduler-event is vereist", + "management": "Beheer van de planning", + "scheduler-events": "Scheduler-events", + "add-scheduler-event": "Scheduler-event toevoegen", + "search-scheduler-events": "Scheduler-events zoeken", + "created-time": "Gecreëerde tijd", + "name": "Naam", + "name-required": "Naam is verplicht", + "name-max-length": "Naam moet kleiner zijn dan 256 tekens", + "type": "Type", + "created_customer": "Gemaakt door de klant", + "edit-scheduler-event": "Scheduler-event bewerken", + "view-scheduler-event": "Scheduler event weergeven", + "delete-scheduler-event": "Scheduler-event verwijderen", + "no-scheduler-events": "Geen planner-gebeurtenissen gevonden", + "selected-scheduler-events": "{ count, plural, =1 {1 scheduler event} andere {# scheduler events} } geselecteerd", + "delete-scheduler-event-title": "Weet u zeker dat u de '{{schedulerEventName}}' van de planningsgebeurtenis wilt verwijderen?", + "delete-scheduler-event-text": "Opgelet, na de bevestiging worden de event van de planner en alle gerelateerde gegevens onherstelbaar.", + "delete-scheduler-events-title": "Weet u zeker dat u { count, plural, =1 {1 scheduler event} andere {# scheduler events} } wilt verwijderen?", + "delete-scheduler-events-text": "Opgelet, na de bevestiging worden alle geselecteerde scheduler events verwijderd en kunnen alle gerelateerde gegevens niet meer worden hersteld.", + "create": "Scheduler-event maken", + "edit": "Scheduler-event bewerken", + "view": "Scheduler event weergeven", + "configuration": "Configuratie", + "schedule": "Rooster", + "start-time": "Begintijd", + "repeat": "Herhalen", + "repeats": "Herhaalt", + "daily": "Dagelijks", + "every-n-days": "Elke N dagen", + "every-n-days-text": "Elke { days, plural, =1 {day} andere {# days} }", + "weekly": "Wekelijks", + "every-n-weeks": "Elke N weken", + "every-n-weeks-text": "Elke { weeks, plural, =1 {week} andere {# weeks} }", + "monthly": "Maandelijks", + "yearly": "Jaarlijks", + "timer": "Op basis van een timer", + "repeats-required": "Herhalingen zijn vereist.", + "repeat-on": "Herhaal op", + "repeat-every": "Herhaal elke", + "repeat-every-n-days": "Herhaal dit elke N dagen", + "repeat-days-required": "Het aantal dagen om te herhalen is vereist.", + "invalid-repeat-days-value": "Het aantal te herhalen dagen moet een positief geheel getal zijn.", + "repeat-every-n-weeks": "Herhaal elke N weken", + "repeat-weeks-required": "Aantal weken om te herhalen is vereist.", + "invalid-repeat-weeks-value": "Het aantal te herhalen weken moet een positief geheel getal zijn.", + "ends-on": "Eindigt op", + "sunday-label": "S", + "monday-label": "M", + "tuesday-label": "T", + "wednesday-label": "W", + "thursday-label": "T", + "friday-label": "F", + "saturday-label": "S", + "repeat-on-sunday": "Herhaling op zondag", + "repeat-on-monday": "Herhaal op maandag", + "repeat-on-tuesday": "Herhaal op dinsdag", + "repeat-on-wednesday": "Herhaal op woensdag", + "repeat-on-thursday": "Herhaal op donderdag", + "repeat-on-friday": "Herhaal op vrijdag", + "repeat-on-saturday": "Herhaling op zaterdag", + "event-type": "Type event", + "select-event-type": "Selecteer evenementtype", + "event-type-required": "Gebeurtenistype is vereist.", + "event-type-max-length": "Het gebeurtenistype moet kleiner zijn dan 256 tekens.", + "list-mode": "Lijst weergave", + "calendar-mode": "Kalenderweergave", + "calendar-view-type": "Type kalenderweergave", + "month": "Maand", + "week": "Week", + "day": "Dag", + "agenda-week": "Agenda Week", + "agenda-day": "Dag van de agenda", + "list-year": "Lijst Jaar", + "list-month": "Lijst Maand", + "list-week": "Lijst Week", + "list-day": "Lijst Dag", + "today": "Vandaag", + "navigate-before": "Navigeer voor", + "navigate-next": "Navigeer volgende", + "starting-from": "Vanaf", + "until": "totdat", + "on": "op", + "sunday": "Zondag", + "monday": "Maandag", + "tuesday": "Dinsdag", + "wednesday": "Woensdag", + "thursday": "Donderdag", + "friday": "Vrijdag", + "saturday": "Zaterdag", + "originator": "Opdrachtgever", + "single-entity": "Eén entiteit", + "group-of-entities": "Groep van entiteiten", + "entities-group-owner": "Eigenaar van entiteitengroep", + "single-device": "Eén device", + "group-of-devices": "Groep Devices", + "devices-group-owner": "Eigenaar van de Devicesgroep", + "message-body": "Hoofdtekst van bericht", + "target": "Doel", + "rpc-method": "Methode", + "rpc-method-required": "Methode is vereist", + "rpc-method-white-space": "Witruimte is niet toegestaan.", + "rpc-params": "Params", + "select-dashboard-state": "Dashboardstatus selecteren", + "hours": "Uren", + "minutes": "Notulen", + "seconds": "Seconden", + "time-interval-required": "Tijdsinterval is vereist", + "time-unit-required": "Tijdseenheid is vereist", + "every-hour": "elke { count, plural, =1 {hour} andere {# hours} }", + "every-minute": "elke { count, plural, =1 {minute} andere {# minutes} }", + "every-second": "elke { count, plural, =1 {second} andere {# seconds} }", + "invalid-time": "Ongeldige tijd" + }, + "report": { + "report-config": "Configuratie van rapporten", + "email-config": "E-mail configuratie", + "dashboard-state-param": "Parameterwaarde dashboardstatus", + "base-url": "Basis-URL", + "base-url-required": "Basis-URL is vereist.", + "use-dashboard-timewindow": "Dashboard tijdvenster gebruiken", + "timewindow": "Tijdvenster", + "name-pattern": "Patroon van rapportnaam", + "name-pattern-required": "Rapportnaam patroon is vereist", + "type": "Soort rapport", + "use-current-user-credentials": "Huidige gebruikersreferenties gebruiken", + "customer-user-credentials": "Gebruikersgegevens van de klant", + "customer-user-credentials-required": "Gebruikersgegevens van de klant zijn vereist", + "generate-test-report": "Testrapport genereren", + "send-email": "Stuur een e-mail", + "from": "Van", + "from-required": "Van is vereist.", + "to": "Aan", + "to-required": "Naar is vereist.", + "cc": "CC", + "bcc": "Bcc", + "subject": "Onderwerp", + "subject-required": "Onderwerp is verplicht.", + "body": "Body", + "body-required": "Body is vereist." + }, + "blob-entity": { + "blob-entity": "Blob-entiteit", + "select-blob-entity": "Blob-entiteit selecteren", + "no-blob-entities-matching": "Er zijn geen blob-entiteiten gevonden die overeenkomen met '{{entity}}'.", + "blob-entity-required": "Blob-entiteit is vereist", + "files": "Archief", + "search": "Bestanden zoeken", + "clear-search": "Zoekopdracht wissen", + "no-blob-entities-prompt": "Geen bestanden gevonden", + "report": "Rapport", + "created-time": "Gecreëerde tijd", + "name": "Naam", + "type": "Type", + "created_customer": "Gemaakt door de klant", + "selected-blob-entities": "{ count, plural, =1 {1 file} andere {# files} } geselecteerd", + "download-blob-entity": "Bestand downloaden", + "delete-blob-entity": "Bestand verwijderen", + "delete-blob-entity-title": "Weet u zeker dat u bestand '{{blobEntityName}}' wilt verwijderen?", + "delete-blob-entity-text": "Opgelet, na de bevestiging worden de gegevens van het bestand onherstelbaar.", + "delete-blob-entities-title": "Weet u zeker dat u { count, plural, =1 {1 file} andere {# files} } wilt verwijderen?", + "delete-blob-entities-text": "Opgelet, na de bevestiging worden alle geselecteerde bestanden verwijderd en kunnen alle gerelateerde gegevens niet meer worden hersteld." + }, + "timezone": { + "timezone": "Tijdzone", + "select-timezone": "Selecteer tijdzone", + "no-timezones-matching": "Er zijn geen tijdzones gevonden die overeenkomen met '{{timezone}}'.", + "timezone-required": "Tijdzone is vereist.", + "browser-time": "Browser Tijd" + }, + "queue": { + "queue-name": "Rij", + "no-queues-found": "Geen queues gevonden.", + "no-queues-matching": "Er zijn geen queues gevonden die overeenkomen met '{{queue}}'.", + "select-name": "Selecteer de naam van de queue", + "name": "Naam", + "name-required": "Queue naam is verplicht!", + "name-unique": "De naam van de queue is niet uniek!", + "name-pattern": "De naam van de queue bevat een ander teken dan ASCII-alfanumerieke tekens, '.', '_' en '-'!", + "queue-required": "Queue is verplicht!", + "topic-required": "Wachtrijonderwerp is vereist!", + "poll-interval-required": "Poll-interval is vereist!", + "poll-interval-min-value": "De waarde van het pollinterval mag niet kleiner zijn dan 1", + "partitions-required": "Partities is vereist!", + "partitions-min-value": "De waarde van partities mag niet kleiner zijn dan 1", + "pack-processing-timeout-required": "Time-out voor verwerking is vereist", + "pack-processing-timeout-min-value": "De time-outwaarde voor verwerking mag niet kleiner zijn dan 1", + "batch-size-required": "Batchgrootte is vereist!", + "batch-size-min-value": "De waarde van de batchgrootte mag niet kleiner zijn dan 1", + "retries-required": "Opnieuw proberen is vereist!", + "retries-min-value": "De waarde voor nieuwe pogingen mag niet negatief zijn", + "failure-percentage-required": "Error percentage is vereist!", + "failure-percentage-min-value": "De waarde van het error percentage mag niet kleiner zijn dan 0", + "failure-percentage-max-value": "De waarde van het error percentage mag niet hoger zijn dan 100", + "pause-between-retries-required": "Pauze tussen nieuwe pogingen is vereist!", + "pause-between-retries-min-value": "De waarde van de pauze tussen nieuwe pogingen mag niet kleiner zijn dan 1", + "max-pause-between-retries-required": "Maximale pauze tussen nieuwe pogingen is vereist!", + "max-pause-between-retries-min-value": "De maximale pauze tussen de waarde voor nieuwe pogingen mag niet minder zijn dan 1", + "submit-strategy-type-required": "Strategietype indienen is vereist!", + "processing-strategy-type-required": "Het type verwerkingsstrategie is vereist!", + "queues": "Queues", + "selected-queues": "{ count, plural, =1 {1 queue} andere {# queues} } geselecteerd", + "delete-queue-title": "Weet je zeker dat je de queue '{{queueName}}' wilt verwijderen?", + "delete-queues-title": "Weet u zeker dat u { count, plural, =1 {1 queue} andere {# queues} } wilt verwijderen?", + "delete-queue-text": "Opgelet, na de bevestiging worden de queue en alle gerelateerde gegevens onherstelbaar.", + "delete-queues-text": "Na de bevestiging worden alle geselecteerde queues verwijderd en zijn ze niet meer toegankelijk.", + "search": "Queue zoeken", + "add": "Queue toevoegen", + "details": "Details van de queue", + "topic": "Onderwerp", + "submit-settings": "Instellingen verzenden", + "submit-strategy": "Soort strategie *", + "grouping-parameter": "Parameter groeperen", + "processing-settings": "Verwerkingsinstellingen opnieuw proberen", + "processing-strategy": "Soort verwerking *", + "retries-settings": "Instellingen voor nieuwe pogingen", + "polling-settings": "Polling-instellingen", + "batch-processing": "Batchverwerking", + "poll-interval": "Poll-interval", + "partitions": "Partities", + "immediate-processing": "Onmiddellijke verwerking", + "consumer-per-partition": "Stuur een berichtenquête voor elke consument", + "consumer-per-partition-hint": "Schakel afzonderlijke verbruiker(s) in voor elke partitie", + "processing-timeout": "Verwerking binnen, ms", + "batch-size": "Grootte van de partij", + "retries": "Aantal nieuwe pogingen (0 – onbeperkt)", + "failure-percentage": "Percentage mislukte berichten voor het overslaan van nieuwe pogingen", + "pause-between-retries": "Probeer het opnieuw binnen, sec", + "max-pause-between-retries": "Extra nieuwe poging binnen, sec", + "delete": "Queue verwijderen", + "copyId": "Queue-ID kopiëren", + "idCopiedMessage": "Queue-ID is gekopieerd naar klembord", + "description": "Omschrijving: __________", + "description-hint": "Deze tekst wordt weergegeven in de wachtrijbeschrijving in plaats van de geselecteerde strategie", + "alt-description": "Strategie indienen: {{submitStrategy}}, verwerkingsstrategie: {{processingStrategy}}", + "strategies": { + "sequential-by-originator-label": "Opeenvolgend door opsteller", + "sequential-by-originator-hint": "Het nieuwe bericht voor bijvoorbeeld device A wordt pas verzonden als het vorige bericht voor device A is bevestigd", + "sequential-by-tenant-label": "Sequentieel per tenant", + "sequential-by-tenant-hint": "Nieuw bericht voor bijvoorbeeld tenant A wordt pas verzonden als het vorige bericht voor tenant A is bevestigd", + "sequential-label": "Sequentieel", + "sequential-hint": "Nieuw bericht wordt pas verzonden als het vorige bericht is bevestigd", + "burst-label": "Barsten", + "burst-hint": "Alle berichten worden verzonden naar de rule chains in de volgorde waarin ze binnenkomen", + "batch-label": "Batch", + "batch-hint": "De nieuwe batch wordt pas ingediend als de vorige batch is bevestigd", + "skip-all-failures-label": "Sla alle storingen over", + "skip-all-failures-hint": "Negeer alle fouten", + "skip-all-failures-and-timeouts-label": "Sla alle storingen en time-outs over", + "skip-all-failures-and-timeouts-hint": "Negeer alle storingen en time-outs", + "retry-all-label": "Probeer alles opnieuw", + "retry-all-hint": "Probeer alle berichten uit het verwerkingspakket opnieuw uit te voeren", + "retry-failed-label": "Opnieuw proberen mislukt", + "retry-failed-hint": "Probeer alle mislukte berichten opnieuw uit het verwerkingspakket", + "retry-timeout-label": "Time-out opnieuw proberen", + "retry-timeout-hint": "Probeer alle time-outberichten opnieuw uit het verwerkingspakket", + "retry-failed-and-timeout-label": "Opnieuw proberen mislukt en time-out", + "retry-failed-and-timeout-hint": "Probeer alle mislukte en getimede berichten opnieuw uit het verwerkingspakket" + } + }, + "server-error": { + "general": "Algemene serverfout", + "authentication": "Authenticatie fout", + "jwt-token-expired": "JWT-token is verlopen", + "tenant-trial-expired": "Proefperiode tenant verlopen", + "credentials-expired": "Inloggegevens verlopen", + "permission-denied": "Toestemming geweigerd", + "invalid-arguments": "Ongeldige argumenten", + "bad-request-params": "Ongeldige aanvraagparameters", + "item-not-found": "Object niet gevonden", + "too-many-requests": "Te veel aanvragen", + "too-many-updates": "Te veel updates" + }, + "tenant": { + "tenant": "Tenant", + "tenants": "Tenants", + "management": "Beheer van tenants", + "add": "Tenant toevoegen", + "admins": "Beheerders", + "manage-tenant-admins": "Tenant beheerders beheren", + "delete": "Tenant verwijderen", + "add-tenant-text": "Nieuwe tenant toevoegen", + "no-tenants-text": "Geen tenants gevonden", + "tenant-details": "Gegevens tenant", + "title-max-length": "Titel moet kleiner zijn dan 256 tekens", + "delete-tenant-title": "Weet u zeker dat u de tenant '{{tenantTitle}}' wilt verwijderen?", + "delete-tenant-text": "Let op, na de bevestiging worden de tenant en alle gerelateerde gegevens onherstelbaar.", + "delete-tenants-title": "Weet u zeker dat u { count, plural, =1 {1 tenant} andere {# tenants} } wilt verwijderen?", + "delete-tenants-action-title": "Verwijder { count, plural, =1 {1 tenant} andere {# tenants} }", + "delete-tenants-text": "Let op, na de bevestiging worden alle geselecteerde tenants verwijderd en worden alle gerelateerde gegevens onherstelbaar.", + "title": "Titel", + "title-required": "Titel is vereist.", + "description": "Omschrijving: __________", + "details": "Details", + "events": "Events", + "copyId": "Tenant-id kopiëren", + "idCopiedMessage": "Tenant-id is gekopieerd naar klembord", + "select-tenant": "Selecteer tenant", + "no-tenants-matching": "Er zijn geen tenants gevonden die overeenkomen met '{{entity}}'.", + "tenant-required": "Tenant is verplicht", + "allow-white-labeling": "White Labeling toestaan", + "allow-customer-white-labeling": "White labeling van klanten toestaan", + "search": "Tenants zoeken", + "selected-tenants": "{ count, plural, =1 {1 tenant} andere {# tenants} } geselecteerd", + "isolated-tb-rule-engine": "Verwerking in geïsoleerde ThingsBoard Rule Engine-container", + "isolated-tb-rule-engine-details": "Vereist afzonderlijke microservice(s) per geïsoleerde tenant" + }, + "tenant-profile": { + "tenant-profile": "Profiel van de tenant", + "tenant-profiles": "Profielen van tenants", + "add": "Huurdersprofiel toevoegen", + "add-profile": "Profiel toevoegen", + "edit": "Huurdersprofiel bewerken", + "tenant-profile-details": "Details van tenantsprofiel", + "no-tenant-profiles-text": "Geen tenantsprofielen gevonden", + "name-max-length": "Naam moet kleiner zijn dan 256 tekens", + "search": "Tentant profielen zoeken", + "selected-tenant-profiles": "{ count, plural, =1 {1 tenant profile} andere {# tenant profiles} } geselecteerd", + "no-tenant-profiles-matching": "Er zijn geen tenantprofielen gevonden die overeenkomen met '{{entity}}'.", + "tenant-profile-required": "Huurdersprofiel is vereist", + "idCopiedMessage": "De profiel-id van de tenant is gekopieerd naar het klembord", + "set-default": "Tenantprofiel standaard instellen", + "delete": "Tenantprofiel verwijderen", + "copyId": "Tenantprofiel-id kopiëren", + "name": "Naam", + "name-required": "Naam is verplicht.", + "data": "Profiel gegevens", + "profile-configuration": "Profiel configuratie", + "description": "Omschrijving: __________", + "default": "Verstek", + "delete-tenant-profile-title": "Weet u zeker dat u het tenantsprofiel '{{tenantProfileName}}' wilt verwijderen?", + "delete-tenant-profile-text": "Let op, na de bevestiging wordt het tenantsprofiel en alle gerelateerde gegevens onherstelbaar.", + "delete-tenant-profiles-title": "Weet u zeker dat u { count, plural, =1 {1 tenant profile} andere {# tenant profiles} } wilt verwijderen?", + "delete-tenant-profiles-text": "Opgelet, na de bevestiging worden alle geselecteerde tenantsprofielen verwijderd en kunnen alle gerelateerde gegevens niet meer worden hersteld.", + "set-default-tenant-profile-title": "Weet u zeker dat u het tenantsprofiel standaard '{{tenantProfileName}}' wilt maken?", + "set-default-tenant-profile-text": "Na de bevestiging wordt het tenantsprofiel als standaard gemarkeerd en wordt het gebruikt voor nieuwe tenants waarvoor geen profiel is opgegeven.", + "no-tenant-profiles-found": "Er zijn geen tenantsprofielen gevonden.", + "create-new-tenant-profile": "Maak een nieuwe aan!", + "create-tenant-profile": "Nieuw tenantsprofiel maken", + "import": "Tenantprofiel importeren", + "export": "Tenantprofiel exporteren", + "export-failed-error": "Kan tenantprofiel niet exporteren: {{error}}", + "tenant-profile-file": "Bestand met tenantsprofiel", + "invalid-tenant-profile-file-error": "Kan tenantprofiel niet importeren: Ongeldige gegevensstructuur van tenantprofiel.", + "advanced-settings": "Geavanceerde instellingen", + "entities": "Entiteiten", + "rule-engine": "Rule engine", + "time-to-live": "Tijd om te leven", + "alarms-and-notifications": "Alarmen en meldingen", + "ota-files-in-bytes": "OTA-bestanden in bytes", + "ws-title": "WS", + "unlimited": "(0 - onbeperkt)", + "maximum-devices": "Maximaal aantal Devices", + "maximum-devices-required": "Het maximale aantal devices is vereist.", + "maximum-devices-range": "Het maximale aantal devices mag niet negatief zijn", + "maximum-assets": "Maximaal aantal asset", + "maximum-assets-required": "Het maximale aantal asset is vereist.", + "maximum-assets-range": "Het maximumaantal items mag niet negatief zijn", + "maximum-customers": "Maximaal aantal klanten", + "maximum-customers-required": "Het maximale aantal klanten is vereist.", + "maximum-customers-range": "Het maximale aantal klanten mag niet negatief zijn", + "maximum-users": "Maximaal aantal gebruikers", + "maximum-users-required": "Het maximale aantal gebruikers is vereist.", + "maximum-users-range": "Het maximumaantal gebruikers mag niet negatief zijn", + "maximum-dashboards": "Dashboards maximaal aantal", + "maximum-dashboards-required": "Het maximale aantal dashboards is vereist.", + "maximum-dashboards-range": "Het maximumaantal dashboards mag niet negatief zijn", + "maximum-rule-chains": "Maximaal aantal rule chains", + "maximum-rule-chains-required": "Het maximale aantal rule chains is vereist.", + "maximum-rule-chains-range": "Het maximale aantal rule chains mag niet negatief zijn", + "maximum-integrations": "Integraties maximaal aantal", + "maximum-integrations-required": "Integraties maximaal aantal is vereist.", + "maximum-integrations-range": "Het maximale aantal integraties mag niet negatief zijn", + "maximum-converters": "Converters maximaal aantal", + "maximum-converters-required": "Het maximale aantal converters is vereist.", + "maximum-converters-range": "Het maximale aantal converters mag niet negatief zijn", + "maximum-scheduler-events": "Maximaal aantal scheduler events", + "maximum-scheduler-events-required": "Het maximale aantal scheduler events is vereist.", + "maximum-scheduler-events-range": "Het maximale aantal scheduler events mag niet negatief zijn", + "maximum-resources-sum-data-size": "Totale grootte van bronbestanden", + "maximum-resources-sum-data-size-required": "De somgrootte van bronbestanden is vereist.", + "maximum-resources-sum-data-size-range": "De somgrootte van resourcebestanden mag niet negatief zijn", + "maximum-ota-packages-sum-data-size": "Totale grootte van OTA-pakketbestanden", + "maximum-ota-package-sum-data-size-required": "De somgrootte van OTA-pakketbestanden is vereist.", + "maximum-ota-package-sum-data-size-range": "De somgrootte van OTA-pakketbestanden mag niet negatief zijn", + "rest-requests-for-tenant": "REST-aanvragen voor tenant", + "transport-tenant-telemetry-msg-rate-limit": "Telemetrieberichten van tenants vervoeren", + "transport-tenant-telemetry-data-points-rate-limit": "Telemetrie gegevenspunten voor transporttenants", + "transport-device-msg-rate-limit": "Berichten over transportmiddelen", + "transport-device-telemetry-msg-rate-limit": "Telemetrieberichten van transport devices", + "transport-device-telemetry-data-points-rate-limit": "Telemetrie gegevenspunten voor transport devices", + "tenant-entity-export-rate-limit": "Aanmaken van entiteitsversies", + "tenant-entity-import-rate-limit": "Laden van entiteitsversie", + "tenant-notification-request-rate-limit": "Verzoeken om kennisgeving", + "tenant-notification-requests-per-rule-rate-limit": "Notificatieverzoeken per notificatieregel", + "max-transport-messages": "Maximaal aantal transportberichten", + "max-transport-messages-required": "Transportberichten maximaal aantal is vereist.", + "max-transport-messages-range": "Het maximale aantal transportberichten mag niet negatief zijn", + "max-transport-data-points": "Maximaal aantal transportdatapunten", + "max-transport-data-points-required": "Er is een maximaal aantal transportdatapunten vereist.", + "max-transport-data-points-range": "Het maximale aantal transport gegevenspunten mag niet negatief zijn", + "max-r-e-executions": "Maximaal aantal uitvoeringen van rule engine", + "max-r-e-executions-required": "Het maximale aantal uitvoeringen van de rule engine is vereist.", + "max-r-e-executions-range": "Het maximale aantal uitvoeringen van de rule engine mag niet negatief zijn", + "max-j-s-executions": "Maximaal aantal JavaScript-uitvoeringen", + "max-j-s-executions-required": "Het maximale aantal JavaScript-uitvoeringen is vereist.", + "max-j-s-executions-range": "Het maximale aantal JavaScript-uitvoeringen mag niet negatief zijn", + "max-d-p-storage-days": "Maximaal aantal bewaardagen datapunten", + "max-d-p-storage-days-required": "Het maximale aantal opslagdagen voor datapunten is vereist.", + "max-d-p-storage-days-range": "Het maximale aantal opslagdagen voor gegevenspunten kan niet negatief zijn", + "default-storage-ttl-days": "Opslag TTL-dagen standaard", + "default-storage-ttl-days-required": "Standaard zijn TTL-dagen voor opslag vereist.", + "default-storage-ttl-days-range": "Opslag TTL-dagen kunnen standaard niet negatief zijn", + "alarms-ttl-days": "Alarmen TTL-dagen", + "alarms-ttl-days-required": "Alarmen TTL-dagen vereist", + "alarms-ttl-days-days-range": "Alarmen TTL-dagen kunnen niet negatief zijn", + "rpc-ttl-days": "RPC TTL-dagen", + "rpc-ttl-days-required": "RPC TTL-dagen vereist", + "rpc-ttl-days-days-range": "RPC TTL-dagen kunnen niet negatief zijn", + "max-rule-node-executions-per-message": "Maximaal aantal uitvoeringen van rule node per bericht", + "max-rule-node-executions-per-message-required": "MRule node per bericht voert het maximale aantal uit dat wordt uitgevoerd.", + "max-rule-node-executions-per-message-range": "Rule node per bericht dat wordt uitgevoerd, het maximale aantal kan niet negatief zijn", + "max-emails": "Maximaal aantal verzonden e-mails", + "max-emails-required": "Het maximale aantal verzonden e-mails is vereist.", + "max-emails-range": "Het maximale aantal verzonden e-mails mag niet negatief zijn", + "max-sms": "Maximaal aantal sms-berichten", + "max-sms-required": "Het maximale aantal sms-berichten is vereist.", + "max-sms-range": "Het maximale aantal verzonden sms'jes mag niet negatief zijn", + "max-created-alarms": "Maximaal aantal alarmen gemaakt", + "max-created-alarms-required": "Het maximale aantal alarmen is vereist.", + "max-created-alarms-range": "Alarmen gemaakt maximaal aantal negatief zijn", + "no-queue": "Geen queue geconfigureerd", + "add-queue": "Queue toevoegen", + "queues-with-count": "Queues ({{count}})", + "tenant-rest-limits": "REST-aanvragen voor tenant", + "customer-rest-limits": "REST-aanvragen voor klant", + "incorrect-pattern-for-rate-limits": "Het formaat bestaat uit door komma's gescheiden paren van capaciteit en punt (in seconden) met een dubbele punt ertussen, bijvoorbeeld 100:1,2000:60", + "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 queue wordt ook beperkt door de systeemconfiguratie.", + "cassandra-tenant-limits-configuration": "Cassandra-query voor tenant", + "ws-limit-max-sessions-per-tenant": "Sessies per tenant maximaal aantal", + "ws-limit-max-sessions-per-customer": "Maximaal aantal sessies per klant", + "ws-limit-max-sessions-per-regular-user": "Sessies per reguliere gebruiker maximaal aantal", + "ws-limit-max-sessions-per-public-user": "Maximaal aantal sessies per openbare gebruiker", + "ws-limit-queue-per-session": "Maximale grootte van berichtenwachtrij per sessie", + "ws-limit-max-subscriptions-per-tenant": "Maximaal aantal abonnementen per tenant", + "ws-limit-max-subscriptions-per-customer": "Abonnementen per klant maximum aantal", + "ws-limit-max-subscriptions-per-regular-user": "Abonnementen per gewone gebruiker maximum aantal", + "ws-limit-max-subscriptions-per-public-user": "Abonnementen per openbare gebruiker maximum aantal", + "ws-limit-updates-per-session": "WS-updates per sessie", + "rate-limits": { + "add-limit": "Limiet toevoegen", + "advanced-settings": "Geavanceerde instellingen", + "edit-limit": "Limiet bewerken", + "but-less-than": "maar minder dan", + "edit-transport-tenant-msg-title": "Snelheidslimieten voor berichten van transporttenants bewerken", + "edit-transport-tenant-telemetry-msg-title": "Snelheidslimieten voor telemetrie berichten van transporttenants bewerken", + "edit-transport-tenant-telemetry-data-points-title": "Snelheidslimieten voor telemetrie gegevenspunten van transporttenants bewerken", + "edit-transport-device-msg-title": "Snelheidslimieten voor berichten van transport devices bewerken", + "edit-transport-device-telemetry-msg-title": "Snelheidslimieten voor telemetrie berichten van transport devices bewerken", + "edit-transport-device-telemetry-data-points-title": "Snelheidslimieten voor telemetriegegevenspunten van transport devices bewerken", + "edit-tenant-rest-limits-title": "REST-aanvragen voor tarieflimieten voor tenants bewerken", + "edit-customer-rest-limits-title": "REST-aanvragen voor snelheidslimieten voor klanten bewerken", + "edit-ws-limit-updates-per-session-title": "Snelheidslimieten voor WS-updates per sessie bewerken", + "edit-cassandra-tenant-limits-configuration-title": "Cassandra-query bewerken voor tarieflimieten voor tenants", + "edit-tenant-entity-export-rate-limit-title": "Limieten voor het maken van entiteitsversies bewerken", + "edit-tenant-entity-import-rate-limit-title": "Limieten voor de laadsnelheid van entiteitsversies bewerken", + "edit-tenant-notification-request-rate-limit-title": "Snelheidslimieten voor meldingsverzoeken bewerken", + "edit-tenant-notification-requests-per-rule-rate-limit-title": "Snelheidslimieten voor meldingsverzoeken per meldingsregel bewerken", + "messages-per": "berichten per", + "not-set": "Niet ingesteld", + "number-of-messages": "Aantal berichten", + "number-of-messages-required": "Het aantal berichten is vereist.", + "number-of-messages-min": "Minimale waarde is 1.", + "preview": "Voorbeeld", + "per-seconds": "Per seconde", + "per-seconds-required": "Tijdtarief is vereist.", + "per-seconds-min": "Minimale waarde is 1.", + "rate-limits": "Limieten voor tarieven", + "remove-limit": "Limiet verwijderen", + "transport-tenant-msg": "Berichten van tenants vervoeren", + "transport-tenant-telemetry-msg": "Telemetrieberichten van tenants vervoeren", + "transport-tenant-telemetry-data-points": "Telemetriege gevenspunten voor transport tenants", + "transport-device-msg": "Berichten over transportmiddelen", + "transport-device-telemetry-msg": "Telemetrieberichten van transport devices", + "transport-device-telemetry-data-points": "Telemetriegegevenspunten voor transport devices", + "sec": "seconde" + } + }, + "timeinterval": { + "seconds-interval": "{ seconds, plural, =1 {1 second} andere {# seconds} }", + "minutes-interval": "{ minutes, plural, =1 {1 minute} andere {# minutes} }", + "hours-interval": "{ hours, plural, =1 {1 hour} andere {# hours} }", + "days-interval": "{ days, plural, =1 {1 day} andere {# days} }", + "days": "Dagen", + "hours": "Uren", + "minutes": "Notulen", + "seconds": "Seconden", + "advanced": "Geavanceerd", + "predefined": { + "yesterday": "Gisteren", + "day-before-yesterday": "Eergisteren", + "this-day-last-week": "Deze dag vorige week", + "previous-week": "Vorige week (zo - za)", + "previous-week-iso": "Vorige week (ma - zo)", + "previous-month": "Vorige maand", + "previous-quarter": "Vorig kwartaal", + "previous-half-year": "Vorig halfjaar", + "previous-year": "Vorig jaar", + "current-hour": "Huidig uur", + "current-day": "Huidige dag", + "current-day-so-far": "Huidige dag tot nu toe", + "current-week": "Huidige week (zo - za)", + "current-week-iso": "Huidige week (ma - zo)", + "current-week-so-far": "Huidige week tot nu toe (zo - za)", + "current-week-iso-so-far": "Huidige week tot nu toe (ma - zo)", + "current-month": "Huidige maand", + "current-month-so-far": "Huidige maand tot nu toe", + "current-quarter": "Huidig kwartaal", + "current-quarter-so-far": "Huidig kwartaal tot nu toe", + "current-half-year": "Huidig halfjaar", + "current-half-year-so-far": "Huidig halfjaar tot nu toe", + "current-year": "Huidig jaar", + "current-year-so-far": "Huidig jaar tot nu toe" + } + }, + "timeunit": { + "milliseconds": "Milliseconden", + "seconds": "Seconden", + "minutes": "Notulen", + "hours": "Uren", + "days": "Dagen" + }, + "timewindow": { + "years": "{ years, plural, =1 { year } andere {# years } }", + "months": "{ months, plural, =1 { month } andere {# months } }", + "weeks": "{ weeks, plural, =1 { week } andere {# weeks } }", + "days": "{ days, plural, =1 { day } andere {# days } }", + "hours": "{ hours, plural, =0 { hour } =1 {1 hour } andere {# hours } }", + "hr": "{{ hr }} uur", + "minutes": "{ minutes, plural, =0 { minute } =1 {1 minute } andere {# minutes } }", + "min": "{{ min }} min", + "seconds": "{ seconds, plural, =0 { second } =1 {1 second } andere {# seconds } }", + "sec": "{{ sec }} sec", + "short": { + "days": "{ days, plural, =1 {1 day } andere {# days } }", + "hours": "{ hours, plural, =1 {1 hour } andere {# hours } }", + "minutes": "{{minutes}} min", + "seconds": "{{seconds}} sec" + }, + "realtime": "Realtime", + "history": "Geschiedenis", + "last-prefix": "laatste", + "period": "van {{ startTime }} tot {{ endTime }}", + "edit": "Tijdvenster bewerken", + "date-range": "Periode", + "for-all-time": "Permanent", + "last": "Laatste", + "time-period": "Periode", + "hide": "Verbergen", + "interval": "Interval", + "just-now": "Daarnet", + "ago": "geleden" + }, + "user": { + "all": "Alle", + "all-users": "Alle gebruikers", + "groups": "Groepen", + "user": "Gebruiker", + "users": "Gebruikers", + "management": "Gebruikersbeheer", + "customer-users": "Gebruikers van klanten", + "tenant-admins": "Tenant Admins", + "sys-admin": "Systeembeheerder", + "tenant-admin": "Tenant beheerder", + "customer": "Klant", + "anonymous": "Anoniem", + "add": "Gebruiker toevoegen", + "delete": "Gebruiker verwijderen", + "add-user-text": "Nieuwe gebruiker toevoegen", + "no-users-text": "Geen gebruikers gevonden", + "user-details": "Gegevens van de gebruiker", + "delete-users": "Gebruikers verwijderen", + "delete-user-title": "Weet u zeker dat u de '{{userEmail}}' van de gebruiker wilt verwijderen?", + "delete-user-text": "Opgelet, na de bevestiging worden de gebruiker en alle gerelateerde gegevens onherstelbaar.", + "delete-users-title": "Weet u zeker dat u { count, plural, =1 {1 user} andere {# users} } wilt verwijderen?", + "delete-users-action-title": "Verwijder { count, plural, =1 {1 user} andere {# users} }", + "delete-users-text": "Opgelet, na de bevestiging worden alle geselecteerde gebruikers verwijderd en kunnen alle gerelateerde gegevens niet meer worden hersteld.", + "activation-email-sent-message": "Activeringsmail is succesvol verzonden!", + "resend-activation": "Activering opnieuw verzenden", + "email": "E-mail", + "email-required": "E-mail is vereist.", + "invalid-email-format": "Ongeldig e-mailformaat.", + "first-name": "Voornaam", + "last-name": "Achternaam", + "description": "Omschrijving: __________", + "default-dashboard": "Standaard dashboard", + "always-fullscreen": "Altijd volledig scherm", + "select-user": "Selecteer gebruiker", + "no-users-matching": "Er zijn geen gebruikers gevonden die overeenkomen met '{{entity}}'.", + "user-required": "Gebruiker is vereist", + "activation-method": "Activeringsmethode", + "display-activation-link": "Activeringslink weergeven", + "send-activation-mail": "Activeringsmail versturen", + "activation-link": "Activeringslink voor gebruiker", + "activation-link-text": "Om de gebruiker te activeren gebruikt u de volgende activation link:", + "copy-activation-link": "Activeringslink kopiëren", + "activation-link-copied-message": "De activeringslink van de gebruiker is gekopieerd naar het klembord", + "details": "Details", + "login-as-tenant-admin": "Aanmelden als tenantbeheerder", + "login-as-customer-user": "Inloggen als klantgebruiker", + "select-group-to-add": "Selecteer doelgroep om geselecteerde gebruikers toe te voegen", + "select-group-to-move": "Selecteer de doelgroep om geselecteerde gebruikers te verplaatsen", + "remove-users-from-group": "Weet je zeker dat je { count, plural, =1 {1 user} andere {# users} } uit groep '{{entityGroup}}' wilt verwijderen?", + "group": "Groep gebruikers", + "list-of-groups": "{ count, plural, =1 {One user group} andere {List of # user groups} }", + "group-name-starts-with": "Gebruikersgroepen waarvan de naam begint met '{{prefix}}'", + "search": "Gebruikers zoeken", + "selected-users": "{ count, plural, =1 {1 user} andere {# users} } geselecteerd", + "disable-account": "Gebruikersaccount uitschakelen", + "enable-account": "Gebruikersaccount inschakelen", + "enable-account-message": "Gebruikersaccount is succesvol ingeschakeld!", + "disable-account-message": "Gebruikersaccount is met succes uitgeschakeld!", + "copyId": "Kopieer gebruikers-ID", + "idCopiedMessage": "Gebruikers-ID is gekopieerd naar klembord", + "user-list": "Lijst met gebruikers", + "user-list-required": "Gebruikerslijst is vereist" + }, + "value": { + "type": "Soort waarde", + "string": "Snaar", + "string-value": "Tekenreeks waarde", + "string-value-required": "Tekenreekswaarde is vereist", + "integer": "Geheel getal", + "integer-value": "Gehele waarde", + "integer-value-required": "Geheel getal is vereist", + "invalid-integer-value": "Ongeldige waarde van een geheel getal", + "double": "Dubbel", + "double-value": "Dubbele waarde", + "double-value-required": "Dubbele waarde is vereist", + "boolean": "Booleaans", + "boolean-value": "Booleaanse waarde", + "false": "Vals", + "true": "Waar", + "long": "Lang", + "json": "JSON", + "json-value": "JSON-waarde", + "json-value-invalid": "JSON-waarde heeft een ongeldige indeling", + "json-value-required": "JSON-waarde is vereist." + }, + "version-control": { + "version-control": "Versiebeheer", + "management": "Beheer van versiebeheer", + "search": "Versies zoeken", + "branch": "Tak", + "default": "Verstek", + "select-branch": "Selecteer filiaal", + "branch-required": "Filiaal is vereist", + "create-entity-version": "Entiteitsversie maken", + "version-name": "Versienaam", + "version-name-required": "Versienaam is vereist", + "author": "Auteur", + "export-relations": "Exportrelaties", + "export-attributes": "Attributen exporteren", + "export-credentials": "Inloggegevens exporteren", + "export-group-entities": "Groepsentiteiten exporteren", + "export-roles": "Rollen exporteren", + "entity-versions": "Versies van entiteiten", + "versions": "Versies", + "created-time": "Gecreëerde tijd", + "version-id": "Versie-ID", + "no-entity-versions-text": "Geen entiteitsversies gevonden", + "no-versions-text": "Geen versies gevonden", + "copy-full-version-id": "Kopieer de volledige versie-id", + "create-version": "Versie maken", + "creating-version": "Versie maken... Een ogenblik geduld", + "nothing-to-commit": "Geen wijzigingen om vast te leggen", + "restore-version": "Versie herstellen", + "restore-entity-from-version": "Entiteit herstellen vanaf versie '{{versionName}}'", + "restoring-entity-version": "Entiteitsversie herstellen... Een ogenblik geduld", + "load-relations": "Relaties met belasting", + "load-attributes": "Attributen laden", + "load-credentials": "Inloggegevens laden", + "load-group-entities": "Groepsentiteiten laden", + "load-roles": "Rollen laden", + "compare-with-current": "Vergelijk met de huidige", + "diff-entity-with-version": "Verschil met entiteitsversie '{{versionName}}'", + "previous-difference": "Vorig verschil", + "next-difference": "Volgende Verschil", + "current": "Actueel", + "differences": "{ count, plural, =1 {1 difference} andere {# differences} }", + "create-entities-version": "Versie van entiteiten maken", + "default-sync-strategy": "Standaard synchronisatiestrategie", + "sync-strategy-merge": "Fuseren", + "sync-strategy-overwrite": "Overschrijven", + "entities-to-export": "Te exporteren entiteiten", + "entities-to-restore": "Entiteiten die moeten worden hersteld", + "sync-strategy": "Synchronisatie strategie", + "all-entities": "Alle entiteiten", + "no-entities-to-export-prompt": "Geef entiteiten op die u wilt exporteren", + "no-entities-to-restore-prompt": "Geef entiteiten op die u wilt herstellen", + "add-entity-type": "Entiteitstype toevoegen", + "remove-all": "Alles verwijderen", + "version-create-result": "{ added, plural, =0 {No entities} =1 {1 entity} andere {# entities} } toegevoegd.
{ modified, plural, =0 {No entities} =1 {1 entity} andere {# entities} } gewijzigd.
{ removed, plural, =0 {No entities} =1 {1 entity} andere {# entities} } verwijderd.", + "remove-other-entities": "Andere entiteiten verwijderen", + "find-existing-entity-by-name": "Bestaande entiteit zoeken op naam", + "restore-entities-from-version": "Entiteiten herstellen vanaf versie '{{versionName}}'", + "restoring-entities-from-version": "Entiteiten herstellen... Een ogenblik geduld", + "no-entities-restored": "Geen entiteiten hersteld", + "created": "{{created}} gemaakt", + "updated": "{{updated}} geüpdatet", + "deleted": "{{deleted}} geschrapt", + "groups-created": "{ created, plural, =1 {1 group} andere {# groups} } gemaakt", + "groups-updated": "{ updated, plural, =1 {1 group} andere {# groups} } bijgewerkt", + "groups-deleted": "{ deleted, plural, =1 {1 group} andere {# groups} } verwijderd", + "remove-other-entities-confirm-text": "Opgelet! Hiermee worden alle huidige entiteiten
die niet aanwezig zijn in de versie die u wilt herstellen, permanent verwijderd.

Typ andere entiteiten verwijderen om te bevestigen.", + "auto-commit-to-branch": "Automatisch vastleggen op {{ branch }} filiaal", + "default-create-entity-version-name": "{{entityName}} update", + "sync-strategy-merge-hint": "Hiermee maakt of actualiseert u geselecteerde entiteiten in de opslagplaats. Alle andere opslagplaatsentiteiten worden niet gewijzigd.", + "sync-strategy-overwrite-hint": "Hiermee maakt of actualiseert u geselecteerde entiteiten in de opslagplaats. Alle andere opslagplaatsentiteiten worden verwijderd.", + "device-credentials-conflict": "Kan het device niet laden met externe id {{entityId}}
omdat dezelfde referenties al aanwezig zijn in de database voor een ander device.
Overweeg om de instelling voor laadreferenties in het herstelformulier uit te schakelen.", + "missing-referenced-entity": "Het laden van de {{sourceEntityTypeName}} met externe id {{sourceEntityId}}
omdat het verwijst naar ontbrekende {{targetEntityTypeName}} met id {{targetEntityId}}.", + "add-entity-groups": "Entiteitsgroepen toevoegen", + "entity-groups": "Entiteitsgroepen", + "integration-routing-key-conflict": "Kan de integratie met externe id niet laden {{entityId}}
vanwege dezelfde integratiesleutel is al aanwezig in de database voor een andere integratie.
Overweeg om de instelling voor het automatisch genereren van integratiesleutels in het herstelformulier in te schakelen.", + "auto-generate-integration-key": "Integratiesleutel automatisch genereren", + "runtime-failed": "Mislukt: {{message}}", + "auto-commit-settings-read-only-hint": "De functie voor automatisch vastleggen werkt niet met de ingeschakelde niet editeerbaar optie in de instellingen van de opslagplaats." + }, + "widget": { + "widget-library": "Widgets Bibliotheek", + "widget-bundle": "Widgets Bundel", + "all-bundles": "Alle bundels", + "select-widgets-bundle": "Selecteer widgetsbundel", + "management": "Beheer van widgets", + "editor": "Widget-editor", + "widget-type-not-found": "Probleem met het laden van de configuratie van de widget.
Waarschijnlijk geassocieerd\n Widgettype is verwijderd.", + "widget-type-load-error": "Widget is niet geladen vanwege de volgende fouten:", + "remove": "Widget verwijderen", + "edit": "Widget bewerken", + "remove-widget-title": "Weet je zeker dat je de widget '{{widgetTitle}}' wilt verwijderen?", + "remove-widget-text": "Na de bevestiging worden de widget en alle gerelateerde gegevens onherstelbaar.", + "timeseries": "Timeseries", + "search-data": "Zoekgegevens", + "no-data-found": "Geen gegevens gevonden", + "latest": "Meest recente waarden", + "rpc": "Controle widget", + "alarm": "Alarm widget", + "static": "Statische widget", + "select-widget-type": "Selecteer widgettype", + "missing-widget-title-error": "De titel van de widget moet worden opgegeven!", + "widget-saved": "Widget opgeslagen", + "unable-to-save-widget-error": "Kan widget niet opslaan! Widget heeft fouten!", + "save": "Widget opslaan", + "saveAs": "Widget opslaan als", + "save-widget-type-as": "Widgettype opslaan als", + "save-widget-type-as-text": "Voer een nieuwe widgettitel in en/of selecteer de bundel met doelwidgets", + "toggle-fullscreen": "Volledig scherm in- en uitschakelen", + "run": "Widget uitvoeren", + "title": "Titel van de widget", + "title-required": "De titel van de widget is vereist.", + "type": "Type widget", + "resources": "Weg", + "resource-url": "JavaScript/CSS-URL", + "resource-is-module": "Is-module", + "remove-resource": "Bron verwijderen", + "add-resource": "Bron toevoegen", + "html": ".HTML", + "tidy": "Ordelijk", + "css": ".CSS", + "settings-schema": "Schema Instellingen", + "datakey-settings-schema": "Schema voor instellingen voor gegevenssleutels", + "latest-datakey-settings-schema": "Schema met meest recente instellingen voor gegevenssleutels", + "widget-settings": "Widget instellingen", + "description": "Omschrijving: __________", + "image-preview": "Voorbeeld van afbeelding", + "settings-form-selector": "Formulierkiezer voor instellingen", + "data-key-settings-form-selector": "Formulierkiezer voor instellingen voor gegevenssleutels", + "latest-data-key-settings-form-selector": "Formulierkiezer voor de meest recente gegevenssleutelinstellingen", + "javascript": "Javascript", + "js": ".JS", + "remove-widget-type-title": "Weet je zeker dat je het widgettype '{{widgetName}}' wilt verwijderen?", + "remove-widget-type-text": "Na de bevestiging worden het type widget en alle gerelateerde gegevens onherstelbaar.", + "remove-widget-type": "Widgettype verwijderen", + "add-widget-type": "Nieuw widgettype toevoegen", + "widget-type-load-failed-error": "Kan widgettype niet laden!", + "widget-template-load-failed-error": "Kan widgetsjabloon niet laden!", + "add": "Widget toevoegen", + "undo": "Wijzigingen in widgets ongedaan maken", + "export": "Widget exporteren", + "export-data": "Widgetgegevens exporteren", + "export-to-csv": "Exporteer gegevens naar CSV...", + "export-to-excel": "Gegevens exporteren naar XLS...", + "export-to-excel-xlsx": "Gegevens exporteren naar XLSX...", + "no-data": "Geen gegevens om weer te geven op widget", + "data-overflow": "Widget geeft {{count}} van {{total}} entiteiten weer", + "alarm-data-overflow": "Widget geeft alarmen weer voor {{allowedEntities}} (maximaal toegestane) entiteiten van {{totalEntities}} entiteiten", + "search": "Widget zoeken", + "filter": "Type widgetfilter", + "loading-widgets": "Widgets worden geladen...", + "widget-template-error": "Ongeldige HTML-sjabloon voor widgets." + }, + "widget-action": { + "header-button": "Knop koptekst widget", + "open-dashboard-state": "Navigeer naar de nieuwe dashboardstatus", + "update-dashboard-state": "Huidige dashboardstatus bijwerken", + "open-dashboard": "Navigeer naar ander dashboard", + "custom": "Aangepaste actie", + "custom-pretty": "Aangepaste actie (met HTML-sjabloon)", + "custom-pretty-error-title": "Fout in aangepast dialoogvenster", + "custom-pretty-template-error": "Ongeldige sjabloon voor een aangepast dialoogvenster.", + "custom-pretty-controller-error": "Er is een fout opgetreden bij het evalueren van de aangepaste dialoogvensterfunctie.", + "mobile-action": "Mobiele actie", + "target-dashboard-state": "Status van doeldashboard", + "target-dashboard-state-required": "De status van het doeldashboard is vereist", + "set-entity-from-widget": "Entiteit instellen vanuit widget", + "target-dashboard": "Dashboard voor doelen", + "open-right-layout": "Dashboardlay-out rechts openen (mobiele weergave)", + "state-display-type": "Optie voor weergave van de status van het dashboard", + "open-normal": "Normaal", + "open-in-separate-dialog": "Openen in apart dialoogvenster", + "open-in-popover": "Openen in popover", + "dialog-title": "Titel van het dialoogvenster", + "dialog-hide-dashboard-toolbar": "Dashboardwerkbalk verbergen in dialoogvenster", + "dialog-width": "Dialoogvensterbreedte in procenten ten opzichte van viewportbreedte", + "dialog-height": "Dialoogvensterhoogte in procenten ten opzichte van viewporthoogte", + "dialog-size-range-error": "De procentuele waarde van de dialooggrootte moet tussen 1 en 100 liggen.", + "popover-preferred-placement": "Voorkeursplaatsing van de popover", + "popover-placement-top": "Boven", + "popover-placement-topLeft": "Linksboven", + "popover-placement-topRight": "Rechtsboven", + "popover-placement-right": "Rechts", + "popover-placement-rightTop": "Rechtsboven", + "popover-placement-rightBottom": "Rechtsonder", + "popover-placement-bottom": "Bodem", + "popover-placement-bottomLeft": "Linksonder", + "popover-placement-bottomRight": "Rechtsonder", + "popover-placement-left": "Links", + "popover-placement-leftTop": "Links boven", + "popover-placement-leftBottom": "Links onder", + "popover-hide-on-click-outside": "Popover verbergen bij klikken aan de buitenkant", + "popover-hide-dashboard-toolbar": "Dashboardwerkbalk verbergen in pop-over", + "popover-width": "Popover-breedte in browsereenheden (bijv. 100px, 25vw)", + "popover-height": "Popover-hoogte in browsereenheden (bijv. 100px, 25vh)", + "popover-style": "Popover-stijl", + "open-new-browser-tab": "Openen in een nieuw browsertabblad", + "mobile": { + "action-type": "Mobiel actietype", + "action-type-required": "Mobiel actietype is vereist", + "take-picture-from-gallery": "Maak een foto uit de galerij", + "take-photo": "Maak een foto", + "map-direction": "Routebeschrijving openen", + "map-location": "Locatie op de kaart openen", + "scan-qr-code": "QR-code scannen", + "make-phone-call": "Telefoneren", + "get-location": "Telefoonlocatie ophalen", + "take-screenshot": "Screenshot maken" + } + }, + "widgets-bundle": { + "current": "Huidige bundel", + "widgets-bundles": "Widgets Bundels", + "add": "Widgets-bundel toevoegen", + "delete": "Widgetsbundel verwijderen", + "title": "Titel", + "title-required": "Titel is vereist.", + "title-max-length": "Titel moet kleiner zijn dan 256 tekens", + "description": "Omschrijving: __________", + "image-preview": "Voorbeeld van afbeelding", + "add-widgets-bundle-text": "Nieuwe widgetsbundel toevoegen", + "no-widgets-bundles-text": "Geen widgetbundels gevonden", + "empty": "Widgets-bundel is leeg", + "details": "Details", + "widgets-bundle-details": "Details van de widgetsbundel", + "delete-widgets-bundle-title": "Weet je zeker dat je de widgets bundel '{{widgetsBundleTitle}}' wilt verwijderen?", + "delete-widgets-bundle-text": "Opgelet, na de bevestiging worden de widgetbundel en alle gerelateerde gegevens onherstelbaar.", + "delete-widgets-bundles-title": "Weet u zeker dat u { count, plural, =1 {1 widgets bundle} andere {# widgets bundles} } wilt verwijderen?", + "delete-widgets-bundles-action-title": "Verwijder { count, plural, =1 {1 widgets bundle} andere {# widgets bundles} }", + "delete-widgets-bundles-text": "Opgelet, na de bevestiging worden alle geselecteerde widgetbundels verwijderd en worden alle gerelateerde gegevens onherstelbaar.", + "no-widgets-bundles-matching": "Er zijn geen widgetbundels gevonden die overeenkomen met '{{widgetsBundle}}'.", + "widgets-bundle-required": "Widgets-bundel is vereist.", + "system": "Systeem", + "import": "Widgets importeren bundel", + "export": "Widgets exporteren bundel", + "export-failed-error": "Kan widgetbundel niet exporteren: {{error}}", + "create-new-widgets-bundle": "Nieuwe widgetsbundel maken", + "widgets-bundle-file": "Widgets bundel bestand", + "invalid-widgets-bundle-file-error": "Kan widgetbundel niet importeren: Ongeldige widgetbundel gegevensstructuur.", + "search": "Widgetbundels zoeken", + "selected-widgets-bundles": "{ count, plural, =1 {1 widgets bundle} andere {# widgets bundles} } geselecteerd", + "open-widgets-bundle": "Widgets-bundel openen", + "loading-widgets-bundles": "Widgets bundels worden geladen..." + }, + "widget-config": { + "data": "Gegevens", + "settings": "Instellingen", + "advanced": "Geavanceerd", + "title": "Titel", + "title-tooltip": "Titel Tooltip", + "general-settings": "Algemene instellingen", + "display-title": "Titel van widget weergeven", + "drop-shadow": "Schaduw verwijderen", + "enable-fullscreen": "Volledig scherm inschakelen", + "enable-data-export": "Gegevensexport inschakelen", + "background-color": "Achtergrondkleur", + "text-color": "Tekstkleur", + "padding": "Spacties", + "margin": "Marge", + "widget-style": "Widget stijl", + "widget-css": "Widget CSS", + "title-style": "Titel stijl", + "mobile-mode-settings": "Mobiele modus", + "order": "Bevelen", + "height": "Hoogte", + "mobile-hide": "Widget verbergen in mobiele modus", + "desktop-hide": "Widget verbergen in desktopmodus", + "units": "Speciaal symbool om naast waarde weer te geven", + "decimals": "Aantal cijfers na drijvende komma", + "timewindow": "Tijdvenster", + "use-dashboard-timewindow": "Dashboardtijdvenster gebruiken", + "display-timewindow": "Tijdvenster weergeven", + "legend": "Legende", + "display-legend": "Legende weergeven", + "datasources": "Gegevensbronnen", + "maximum-datasources": "Maximaal { count, plural, =1 {1 datasource is allowed.} andere {# datasources are allowed} }", + "timeseries-key-error": "Er moet ten minste één tijdreeksgegevenssleutel worden opgegeven", + "datasource-type": "Type", + "datasource-parameters": "Parameters", + "remove-datasource": "Gegevensbron verwijderen", + "add-datasource": "Gegevensbron toevoegen", + "target-device": "Doelapparaat", + "alarm-source": "Alarmbron", + "actions": "Acties", + "action": "Actie", + "add-action": "Actie toevoegen", + "search-actions": "Zoekacties", + "no-actions-text": "Geen acties gevonden", + "action-source": "Bron van actie", + "action-source-required": "Actiebron is vereist.", + "action-name": "Naam", + "action-name-required": "De naam van de actie is vereist.", + "action-name-not-unique": "Er bestaat al een andere actie met dezelfde naam.
De naam van de actie moet uniek zijn binnen dezelfde actiebron.", + "action-icon": "Pictogram", + "show-hide-action-using-function": "Actie tonen/verbergen met behulp van functie", + "action-type": "Type", + "action-type-required": "Actietype is vereist.", + "edit-action": "Actie bewerken", + "delete-action": "Actie verwijderen", + "delete-action-title": "Widgetactie verwijderen", + "delete-action-text": "Weet je zeker dat je de actie voor het verwijderen van widgets met de naam '{{actionName}}' wilt?", + "title-icon": "Titel icoon", + "display-icon": "Titelpictogram weergeven", + "icon-color": "Kleur van het pictogram", + "icon-size": "Grootte van het pictogram", + "advanced-settings": "Geavanceerde instellingen", + "data-settings": "Gegevensinstellingen", + "no-data-display-message": "Alternatief bericht 'Geen gegevens om weer te geven'", + "data-page-size": "Maximum aantal entiteiten per gegevensbron", + "settings-component-not-found": "Instellingen formuliercomponent niet gevonden voor selector '{{selector}}'" + }, + "widget-type": { + "import": "Type widget importeren", + "export": "Widgettype exporteren", + "export-failed-error": "Kan widgettype niet exporteren: {{error}}", + "create-new-widget-type": "Nieuw widgettype maken", + "widget-type-file": "Bestand van het type widget", + "invalid-widget-type-file-error": "Kan widgettype niet importeren: Ongeldige gegevensstructuur van het widgettype." + }, + "self-registration": { + "self-registration": "Zelf registratie", + "self-registration-url": "URL voor zelfregistratie", + "captcha-version": "reCAPTCHA-versie", + "captcha-action": "naam van de actie van het reCAPTCHA-logboek", + "captcha-site-key": "reCAPTCHA-sitesleutel", + "captcha-secret-key": "reCAPTCHA geheime sleutel", + "notification-email": "E-mail met melding", + "privacy-policy-text": "Tekst van het privacybeleid", + "terms-of-use-text": "Tekst van de gebruiksvoorwaarden", + "text-message-page": "Sms voor aanmeldingspagina", + "enable-mobile-self-registration": "Zelfregistratie inschakelen vanuit de mobiele applicatie", + "mobile-self-registration-title": "Instellingen voor zelfregistratie van mobiele applicaties", + "mobile-package": "Applicatie pakket", + "mobile-package-placeholder": "Vb.: my.example.app", + "mobile-package-hint": "Voor Android: uw eigen unieke applicatie-ID. Voor iOS: ID van productbundel.", + "mobile-package-required": "Aanvraagpakket is vereist", + "mobile-app-secret": "Geheim van de toepassing", + "invalid-mobile-app-secret": "Het geheim van de toepassing mag alleen alfanumerieke tekens bevatten en moet tussen de 16 en 2048 tekens lang zijn.", + "copy-mobile-app-secret": "Toepassingsgeheim kopiëren", + "mobile-app-scheme": "URL-schema van toepassing", + "mobile-app-scheme-placeholder": "Vb.: maatwerk", + "mobile-app-scheme-required": "Het URL-schema van de aanvraag is vereist", + "mobile-app-host": "Hostnaam van applicatie-URL", + "mobile-app-host-placeholder": "Bijv.: mijn.app.host", + "mobile-app-host-required": "Hostnaam van toepassings-URL is vereist", + "show-privacy-policy": "Toon Privacybeleid", + "show-terms-of-use": "Toon Gebruiksvoorwaarden", + "domain-settings": "Domein instellingen", + "general-settings": "Algemene instellingen" + }, + "solution-template": { + "solution-template": "Oplossing sjabloon", + "solution-templates": "Sjablonen voor oplossingen", + "management": "Oplossingssjablonen beheren", + "details": "Details", + "install": "Installeren", + "level": "Niveau", + "install-title": "Oplossingssjabloon succesvol geïnstalleerd", + "install-failed-title": "Installatie van oplossingssjabloon mislukt", + "instructions": "Aanwijzingen", + "goto-main-dashboard": "Ga naar het hoofddashboard", + "delete": "Verwijderen", + "delete-solution-title": "Weet u zeker dat u de oplossing '{{solutionTitle}}' wilt verwijderen?", + "delete-solution-text": "Opgelet, na de bevestiging worden de oplossing en alle gerelateerde gegevens onherstelbaar.", + "installing": "Oplossingssjabloon installeren..." + }, + "markdown": { + "edit": "Bewerken", + "preview": "Voorbeeld", + "copy-code": "Klik om te kopiëren", + "copied": "Gekopieerd!" + }, + "white-labeling": { + "white-labeling": "White labelling", + "white-labeling-general": "Algemene White Labeling", + "login-white-labeling": "Inloggen White Labeling", + "general": "Algemeen", + "login": "Inloggen", + "preview": "Voorbeeld", + "app-title": "Titel van de toepassing", + "favicon": "Website icoon", + "favicon-description": "*.ico, *.gif of *.png afbeelding met een maximale grootte {{kbSize}} KBytes.", + "favicon-size-error": "De afbeelding van de website is te groot. De maximaal toegestane afbeeldingsgrootte van de website {{kbSize}} KBytes.", + "favicon-type-error": "Ongeldige bestandsindeling voor websiteafbeeldingen. Alleen ICO-, GIF- of PNG-afbeeldingen worden geaccepteerd.", + "drop-favicon-image": "Zet een afbeelding van een websitepictogram neer of klik om een bestand te selecteren om te uploaden.", + "drop-favicon-image-or": "Sleep een afbeelding van een websitepictogram of", + "no-favicon-image": "Geen pictogram geselecteerd", + "logo": "Logo", + "logo-description": "Elke afbeelding met een maximale grootte {{kbSize}} KBytes.", + "logo-size-error": "De afbeelding van het logo is te groot. De maximaal toegestane afbeeldingsgrootte van het logo {{kbSize}} KBytes.", + "logo-type-error": "Ongeldig bestandsformaat voor logo's. Alleen afbeeldingen worden geaccepteerd.", + "drop-logo-image": "Zet een logo-afbeelding neer of klik om een bestand te selecteren om te uploaden.", + "drop-logo-image-or": "Een logo-afbeelding slepen en neerzetten of", + "no-logo-image": "Geen logo geselecteerd", + "logo-height": "Hoogte logo, px", + "primary-palette": "Primair palet", + "accent-palette": "Accent palet", + "customize-palette": "Aanpassen", + "advanced-css": "Geavanceerde CSS", + "edit-palette": "Palet bewerken", + "save-palette": "Palet opslaan", + "primary-background": "Primaire achtergrond", + "secondary-background": "Secundaire achtergrond", + "hue1": "TINT 1", + "hue2": "HUE 2", + "hue3": "HUE 3", + "page-background-color": "Achtergrondkleur van de pagina", + "dark-foreground": "Donkere voorgrond", + "domain-name": "Domeinnaam", + "base-url": "Basis-URL", + "base-url-required": "Basis-URL is vereist.", + "prohibit-different-url": "Verbieden om de hostnaam te gebruiken in de headers van de clientaanvraag", + "prohibit-different-url-hint": "Deze instelling moet zijn ingeschakeld voor productieomgevingen. Kan beveiligingsproblemen veroorzaken wanneer deze is uitgeschakeld", + "help-link-base-url": "Help-links basis-url", + "ui-help-base-url": "Help-basis-URL van de gebruikersinterface", + "enable-help-links": "Helpkoppelingen inschakelen", + "error-verification-url": "Een domeinnaam mag geen symbolen '/' en ':' bevatten. Voorbeeld: thingsboard.io", + "show-platform-name-version": "Platformnaam en -versie weergeven", + "platform-name": "Naam van het platform", + "platform-version": "Platform versie", + "version-mask": "{{name}} v.{{version}}", + "position": { + "label": "Platformnaam en versiepositie", + "under-logo": "Onder het logo", + "bottom": "Onderaan het inlogformulier" + } + }, + "widgets": { + "chart": { + "common-settings": "Algemene instellingen", + "enable-stacking-mode": "Stapelmodus inschakelen", + "line-shadow-size": "Grootte van de lijnschaduw", + "display-smooth-lines": "Vloeiende (gebogen) lijnen weergeven", + "default-bar-width": "Standaardbalkbreedte voor niet-geaggregeerde gegevens (milliseconden)", + "bar-alignment": "Staaf uitlijning", + "bar-alignment-left": "Links", + "bar-alignment-right": "Rechts", + "bar-alignment-center": "Middelpunt", + "default-font-size": "Standaard lettergrootte", + "default-font-color": "Standaard tekstkleur", + "thresholds-line-width": "Standaardregeldikte voor alle drempels", + "tooltip-settings": "Tooltip-instellingen", + "show-tooltip": "Tooltip weergeven", + "hover-individual-points": "Beweeg de muisaanwijzer over individuele punten", + "show-cumulative-values": "Cumulatieve waarden weergeven in stapelmodus", + "hide-zero-false-values": "Nul/onwaar-waarden verbergen in knopinfo", + "tooltip-value-format-function": "Functie voor het opmaken van knoppuntwaarden", + "grid-settings": "Raster instellingen", + "show-vertical-lines": "Verticale lijnen weergeven", + "show-horizontal-lines": "Horizontale lijnen weergeven", + "grid-outline-border-width": "Rasteromtrek/randbreedte (px)", + "primary-color": "Primaire kleur", + "background-color": "Achtergrondkleur", + "ticks-color": "De kleur van de teken", + "xaxis-settings": "Instellingen van de X-as", + "axis-title": "Titel van de as", + "xaxis-tick-labels-settings": "Instellingen voor labels voor tikken op de X-as", + "show-tick-labels": "Labels voor asvinkjes weergeven", + "yaxis-settings": "Y-as instellingen", + "min-scale-value": "Minimumwaarde op de weegschaal", + "max-scale-value": "Maximale waarde op de weegschaal", + "yaxis-tick-labels-settings": "Instellingen voor labels voor Y-as tikken", + "tick-step-size": "Stapgrootte tussen teken", + "number-of-decimals": "Het aantal decimalen dat moet worden weergegeven", + "ticks-formatter-function": "Teken formatter-functie", + "comparison-settings": "Vergelijkingsinstellingen", + "enable-comparison": "Vergelijking inschakelen", + "time-for-comparison": "Vergelijkingsperiode", + "time-for-comparison-previous-interval": "Vorig interval (standaard)", + "time-for-comparison-days": "Dag geleden", + "time-for-comparison-weeks": "Week geleden", + "time-for-comparison-months": "Maand geleden", + "time-for-comparison-years": "Jaar geleden", + "time-for-comparison-custom-interval": "Aangepast interval", + "custom-interval-value": "Aangepaste intervalwaarde (ms)", + "comparison-x-axis-settings": "Vergelijking X-asinstellingen", + "axis-position": "Positie van de as", + "axis-position-top": "Top (standaard)", + "axis-position-bottom": "Bodem", + "custom-legend-settings": "Aangepaste legende-instellingen", + "enable-custom-legend": "Aangepaste legende inschakelen (hiermee kunt u attribuut-/tijdreekswaarden gebruiken in sleutellabels)", + "key-name": "Naam van de sleutel", + "key-name-required": "Sleutelnaam is vereist", + "key-type": "Type sleutel", + "key-type-attribute": "Attribuut", + "key-type-timeseries": "Timeseries", + "label-keys-list": "Toetsenlijst voor labels", + "no-label-keys": "Geen sleutels geconfigureerd", + "add-label-key": "Nieuwe sleutel toevoegen", + "line-width": "Lijndikte", + "color": "Kleur", + "data-is-hidden-by-default": "Gegevens zijn standaard verborgen", + "disable-data-hiding": "Schakel het verbergen van gegevens uit", + "remove-from-legend": "Datakey verwijderen uit legende", + "exclude-from-stacking": "Uitsluiten van stapelen (beschikbaar in de modus \"Stapelen\")", + "line-settings": "Lijn instellingen", + "show-line": "Toon lijn", + "fill-line": "Lijn vullen", + "fill-line-opacity": "Dekking vullen", + "points-settings": "Punten instellingen", + "show-points": "Toon punten", + "points-line-width": "Lijndikte van punten", + "points-radius": "Straal van punten", + "point-shape": "Puntvorm", + "point-shape-circle": "Cirkel", + "point-shape-cross": "Kruis", + "point-shape-diamond": "Diamant", + "point-shape-square": "Vierkant", + "point-shape-triangle": "Driehoek", + "point-shape-custom": "Aangepaste functie", + "point-shape-draw-function": "Tekenfunctie voor puntvorm", + "show-separate-axis": "Afzonderlijke as weergeven", + "axis-position-left": "Links a-x positie", + "axis-position-right": "Rechts a-x positie", + "thresholds": "Drempels", + "no-thresholds": "Geen drempels geconfigureerd", + "add-threshold": "Nieuwe drempel toevoegen", + "show-values-for-comparison": "Historische waarden weergeven ter vergelijking", + "comparison-values-label": "Label met historische waarden", + "threshold-settings": "Drempelwaarde instellingen", + "use-as-threshold": "Sleutelwaarde gebruiken als drempelwaarde", + "threshold-line-width": "Lijnbreedte drempel", + "threshold-color": "Drempel kleur", + "common-pie-settings": "Algemene taartinstellingen", + "radius": "Radius", + "inner-radius": "Binnen radius", + "tilt": "Kantelen", + "stroke-settings": "Lijn instellingen", + "width-pixels": "Breedte (pixels)", + "show-labels": "Labels weergeven", + "animation-settings": "Animatie-instellingen", + "animated-pie": "Pie animatie inschakelen (experimenteel)", + "border-settings": "Randinstellingen", + "border-width": "Breedte van de edge", + "border-color": "Kleur van de edge", + "legend-settings": "Legende-instellingen", + "display-legend": "Legende weergeven", + "labels-font-color": "Letterkleur van labels" + }, + "dashboard-state": { + "dashboard-state-settings": "Instellingen voor de status van het dashboard", + "dashboard-state": "Status-id van dashboard", + "autofill-state-layout": "Standaard lay-outhoogte voor automatisch aanvullen", + "default-margin": "Standaard widgets marge", + "default-background-color": "Standaard achtergrondkleur", + "sync-parent-state-params": "Statusparameters synchroniseren met het bovenliggende dashboard" + }, + "date-range-navigator": { + "date-range-picker-settings": "Instellingen voor het kiezen van het datumbereik", + "hide-date-range-picker": "Datumbereik kiezer verbergen", + "picker-one-panel": "Datumbereik kiezer één paneel", + "picker-auto-confirm": "Datumbereik kiezer automatisch bevestigen", + "picker-show-template": "Datumbereik kiezer toon sjabloon", + "first-day-of-week": "Eerste dag van de week", + "interval-settings": "Interval-instellingen", + "hide-interval": "Interval verbergen", + "initial-interval": "Initieel interval", + "interval-hour": "Uur", + "interval-day": "Dag", + "interval-week": "Week", + "interval-two-weeks": "2 weken", + "interval-month": "Maand", + "interval-three-months": "3 maanden", + "interval-six-months": "6 maanden", + "step-settings": "Stap instellingen", + "hide-step-size": "Stapgrootte verbergen", + "initial-step-size": "Grootte van de eerste stap", + "hide-labels": "Labels verbergen", + "use-session-storage": "Sessieopslag gebruiken", + "localizationMap": { + "Sun": "Zon", + "Mon": "Ma", + "Tue": "Di", + "Wed": "Woe", + "Thu": "Do", + "Fri": "Vr", + "Sat": "Zaterdag", + "Jan": "Jan", + "Feb": "Februari", + "Mar": "Mar", + "Apr": "Apr", + "May": "Mei", + "Jun": "Jun", + "Jul": "Jul", + "Aug": "Aug", + "Sep": "Sep", + "Oct": "Oct", + "Nov": "Nov", + "Dec": "Dec", + "January": "Januari", + "February": "Februari", + "March": "Maart", + "April": "April", + "June": "Juni", + "July": "Juli", + "August": "Augustus", + "September": "September", + "October": "Oktober", + "November": "November", + "December": "December", + "Custom Date Range": "Aangepast datumbereik", + "Date Range Template": "Datumbereik sjabloon", + "Today": "Vandaag", + "Yesterday": "Gisteren", + "This Week": "Deze week", + "Last Week": "Vorige week", + "This Month": "Deze maand", + "Last Month": "Afgelopen maand", + "Year": "Jaar", + "This Year": "Dit jaar", + "Last Year": "Vorig jaar", + "Date picker": "Datumkiezer", + "Hour": "Uur", + "Day": "Dag", + "Week": "Week", + "2 weeks": "2 weken", + "Month": "Maand", + "3 months": "3 maanden", + "6 months": "6 maanden", + "Custom interval": "Aangepast interval", + "Interval": "Interval", + "Step size": "Stap grootte", + "Ok": "OK" + } + }, + "entities-hierarchy": { + "hierarchy-data-settings": "Instellingen voor hiërarchische gegevens", + "relations-query-function": "Queryfunctie voor knooppuntrelaties", + "has-children-function": "Knoop heeft een kinderfunctie", + "node-state-settings": "Instellingen voor knooppuntstatus", + "node-opened-function": "Standaard functie voor het openen van rule nodes", + "node-disabled-function": "Knooppuntuitgeschakelde functie", + "display-settings": "Weergave-instellingen", + "node-icon-function": "Knooppuntpictogram functie", + "node-text-function": "Knooppunttekstfunctie", + "sort-settings": "Sorteer instellingen", + "nodes-sort-function": "Sorteerfunctie voor rule nodes" + }, + "edge": { + "display-default-title": "Standaardtitel weergeven" + }, + "gateway": { + "general-settings": "Algemene instellingen", + "widget-title": "Titel van de widget", + "default-archive-file-name": "Standaard bestandsnaam voor archief", + "device-type-for-new-gateway": "Device type voor nieuwe gateway", + "messages-settings": "Instellingen voor Berichten", + "save-config-success-message": "Sms-bericht over succesvol opgeslagen gatewayconfiguratie", + "device-name-exists-message": "Sms-bericht wanneer het device met de ingevoerde naam al bestaat", + "gateway-title": "Gateway-formulier", + "read-only": "Alleen-lezen", + "events-title": "Titel van het formulier voor gateway events", + "events-filter": "Events filter", + "event-key-contains": "Events sleutel bevat..." + }, + "gauge": { + "default-color": "Standaard kleur", + "radial-gauge-settings": "Instellingen radiale meter", + "ticks-settings": "Vink instellingen aan", + "min-value": "Minimumwaarde", + "max-value": "Maximale waarde", + "start-ticks-angle": "Start tikt hoek", + "ticks-angle": "De hoek van teken", + "major-ticks-count": "Aantal belangrijke teken", + "major-ticks-color": "De belangrijkste kleur van teken", + "minor-ticks-count": "Kleine vinkjes tellen", + "minor-ticks-color": "Kleine vinkjes kleur", + "tick-numbers-font": "Tick nummers lettertype", + "unit-title-settings": "Instellingen voor eenheidstitels", + "show-unit-title": "Titel van eenheid weergeven", + "unit-title": "Titel van de eenheid", + "title-font": "Lettertype van titeltekst", + "units-settings": "Instellingen van de eenheden", + "units-font": "Eenheden tekstlettertype", + "value-box-settings": "Instellingen voor het vak Waarde", + "show-value-box": "Vak Waarde weergeven", + "value-int": "Cijfers tellen mee voor het gehele deel van de waarde", + "value-font": "Waarde tekstlettertype", + "value-box-rect-stroke-color": "Voordeelvak rechthoekige lijnkleur", + "value-box-rect-stroke-color-end": "Voordeelvak rechthoekige lijnkleur - eindverloop", + "value-box-background-color": "Achtergrondkleur van het waardevak", + "value-box-shadow-color": "Waarde vak schaduw kleur", + "plate-settings": "Plaat instellingen", + "show-plate-border": "Plaatrand weergeven", + "plate-color": "Kleur van de plaat", + "needle-settings": "Naald instellingen", + "needle-circle-size": "De grootte van de naaldcirkel", + "needle-color": "Kleur van de naald", + "needle-color-end": "Naaldkleur - eindverloop", + "needle-color-shadow-up": "Bovenste helft van de kleur van de naaldschaduw", + "needle-color-shadow-down": "Kleur slagschaduw naald", + "highlights-settings": "Instellingen voor markeringen", + "highlights-width": "Breedte van hoogtepunten", + "highlights": "Hoogtepunten", + "highlight-from": "Van", + "highlight-to": "Aan", + "highlight-color": "Kleur", + "no-highlights": "Geen markeringen geconfigureerd", + "add-highlight": "Markering toevoegen", + "animation-settings": "Animatie-instellingen", + "enable-animation": "Animatie inschakelen", + "animation-duration": "Duur van de animatie", + "animation-rule": "Animatie regel", + "animation-linear": "Lineair", + "animation-quad": "Quad", + "animation-quint": "Quint", + "animation-cycle": "Cyclus", + "animation-bounce": "Stuiteren", + "animation-elastic": "Elastisch", + "animation-dequad": "Splitsen", + "animation-dequint": "Afscheid nemen", + "animation-decycle": "Uitzetten", + "animation-debounce": "Debouncen", + "animation-delastic": "Delastisch", + "linear-gauge-settings": "Lineaire meetinstellingen", + "bar-stroke-width": "Lijnbreedte van de staaf", + "bar-stroke-color": "Kleur balklijn", + "bar-background-color": "Achtergrondkleur van de meterbalk", + "bar-background-color-end": "Achtergrondkleur van de balk - eindverloop", + "progress-bar-color": "Kleur voortgangsbalk", + "progress-bar-color-end": "Kleur voortgangsbalk - eindverloop", + "major-ticks-names": "Belangrijke namen van teken", + "show-stroke-ticks": "Toon teken beroerte", + "major-ticks-font": "Het belangrijkste teken lettertype", + "border-color": "Kleur van de edge", + "border-width": "Breedte van de edge", + "needle-circle-color": "De cirkelkleur van de naald", + "animation-target": "Animatie doel", + "animation-target-needle": "Naald", + "animation-target-plate": "Bord", + "common-settings": "Gemeenschappelijke meterinstellingen", + "gauge-type": "Type meter", + "gauge-type-arc": "Boog", + "gauge-type-donut": "Donut", + "gauge-type-horizontal-bar": "Rekstok", + "gauge-type-vertical-bar": "Verticale balk", + "donut-start-angle": "Hoek om mee te beginnen", + "bar-settings": "Meetbalk-instellingen", + "relative-bar-width": "Relatieve staafbreedte", + "neon-glow-brightness": "Neon glow effect helderheid, (0-100), 0 - effect uitschakelen", + "stripes-thickness": "Dikte van de strepen, 0 - geen strepen", + "rounded-line-cap": "Afgeronde lijndop weergeven", + "bar-color-settings": "Kleurinstellingen voor de balk", + "use-precise-level-color-values": "Gebruik nauwkeurige kleurniveaus", + "bar-colors": "Balkkleuren, van onder naar boven", + "color": "Kleur", + "no-bar-colors": "Geen balkkleuren geconfigureerd", + "add-bar-color": "Staafkleur toevoegen", + "from": "Van", + "to": "Aan", + "fixed-level-colors": "Staafkleuren met behulp van grenswaarden", + "gauge-title-settings": "Titelinstellingen meten", + "show-gauge-title": "Metertitel weergeven", + "gauge-title": "Titel van de meter", + "gauge-title-font": "Lettertype van de metertitel", + "unit-title-and-timestamp-settings": "Instellingen voor titel en tijdstempel van de eenheid", + "show-timestamp": "Tijdstempel van de waarde weergeven", + "timestamp-format": "Indeling tijdstempel", + "label-font": "Lettertype van label dat onder waarde wordt weergegeven", + "value-settings": "Waarde-instellingen", + "show-value": "Waardetekst weergeven", + "min-max-settings": "Instellingen voor minimale/maximale labels", + "show-min-max": "Min- en max-waarden weergeven", + "min-max-font": "Lettertype van minimum- en maximumlabels", + "show-ticks": "Toon teken", + "tick-width": "Tikbreedte", + "tick-color": "Vink kleur aan", + "tick-values": "Vink waarden aan", + "no-tick-values": "Geen vinkjes geconfigureerd", + "add-tick-value": "Tick waarde toevoegen" + }, + "gpio": { + "pin": "Speld", + "label": "Etiket", + "row": "Rijen", + "column": "Kolom", + "color": "Kleur", + "panel-settings": "Paneel instellingen", + "background-color": "Achtergrondkleur", + "gpio-switches": "GPIO-schakelaars", + "no-gpio-switches": "Geen GPIO-schakelaars geconfigureerd", + "add-gpio-switch": "GPIO-schakelaar toevoegen", + "gpio-status-request": "GPIO-statusaanvraag", + "method-name": "Naam van de methode", + "method-body": "Methode lichaam", + "gpio-status-change-request": "Aanvraag voor wijziging van GPIO-status", + "parse-gpio-status-function": "GPIO-statusfunctie parseren", + "gpio-leds": "GPIO-leds", + "no-gpio-leds": "Geen GPIO-leds geconfigureerd", + "add-gpio-led": "GPIO-led toevoegen" + }, + "html-card": { + "html": ".HTML", + "css": ".CSS" + }, + "input-widgets": { + "attribute-not-allowed": "Attribuutparameter kan niet worden gebruikt in deze widget", + "blocked-location": "Geolocatie is geblokkeerd in uw browser", + "claim-device": "Device claimen", + "claim-failed": "Kan het device niet claimen!", + "claim-not-found": "Device niet gevonden!", + "claim-successful": "Device is succesvol geclaimd!", + "date": "Datum", + "device-name": "Naam van het device", + "device-name-required": "Device naam is vereist", + "discard-changes": "Wijzigingen negeren", + "entity-attribute-required": "Entiteitskenmerk is vereist", + "entity-coordinate-required": "Beide velden, lengte- en breedtegraad, zijn verplicht", + "entity-timeseries-required": "Timeseries van entiteiten zijn vereist", + "get-location": "Huidige locatie ophalen", + "invalid-date": "Ongeldige datum", + "latitude": "Breedtegraad", + "longitude": "Lengtegraad", + "min-value-error": "Minimale waarde is {{value}}", + "max-value-error": "Maximale waarde is {{value}}", + "not-allowed-entity": "Geselecteerde entiteit kan geen gedeelde attributen hebben", + "no-attribute-selected": "Er is geen attribuut geselecteerd", + "no-datakey-selected": "Er is geen datakey geselecteerd", + "no-coordinate-specified": "Datakey voor lengte- en breedtegraad is niet opgegeven", + "no-entity-selected": "Geen entiteit geselecteerd", + "no-image": "Geen afbeelding", + "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 je camera niet vinden", + "no-permission-camera": "Toestemming is geweigerd door de 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 vereist", + "switch-attribute-value": "Entiteitskenmerkwaarde wijzigen", + "switch-camera": "Wissel van camera", + "switch-timeseries-value": "Tijdreekswaarde van entiteit wijzigen", + "take-photo": "Maak een foto", + "time": "Tijd", + "timeseries-not-allowed": "Timeseries parameter kan niet worden gebruikt in deze widget", + "update-failed": "Update mislukt", + "update-successful": "Update geslaagd", + "update-attribute": "Attribuut bijwerken", + "update-timeseries": "Timeseries bijwerken", + "value": "Waarde", + "general-settings": "Algemene instellingen", + "widget-title": "Titel van de widget", + "claim-button-label": "Knoplabel claimen", + "show-secret-key-field": "Toon 'Geheime sleutel' invoerveld", + "labels-settings": "Labels instellingen", + "show-labels": "Labels weergeven", + "device-name-label": "Label voor invoerveld device naam", + "secret-key-label": "Label voor het invoerveld van de geheime sleutel", + "messages-settings": "Instellingen voor berichten", + "claim-device-success-message": "Sms-bericht van succesvolle claiming van device", + "claim-device-not-found-message": "Sms wanneer device niet gevonden", + "claim-device-failed-message": "Sms-bericht van geclaimd device", + "claim-device-name-required-message": "Foutbericht 'Device naam vereist'", + "claim-device-secret-key-required-message": "Foutmelding 'Geheime sleutel vereist'", + "relations-settings": "Instellingen voor relaties", + "relate-device-to-state-entity": "Device relateren aan de entiteit met de huidige status", + "relate-direction": "Richting relateren", + "relate-direction-from": "Van", + "relate-direction-to": "Aan", + "relation-type": "Relatie type", + "show-label": "Etiket weergeven", + "label": "Etiket", + "required": "Vereist", + "required-error-message": "Foutmelding 'Vereist'", + "show-result-message": "Resultaatbericht weergeven", + "integer-field-settings": "Instellingen voor velden met gehele getallen", + "min-value": "Min waarde", + "max-value": "Maximale waarde", + "double-field-settings": "Dubbele veldinstellingen", + "text-field-settings": "Instellingen voor tekstvelden", + "min-length": "Min lengte", + "max-length": "Maximale lengte", + "checkbox-settings": "Selectievakjes instellingen", + "true-label": "Gecontroleerd etiket", + "false-label": "Onaangevinkt etiket", + "image-input-settings": "Instellingen voor beeldinvoer", + "display-preview": "Voorbeeld weergeven", + "display-clear-button": "Knop Wissen weergeven", + "display-apply-button": "Knop Toepassen weergeven", + "display-discard-button": "Knop voor weggooien weergeven", + "datetime-field-settings": "Instellingen voor datum-/tijdvelden", + "display-time-input": "Tijdinvoer weergeven", + "latitude-key-name": "Naam van breedtegraad-sleutel", + "longitude-key-name": "Lengtegraad sleutelnaam", + "show-get-location-button": "Toon knop 'Huidige locatie ophalen'", + "use-high-accuracy": "Gebruik hoge nauwkeurigheid", + "location-fields-settings": "Instellingen voor locatievelden", + "latitude-label": "Label voor breedtegraad", + "longitude-label": "Label voor lengtegraad", + "input-fields-alignment": "Uitlijning van invoervelden", + "input-fields-alignment-column": "Kolom (standaard)", + "input-fields-alignment-row": "Rijen", + "latitude-field-required": "Breedtegraadveld vereist", + "longitude-field-required": "Lengtegraadveld vereist", + "attribute-settings": "Attribuut instellingen", + "widget-mode": "Widget-modus", + "widget-mode-update-attribute": "Attribuut bijwerken", + "widget-mode-update-timeseries": "Timeseries bijwerken", + "attribute-scope": "Bereik van attribuut", + "attribute-scope-server": "Server-attribuut", + "attribute-scope-shared": "Gedeeld attribuut", + "value-required": "Vereiste waarde", + "image-settings": "Beeldinstellingen", + "image-format": "Beeldformaat", + "image-format-jpeg": ".JPEG", + "image-format-png": ".PNG", + "image-format-webp": ".WEBP", + "image-quality": "Beeldkwaliteit die compressie met verlies gebruikt, zoals jpeg en webp", + "max-image-width": "Maximale afbeeldingsbreedte", + "max-image-height": "Maximale afbeeldingshoogte", + "action-buttons": "Actieknoppen", + "show-action-buttons": "Actieknoppen weergeven", + "update-all-values": "Werk alle waarden bij, niet alleen gewijzigd", + "save-button-label": "Label met de knop 'OPSLAAN'", + "reset-button-label": "Knoplabel 'ONGEDAAN MAKEN'", + "group-settings": "Groepsinstellingen", + "show-group-title": "Titel weergeven voor groep velden, gerelateerd aan verschillende entiteiten", + "group-title": "Titel van de groep", + "fields-alignment": "Uitlijning van velden", + "fields-alignment-row": "Rij (standaard)", + "fields-alignment-column": "Kolom", + "fields-in-row": "Aantal velden in de rij", + "option-value": "Waarde (schrijf 'null' voor de optie leeg maken)", + "option-label": "Etiket", + "hide-input-field": "Invoerveld verbergen", + "datakey-type": "Type datakey", + "datakey-type-server": "Serverkenmerk (standaard)", + "datakey-type-shared": "Gedeeld attribuut", + "datakey-type-timeseries": "Timeseries", + "datakey-value-type": "Waardetype Datakey", + "datakey-value-type-string": "Snaar", + "datakey-value-type-double": "Dubbel", + "datakey-value-type-integer": "Geheel getal", + "datakey-value-type-json": "JSON", + "datakey-value-type-boolean-checkbox": "Booleaans (selectievakje)", + "datakey-value-type-boolean-switch": "Booleaans (schakelaar)", + "datakey-value-type-date-time": "Datum en tijd", + "datakey-value-type-date": "Datum", + "datakey-value-type-time": "Tijd", + "datakey-value-type-select": "Selecteren", + "value-is-required": "Waarde is vereist", + "ability-to-edit-attribute": "Mogelijkheid om attribuut te bewerken", + "ability-to-edit-attribute-editable": "Bewerkbaar (standaard)", + "ability-to-edit-attribute-disabled": "Invalide", + "ability-to-edit-attribute-readonly": "Alleen-lezen", + "disable-on-datakey-name": "Uitschakelen bij valse waarde van een andere datakey (geef de naam van de datakey op)", + "slide-toggle-settings": "Instellingen voor schuifschakelaar", + "slide-toggle-label-position": "Schuif de positie van het label omschakelen", + "slide-toggle-label-position-after": "Na", + "slide-toggle-label-position-before": "Voor", + "select-options": "Opties selecteren", + "no-select-options": "Geen geselecteerde opties geconfigureerd", + "add-select-option": "Selectieoptie toevoegen", + "numeric-field-settings": "Instellingen voor numerieke velden", + "step-interval": "Stapinterval tussen waarden", + "error-messages": "Foutberichten", + "min-value-error-message": "Foutmelding 'Min. waarde'", + "max-value-error-message": "Foutmelding 'Maximale waarde'", + "invalid-date-error-message": "Foutmelding 'Ongeldige datum'", + "invalid-JSON-error-message": "Foutbericht 'Ongeldige JSON'", + "icon-settings": "Icoon instellingen", + "dialog-editor-settings": "Instellingen van de dialoogeditor", + "use-custom-icon": "Aangepast pictogram gebruiken", + "input-cell-icon": "Pictogram om weer te geven vóór invoercel", + "value-conversion-settings": "Instellingen voor waardeconversie", + "get-value-settings": "Waarde-instellingen ophalen", + "use-get-value-function": "De getValue-functie gebruiken", + "get-value-function": "getValue, functie", + "set-value-settings": "Waarde-instellingen instellen", + "use-set-value-function": "Gebruik de setValue-functie", + "set-value-function": "setValue-functie", + "json-invalid": "JSON-waarde heeft een ongeldige indeling", + "title": "Titel", + "cancel-button-label": "Label met de knop 'Annuleren'" + }, + "invalid-qr-code-text": "Ongeldige invoertekst voor QR-code. Invoer moet een tekenreekstype hebben", + "qr-code": { + "use-qr-code-text-function": "Gebruik de tekstfunctie van de QR-code", + "qr-code-text-pattern": "Tekstpatroon QR-code (bijv. '${entityName} | ${keyName} - wat tekst.')", + "qr-code-text-pattern-hint": "Het tekstpatroon van de QR-code gebruikt de waarde van de eerst gevonden sleutel in de entiteiten in de entiteitsalias.", + "qr-code-text-pattern-required": "Tekstpatroon QR-code is vereist.", + "qr-code-text-function": "Tekstfunctie QR-code" + }, + "label-widget": { + "label-pattern": "Patroon", + "label-pattern-hint": "Tip: bijv. 'Text <span style=\"color: #000;\">${keyName<span style=\"color: #000;\">} eenheden.' of <span style=\"color: #000;\">${#<key index><span style=\"color: #000;\">} eenheden'", + "label-pattern-required": "Patroon is vereist", + "label-position": "Positie (percentage ten opzichte van achtergrond)", + "x-pos": "X", + "y-pos": "Y", + "background-color": "Achtergrondkleur", + "font-settings": "Lettertype-instellingen", + "background-image": "Achtergrondafbeelding", + "labels": "Etiketten", + "no-labels": "Geen labels geconfigureerd", + "add-label": "Label toevoegen" + }, + "navigation": { + "title": "Titel", + "navigation-path": "Navigatie pad", + "filter-type": "Filter type", + "filter-type-all": "Alle artikelen", + "filter-type-include": "Items opnemen", + "filter-type-exclude": "Items uitsluiten", + "items": "Items", + "enter-urls-to-filter": "Voer url's in om te filteren..." + }, + "persistent-table": { + "rpc-id": "RPC-ID", + "message-type": "Soort bericht", + "method": "Methode", + "params": "Params", + "created-time": "Gecreëerde tijd", + "expiration-time": "Vervaltijd", + "retries": "Pogingen", + "status": "Status", + "filter": "Filter", + "refresh": "Opfrissen", + "add": "RPC-aanvraag toevoegen", + "details": "Details", + "delete": "Verwijderen", + "delete-request-title": "Persistent RPC-verzoek verwijderen", + "delete-request-text": "Weet je zeker dat je een verzoek wilt verwijderen?", + "details-title": "Details RPC-ID:", + "additional-info": "Aanvullende informatie", + "response": "Antwoord", + "any-status": "Elke status", + "rpc-status-list": "RPC-statuslijst", + "no-request-prompt": "Geen verzoek om weer te geven", + "send-request": "Aanvraag versturen", + "add-title": "Permanente RPC-aanvraag maken", + "method-error": "Methode is vereist.", + "timeout-error": "De minimale time-outwaarde is 5000 (5 seconden).", + "white-space-error": "Witruimte is niet toegestaan.", + "rpc-status": { + "QUEUED": "WACHTRIJ", + "SENT": "VERZONDEN", + "DELIVERED": "GELEVERD", + "SUCCESSFUL": "SUCCESVOL", + "TIMEOUT": "TIMEOUT", + "EXPIRED": "VERVALLEN", + "FAILED": "MISLUKT" + }, + "rpc-search-status-all": "ALLE", + "message-types": { + "false": "Twee richtingen", + "true": "One-way" + }, + "general-settings": "Algemene instellingen", + "enable-filter": "Filter inschakelen", + "enable-sticky-header": "Koptekst weergeven tijdens scrollen", + "enable-sticky-action": "Kolom Acties weergeven tijdens het scrollen", + "display-request-details": "Aanvraaggegevens weergeven", + "allow-send-request": "Sta het verzenden van RPC-verzoek toe", + "allow-delete-request": "Verwijderingsverzoek toestaan", + "columns-settings": "Instellingen voor kolommen", + "display-columns": "Weer te geven kolommen", + "column": "Kolom", + "no-columns-found": "Geen kolommen gevonden", + "no-columns-matching": "'{{column}}' niet gevonden." + }, + "rpc": { + "value-settings": "Waarde-instellingen", + "initial-value": "Beginwaarde", + "retrieve-value-settings": "Aan/uit-waarde-instellingen ophalen", + "retrieve-value-method": "Waarde ophalen met behulp van methode", + "retrieve-value-method-none": "Niet ophalen", + "retrieve-value-method-rpc": "RPC aanroepen om waardemethode op te halen", + "retrieve-value-method-attribute": "Abonneren op attribuut", + "retrieve-value-method-timeseries": "Schrijf je in voor tijdseries", + "attribute-value-key": "Attribuut sleutel", + "timeseries-value-key": "Tijdreeks-toets", + "get-value-method": "RPC get value methode", + "parse-value-function": "Functie voor het parseren van waarden", + "update-value-settings": "Waarde-instellingen bijwerken", + "set-value-method": "RPC-methode voor ingestelde waarden", + "convert-value-function": "Functie Waarde converteren", + "rpc-settings": "RPC-instellingen", + "request-timeout": "Time-out voor RPC-aanvraag (ms)", + "persistent-rpc-settings": "Persistente RPC-instellingen", + "request-persistent": "RPC-aanvraag persistent", + "persistent-polling-interval": "Pollinginterval (ms) om persistente RPC-opdrachtrespons te krijgen", + "common-settings": "Algemene instellingen", + "switch-title": "Titel wijzigen", + "show-on-off-labels": "Aan/uit-labels weergeven", + "slide-toggle-label": "Schuif toggle label", + "label-position": "Positie van het etiket", + "label-position-before": "Voor", + "label-position-after": "Na", + "slider-color": "Kleur schuifregelaar", + "slider-color-primary": "Primair", + "slider-color-accent": "Accent", + "slider-color-warn": "Waarschuwen", + "button-style": "Knop stijl", + "button-raised": "Verhoogde knop", + "button-primary": "Primaire kleur", + "button-background-color": "Achtergrondkleur knop", + "button-text-color": "Tekstkleur knop", + "widget-title": "Titel van de widget", + "button-label": "Knop label", + "device-attribute-scope": "Bereik van device attributen", + "server-attribute": "Server-attribuut", + "shared-attribute": "Gedeeld attribuut", + "device-attribute-parameters": "Parameters voor device attributen", + "is-one-way-command": "Is eenrichtingscommando", + "rpc-method": "RPC-methode", + "rpc-method-params": "Params van de RPC-methode", + "show-rpc-error": "Fout bij het uitvoeren van RPC-opdrachten weergeven", + "led-title": "LED-titel", + "led-color": "LED-kleur", + "check-status-settings": "Statusinstellingen controleren", + "perform-rpc-status-check": "Voer de statuscontrole van het RPC-device uit", + "retrieve-led-status-value-method": "Leidsstatuswaarde ophalen met behulp van methode", + "led-status-value-attribute": "Apparaatkenmerk met led-statuswaarde", + "led-status-value-timeseries": "Tijdreeks van het device met led-statuswaarde", + "check-status-method": "RPC-methode voor het controleren van de apparaatstatus", + "parse-led-status-value-function": "Led-statuswaardefunctie parseren", + "knob-title": "Titel van de knop", + "min-value": "Minimumwaarde", + "max-value": "Maximale waarde" + }, + "maps": { + "select-entity": "Entiteit selecteren", + "select-entity-hint": "Tip: klik na selectie op de kaart om de positie in te stellen", + "tooltips": { + "placeMarker": "Klik om de entiteit '{{entityName}}' te plaatsen", + "firstVertex": "Polygoon voor '{{entityName}}': klik om eerste punt te plaatsen", + "firstVertex-cut": "Klik om het eerste punt te plaatsen", + "continueLine": "Polygoon voor '{{entityName}}': klik om verder te tekenen", + "continueLine-cut": "Klik om door te gaan met tekenen", + "finishLine": "Klik op een bestaande markering om te voltooien", + "finishPoly": "Polygoon voor '{{entityName}}': klik op de eerste markering om te voltooien en op te slaan", + "finishPoly-cut": "Klik op de eerste markering om te voltooien en op te slaan", + "finishRect": "Polygoon voor '{{entityName}}': klik om te voltooien en op te slaan", + "startCircle": "Cirkel voor '{{entityName}}': klik om het midden van de cirkel te plaatsen", + "finishCircle": "Cirkel voor '{{entityName}}': klik om cirkel te voltooien", + "placeCircleMarker": "Klik om de cirkelmarkering te plaatsen" + }, + "actions": { + "finish": "Fins", + "cancel": "Annuleren", + "removeLastVertex": "Laatste punt verwijderen" + }, + "buttonTitles": { + "drawMarkerButton": "Entiteit plaatsen", + "drawPolyButton": "Polygoon maken", + "drawLineButton": "Polylijn maken", + "drawCircleButton": "Cirkel maken", + "drawRectButton": "Rechthoek maken", + "editButton": "Modus bewerken", + "dragButton": "Drag-drop-modus", + "cutButton": "Snijd polygoongebied", + "deleteButton": "Verwijderen", + "drawCircleMarkerButton": "Cirkelmarkering maken", + "rotateButton": "Polygoon roteren" + }, + "map-provider-settings": "Instellingen van kaartprovider", + "map-provider": "Kaart provider", + "map-provider-google": "Google kaarten", + "map-provider-openstreet": "OpenStreet-kaarten", + "map-provider-here": "HERE kaarten", + "map-provider-image": "Afbeelding kaart", + "map-provider-tencent": "Tencent kaarten", + "openstreet-provider": "OpenStreet-kaartprovider", + "openstreet-provider-mapnik": "OpenStreetMap.Mapnik (standaard)", + "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": "Aangepaste provider gebruiken", + "custom-provider-tile-url": "Aangepaste tegel-URL van provider", + "google-maps-api-key": "API-sleutel voor Google Maps", + "default-map-type": "Standaard kaarttype", + "google-map-type-roadmap": "Stappenplan", + "google-map-type-satelite": "Satelliet", + "google-map-type-hybrid": "Hybride", + "google-map-type-terrain": "Terrein", + "map-layer": "Kaart laag", + "here-map-normal-day": "HERE.normalDay (standaard)", + "here-map-normal-night": "HIER.normalNight", + "here-map-hybrid-day": "HIER.hybridDay", + "here-map-terrain-day": "HIER.terreinDag", + "credentials": "Geloofsbrief", + "here-app-id": "HERE-app-id", + "here-app-code": "HERE-app-code", + "here-api-key": "HERE API-sleutel", + "here-use-new-version-api-3": "API-versie 3 gebruiken", + "tencent-maps-api-key": "API-sleutel voor Tencent Maps", + "tencent-map-type-roadmap": "Stappenplan", + "tencent-map-type-satelite": "Satelliet", + "tencent-map-type-hybrid": "Hybride", + "image-map-background": "De achtergrond van de afbeeldingskaart", + "image-map-background-from-entity-attribute": "Neem de achtergrond van de afbeeldingstoewijzing van het entiteitskenmerk", + "image-url-source-entity-alias": "Alias van de bronentiteit van de afbeeldings-URL", + "image-url-source-entity-attribute": "Entiteitskenmerk bronentiteit afbeeldings-URL", + "common-map-settings": "Algemene kaartinstellingen", + "x-pos-key-name": "Naam van de X-positiesleutel", + "y-pos-key-name": "Y-positie sleutelnaam", + "latitude-key-name": "Naam van breedtegraad-sleutel", + "longitude-key-name": "Lengtegraad sleutelnaam", + "default-map-zoom-level": "Standaard zoomniveau voor kaart (0 - 20)", + "default-map-center-position": "Standaard middenpositie op de kaart (0,0)", + "disable-scroll-zooming": "Scrollen uitschakelen", + "disable-double-click-zooming": "Dubbelklikken uitschakelen", + "disable-zoom-control-buttons": "Zoombedieningsknoppen uitschakelen", + "fit-map-bounds": "Pas kaartgrenzen aan om alle markeringen te bedekken", + "use-default-map-center-position": "Gebruik de standaardpositie in het midden van de kaart", + "entities-limit": "Limiet van te laden entiteiten", + "markers-settings": "Instellingen voor markeringen", + "marker-offset-x": "Markering X verschuiving ten opzichte van positie vermenigvuldigd met markeringsbreedte", + "marker-offset-y": "Markering Y-verschuiving ten opzichte van positie vermenigvuldigd met markeringshoogte", + "position-function": "Positieconversiefunctie, moet x,y-coördinaten retourneren als dubbel van 0 tot 1 elk", + "draggable-marker": "Versleepbare markering", + "label": "Etiket", + "show-label": "Etiket weergeven", + "use-label-function": "Labelfunctie gebruiken", + "label-pattern": "Label (patroonvoorbeelden: '${entityName}', '${entityName}: (Tekst ${keyName} eenheden.)' )", + "label-function": "Label functie", + "tooltip": "Tooltip", + "show-tooltip": "Tooltip weergeven", + "show-tooltip-action": "Actie voor het weergeven van de knopinfo", + "show-tooltip-action-click": "Knopinfo weergeven bij klikken (Standaard)", + "show-tooltip-action-hover": "Knopinfo weergeven bij aanwijzen", + "auto-close-tooltips": "Tooltips voor automatisch sluiten", + "use-tooltip-function": "Tooltip-functie gebruiken", + "tooltip-pattern": "Tooltip (bijv. 'Tekst ${keyName} eenheden.' of Linktekst')", + "tooltip-function": "Tooltip-functie", + "tooltip-offset-x": "Tooltip X-verschuiving ten opzichte van markeringsanker vermenigvuldigd met markeringsbreedte", + "tooltip-offset-y": "Tooltip Y-verschuiving ten opzichte van markeringsanker vermenigvuldigd met markeringshoogte", + "color": "Kleur", + "use-color-function": "Kleurfunctie gebruiken", + "color-function": "Kleur functie", + "marker-image": "Afbeelding markeren", + "use-marker-image-function": "Gebruik de functie voor markeringsafbeeldingen", + "custom-marker-image": "Aangepaste markeringsafbeelding", + "custom-marker-image-size": "Afbeeldingsgrootte aangepaste markering (px)", + "marker-image-function": "Marker image functie", + "marker-images": "Marker afbeeldingen", + "polygon-settings": "Polygoon-instellingen", + "show-polygon": "Polygoon weergeven", + "polygon-key-name": "Naam van de Polygoonsleutel", + "enable-polygon-edit": "Polygoonbewerking inschakelen", + "polygon-label": "Polygoon etiket", + "show-polygon-label": "Polygoonlabel weergeven", + "use-polygon-label-function": "Polygoonlabelfunctie gebruiken", + "polygon-label-pattern": "Polygoonlabel (patroonvoorbeelden: '${entityName}', '${entityName}: (Tekst ${keyName} eenheden.)' )", + "polygon-label-function": "Polygoon label functie", + "polygon-tooltip": "Tooltip voor polygoon", + "show-polygon-tooltip": "Polygoon knopinfo weergeven", + "auto-close-polygon-tooltips": "Tooltips voor polygoon automatisch sluiten", + "use-polygon-tooltip-function": "Polygoon-tooltipfunctie gebruiken", + "polygon-tooltip-pattern": "Tooltip (bijv. 'Tekst ${keyName} eenheden.' of Linktekst')", + "polygon-tooltip-function": "Polygoon tooltip functie", + "polygon-color": "Polygoon kleur", + "polygon-opacity": "Dekking van polygoon", + "use-polygon-color-function": "Polygoonkleurfunctie gebruiken", + "polygon-color-function": "Polygoon kleur functie", + "polygon-stroke": "Polygoon lijn", + "stroke-color": "Kleur van de lijn", + "stroke-opacity": "Dekking van de beroerte", + "stroke-weight": "Het gewicht van de slag", + "use-polygon-stroke-color-function": "Gebruik de kleurfunctie van de polygoonlijn", + "polygon-stroke-color-function": "Kleurfunctie voor polygoonlijnen", + "circle-settings": "Cirkel-instellingen", + "show-circle": "Toon cirkel", + "circle-key-name": "Naam van de cirkelsleutel", + "enable-circle-edit": "Cirkelbewerking inschakelen", + "circle-label": "Het etiket van de cirkel", + "show-circle-label": "Cirkellabel weergeven", + "use-circle-label-function": "Gebruik de cirkellabelfunctie", + "circle-label-pattern": "Cirkellabel (patroonvoorbeelden: '${entityName}', '${entityName}: (Tekst ${keyName} eenheden.)' )", + "circle-label-function": "Cirkellabel-functie", + "circle-tooltip": "Tooltip voor cirkelen", + "show-circle-tooltip": "Knopinfo cirkel weergeven", + "auto-close-circle-tooltips": "Tooltips voor automatisch sluiten van cirkels", + "use-circle-tooltip-function": "Gebruik de cirkel-tooltip-functie", + "circle-tooltip-pattern": "Tooltip (bijv. 'Tekst ${keyName} eenheden.' of Linktekst')", + "circle-tooltip-function": "Cirkel tooltip functie", + "circle-fill-color": "Vulkleur cirkel", + "circle-fill-color-opacity": "Dekking van de vulkleur van de cirkel", + "use-circle-fill-color-function": "Gebruik de functie voor het vullen van cirkels", + "circle-fill-color-function": "Cirkelvulkleurfunctie", + "circle-stroke": "De slag van de cirkel", + "use-circle-stroke-color-function": "Gebruik de kleurfunctie van de cirkelstreek", + "circle-stroke-color-function": "Cirkellijn kleurfunctie", + "markers-clustering-settings": "Instellingen voor het clusteren van markeringen", + "use-map-markers-clustering": "Clustering van kaartmarkeringen gebruiken", + "zoom-on-cluster-click": "Inzoomen bij het klikken op een cluster", + "max-cluster-zoom": "Het maximale zoomniveau wanneer een markering deel kan uitmaken van een cluster (0 - 18)", + "max-cluster-radius-pixels": "Maximale straal die een cluster in pixels bestrijkt", + "cluster-zoom-animation": "Animatie weergeven op markeringen bij het zoomen", + "show-markers-bounds-on-cluster-mouse-over": "De grenzen van markeringen weergeven wanneer u de muisaanwijzer op een cluster plaatst", + "spiderfy-max-zoom-level": "Spiderfy op het maximale zoomniveau (om alle clustermarkeringen te zien)", + "load-optimization": "Optimalisatie van de belasting", + "cluster-chunked-loading": "Gebruik chunks om markeringen toe te voegen, zodat de pagina niet vastloopt", + "cluster-markers-lazy-load": "Gebruik lazy load voor het toevoegen van markeringen", + "editor-settings": "Editor-instellingen", + "enable-snapping": "Uitlijnen op andere punten inschakelen voor nauwkeurig tekenen", + "init-draggable-mode": "Kaart initialiseren in versleepbare modus", + "hide-all-edit-buttons": "Alle bedieningsknoppen voor bewerken verbergen", + "hide-draw-buttons": "Tekenknoppen verbergen", + "hide-edit-buttons": "Bewerkingsknoppen verbergen", + "hide-remove-button": "Verwijderknop verbergen", + "route-map-settings": "Routekaartinstellingen", + "trip-animation-settings": "Instellingen voor reisanimatie", + "normalization-step": "Normalisatie gegevensstap (ms)", + "tooltip-background-color": "Achtergrondkleur tooltip", + "tooltip-font-color": "Tekstkleur van knopinfo", + "tooltip-opacity": "Tooltip dekking (0-1)", + "auto-close-tooltip": "Tooltip voor automatisch sluiten", + "rotation-angle": "Stel extra draaihoek in voor marker (graden)", + "path-settings": "Pad-instellingen", + "path-color": "De kleur van het pad", + "use-path-color-function": "Padkleurfunctie gebruiken", + "path-color-function": "Padkleurfunctie", + "path-decorator": "Pad decorateur", + "use-path-decorator": "Gebruik paddecorateur", + "decorator-symbol": "Het symbool van de decorateur", + "decorator-symbol-arrow-head": "Pijl", + "decorator-symbol-dash": "Scheutje", + "decorator-symbol-size": "Grootte decorateur symbool (px)", + "use-path-decorator-custom-color": "Gebruik de aangepaste kleur van de paddecorateur", + "decorator-custom-color": "Decorateur aangepaste kleur", + "decorator-offset": "Decorateur offset", + "end-decorator-offset": "Einddecorateur offset", + "decorator-repeat": "Decorateur herhalen", + "points-settings": "Punten instellingen", + "show-points": "Toon punten", + "point-color": "Kleur van de punt", + "point-size": "Punt grootte (px)", + "use-point-color-function": "Puntkleurfunctie gebruiken", + "point-color-function": "Puntkleurfunctie", + "use-point-as-anchor": "Punt gebruiken als anker", + "point-as-anchor-function": "Aanwijzen als ankerfunctie", + "independent-point-tooltip": "Tooltip voor onafhankelijk punt", + "clustering-markers": "Markeringen clusteren", + "use-icon-create-function": "Gebruik de kleurfunctie van markeringen", + "marker-color-function": "Marker kleur functie" + }, + "markdown": { + "use-markdown-text-function": "Markdown/HTML-waardefunctie gebruiken", + "markdown-text-function": "Markdown/HTML-waarde functie", + "markdown-text-pattern": "Markdown/HTML-patroon (markdown of HTML met variabelen, bijvoorbeeld '${entityName} of ${keyName} - wat tekst.')", + "apply-default-markdown-style": "Standaardstijl voor afprijzing toepassen", + "markdown-css": "Afprijzing/HTML CSS" + }, + "simple-card": { + "label-position": "Positie van het etiket", + "label-position-left": "Links", + "label-position-top": "Boven" + }, + "table": { + "common-table-settings": "Algemene tabelinstellingen", + "enable-search": "Zoeken inschakelen", + "enable-sticky-header": "Koptekst altijd weergeven", + "enable-sticky-action": "Kolom Acties altijd weergeven", + "hidden-cell-button-display-mode": "Weergavemodus voor verborgen celknopacties", + "show-empty-space-hidden-action": "Lege ruimte weergeven in plaats van verborgen celknopactie", + "dont-reserve-space-hidden-action": "Reserveer geen ruimte voor verborgen actieknoppen", + "display-timestamp": "Tijdstempelkolom weergeven", + "display-milliseconds": "Tijdstempel milliseconden weergeven", + "display-pagination": "Paginering weergeven", + "default-page-size": "Standaard paginaformaat", + "use-entity-label-tab-name": "Entiteitslabel gebruiken in de naam van het tabblad", + "hide-empty-lines": "Lege regels verbergen", + "row-style": "Rij stijl", + "use-row-style-function": "Rijstijlfunctie gebruiken", + "row-style-function": "Rijstijl functie", + "cell-style": "Cel stijl", + "use-cell-style-function": "Celstijlfunctie gebruiken", + "cell-style-function": "Functie voor celstijl", + "cell-content": "Celinhoud", + "use-cell-content-function": "De functie voor celinhoud gebruiken", + "cell-content-function": "Functie voor celinhoud", + "show-latest-data-column": "Kolom met meest recente gegevens weergeven", + "latest-data-column-order": "Meest recente volgorde van gegevenskolommen", + "entities-table-title": "Titel van de tabel Entiteiten", + "enable-select-column-display": "Schakel geselecteerde kolommen in om weer te geven", + "display-entity-name": "Kolom met entiteitsnaam weergeven", + "entity-name-column-title": "Kolomtitel van entiteitsnaam", + "display-entity-label": "Kolom met entiteitslabel weergeven", + "entity-label-column-title": "Kolomtitel van entiteitslabel", + "display-entity-type": "Kolom met entiteitstype weergeven", + "default-sort-order": "Standaard sorteervolgorde", + "custom-title": "Aangepaste kopteksttitel", + "column-width": "Kolombreedte (px of %)", + "default-column-visibility": "Standaard zichtbaarheid van kolommen", + "column-visibility-visible": "Zichtbaar", + "column-visibility-hidden": "Verborgen", + "column-visibility-hidden-mobile": "Verborgen in mobiele modus", + "column-selection-to-display": "Kolomselectie in 'Weer te geven kolommen'", + "column-selection-to-display-enabled": "Ingeschakeld", + "column-selection-to-display-disabled": "Invalide", + "column-export-option": "Kolom opnemen in export", + "column-export-option-always": "Altijd", + "column-export-option-only-visible": "Alleen als de kolom zichtbaar is", + "column-export-option-never": "Nooit", + "alarms-table-title": "Titel van de tabel Alarmen", + "enable-alarms-selection": "Selectie van alarmen inschakelen", + "enable-alarms-search": "Zoeken naar alarmen inschakelen", + "enable-alarm-filter": "Alarmfilter inschakelen", + "display-alarm-details": "Alarmdetails weergeven", + "allow-alarms-ack": "Alarmbevestiging toestaan", + "allow-alarms-clear": "Laat alarmen wissen", + "display-alarm-activity": "Alarmactiviteit weergeven", + "allow-alarms-assign": "Toewijzing van alarmen toestaan", + "blob-entities-table-title": "Titel van de tabel met blobentiteiten", + "display-created-time": "Aangemaakte tijdkolom weergeven", + "display-type": "Kolom Weergavetype", + "display-customer": "Klantkolom weergeven", + "no-data-display-message": "Alternatief bericht 'Geen gegevens om weer te geven'", + "force-default-blob-entity-type": "Standaard blob-entiteitstype afdwingen", + "scheduler-events-table-title": "Titel van de tabel met scheduler events", + "force-default-event-type": "Standaardgebeurtenistype afdwingen" + }, + "scheduler": { + "enabled-scheduler-event-views": "Weergaven van scheduler events ingeschakeld", + "enabled-scheduler-event-views-both": "Beide", + "enabled-scheduler-event-views-list": "Alleen lijstweergave", + "enabled-scheduler-event-views-calendar": "Alleen agendaweergave", + "display-name": "Weergavenaam", + "type-name": "Typ naam", + "display-originator-select": "Aansteller van entiteit weergeven", + "display-message-type-select": "Berichttype weergeven selecteren", + "display-metadata-table": "Tabel met metagegevens van berichten weergeven", + "configuration-html-template": "Configuratie HTML-sjabloon", + "custom-event-types": "Aangepaste gebeurtenistypen", + "no-custom-event-types": "Geen aangepaste gebeurtenistypen geconfigureerd", + "add-custom-event-type": "Aangepast gebeurtenistype toevoegen" + }, + "value-source": { + "value-source": "Waardebron", + "predefined-value": "Vooraf gedefinieerde waarde", + "entity-attribute": "Waarde ontleend aan entiteitskenmerk", + "value": "Waarde", + "source-entity-alias": "Alias van bronentiteit", + "source-entity-attribute": "Kenmerk van bronentiteit" + }, + "widget-font": { + "font-family": "Lettertype familie", + "size": "Grootte", + "relative-font-size": "Relatieve lettergrootte (procenten)", + "font-style": "Stijl", + "font-style-normal": "Normaal", + "font-style-italic": "Cursief", + "font-style-oblique": "Schuin", + "font-weight": "Gewicht", + "font-weight-normal": "Normaal", + "font-weight-bold": "Bold", + "font-weight-bolder": "Bolder", + "font-weight-lighter": "Lichter", + "color": "Kleur", + "shadow-color": "De kleur van de schaduw" + }, + "home": { + "no-data-available": "Geen gegevens beschikbaar" + }, + "system-info": { + "cpu": "CPU", + "ram": "RAM", + "disk": "Schijf", + "cpu-warning-text": "Hoog CPU-gebruik. Optimaliseer de systeemprestaties om systeemstoringen te voorkomen.", + "cpu-critical-text": "Kritisch hoog CPU-gebruik. Optimaliseer de systeemprestaties om systeemstoringen te voorkomen.", + "ram-warning-text": "Heeft bijna geen RAM-geheugen meer. Om systeemstoringen te voorkomen, optimaliseert u de systeemprestaties of vergroot u de grootte van het RAM-geheugen.", + "ram-critical-text": "Kritisch lage RAM-reserve. Om systeemstoringen te voorkomen, optimaliseert u de systeemprestaties of vergroot u de grootte van het RAM-geheugen.", + "disk-warning-text": "Weinig schijfruimte. Om gegevensverlies te voorkomen, maakt u schijfruimte vrij of breidt u deze uit.", + "disk-critical-text": "Kritisch weinig schijfruimte. Om gegevensverlies te voorkomen, maakt u schijfruimte vrij of breidt u deze uit." + }, + "cluster-info": { + "service-id": "Service-id", + "service-type": "Soort dienst", + "no-data": "Geen gegevens" + }, + "transport-messages": { + "title": "Berichten vervoeren", + "info": "Alle berichten die afkomstig zijn van Devices" + }, + "activity": { + "title": "Activiteit" + }, + "documentation": { + "title": "Documentatie", + "add-link": "Link toevoegen", + "add-link-title": "Documentatiekoppeling toevoegen", + "name": "Naam", + "name-required": "Naam is verplicht.", + "link": "Verbinden", + "link-required": "Link is vereist.", + "columns": "Kolommen" + }, + "quick-links": { + "title": "Snelkoppelingen", + "add-link": "Link toevoegen", + "add-link-title": "Snelkoppeling toevoegen", + "quick-link": "Snelkoppeling", + "quick-link-required": "Snelle koppeling is vereist.", + "no-links-matching": "Er zijn geen links gevonden die overeenkomen met '{{name}}'.", + "columns": "Kolommen" + }, + "recent-dashboards": { + "title": "Dashboards", + "last": "Laatst bekeken", + "starred": "Speelde", + "name": "Naam", + "last-viewed": "Laatst bekeken", + "no-last-viewed-dashboards": "Nog geen laatst bekeken dashboards" + }, + "configured-features": { + "title": "Geconfigureerde functies", + "info": "Status van functies waarvoor configuratie vereist is", + "white-labeling-feature": "White labelling", + "email-feature": "E-mail", + "sms-feature": "SMS", + "slack-feature": "Los", + "oauth2-feature": "OAuth 2", + "2fa-feature": "2FA", + "feature-configured": "Functie is geconfigureerd.\nKlik om in te stellen", + "feature-not-configured": "Functie is niet geconfigureerd.\nKlik om in te stellen" + }, + "version-info": { + "title": "Versie", + "contact-us": "Neem contact met ons op", + "current-version": "Huidige versie", + "current": "Actueel", + "available-version": "Beschikbare versie", + "available": "Beschikbaar", + "upgrade": "Opwaarderen", + "version-is-up-to-date": "Versie is up-to-date" + }, + "license-info": { + "title": "Licentie info", + "view-all": "Alles weergeven", + "license-portal": "Licentie portaal", + "devices-info": "{count} / { max, plural, =0 {∞} andere {#} } Devices", + "assets-info": "{count} / { max, plural, =0 {∞} andere {#} } Assets", + "dashboards-info": "{count} / { max, plural, =0 {∞} andere {#} } Dashboards", + "integrations-info": "{count} / { max, plural, =0 {∞} andere {#} } Integraties", + "community-support": "Ondersteuning van de gemeenschap", + "white-labeling": "White labelling", + "unlimited-datapoints-and-messages": "Onbeperkt aantal datapunten en berichten", + "unlimited-api-calls": "Onbeperkt aantal API-aanroepen" + }, + "usage-info": { + "title": "Gebruik", + "entities": "Entiteiten", + "api-calls": "API-aanroepen" + }, + "functions": { + "title": "Functies", + "pe-feature-tooltip": "Alleen op ThingsBoard\nProfessionele editie", + "switch-to-pe": "Overschakelen naar PE", + "alarms": "Alarmen", + "dashboards": "Dashboards", + "entities-and-relations": "Entiteiten en relaties", + "profiles": "Profielen", + "advanced-features": "Geavanceerde functies", + "notification-center": "Meldingscentrum", + "api-usage": "API-gebruik", + "customers": "Klanten", + "customers-hierarchy": "Hiërarchie van klanten", + "roles-and-permissions": "Rollen en machtigingen", + "groups": "Groepen", + "integrations": "Integraties", + "solution-templates": "Sjablonen voor oplossingen", + "scheduler": "Scheduler", + "white-labeling": "White labelling" + }, + "devices": { + "view-docs": "Documenten bekijken", + "inactive": "Inactief", + "active": "Actief", + "total": "Totaal" + }, + "alarms": { + "critical": "Kritisch", + "assigned-to-me": "Aan mij toegewezen", + "total": "Totaal" + }, + "solution-templates": { + "title": "Sjablonen voor oplossingen", + "prototype-plan": "Prototype plan", + "startup-plan": "Opstart plan" + }, + "getting-started": { + "get-started": "Start", + "finish": "Einde", + "done-welcome-title": "Welkom", + "done-welcome-text": "Je hebt het geweldig gedaan!", + "sys-admin": { + "step1": { + "title": "Tenant en tenantbeheerder maken", + "content": "

Een tenant is een persoon of een organisatie die devices en bedrijfsmiddelen bezit of produceert. De tenant kan meerdere tenantbeheerders, gebruikers, klanten, devices en assets hebben.

De tenantbeheerder kan devices, assets, klanten en dashboards maken en beheren binnen het tenantaccount.

Volg de documentatie over hoe u dit moet doen:

", + "how-to-create-tenant": "Tenant en tenantbeheerder aanmaken" + }, + "step2": { + "title": "Functie configureren: E-mailserver", + "content": "

De configuratie van de e-mailserver is essentieel voor gebruikersactivering, wachtwoordherstel en bezorging van alarmmeldingen.

Volg de documentatie over hoe u dit moet doen:

", + "how-to-configure-mail-server": "Hoe de e-mailserver te configureren" + }, + "step3": { + "title": "Configureer functie: SMS-provider", + "content": "

Configureer sms-providers om de klanten via sms op de hoogte te stellen van de alarmen.

Volg de documentatie over hoe u dit moet doen:

", + "how-to-configure-sms-provider": "Hoe sms-provider te configureren" + }, + "step4": { + "title": "Configureer functie: White-labeling", + "content": "

Pas eenvoudig het logo en het kleurenschema van uw bedrijf of product aan zonder codering en zonder de service opnieuw te starten.

Volg de documentatie over hoe u dit moet doen:

", + "how-to-configure-white-labeling": "Whitelabeling configureren" + }, + "step5": { + "title": "Configureer functie: 2FA", + "content": "

Verbeter de beveiliging van de platformaccounts met tweefactorauthenticatie.

Volg de documentatie over hoe u dit moet doen:

", + "how-to-configure-2fa": "Hoe configureer je 2FA?" + }, + "step6": { + "title": "Functie configureren: OAuth 2", + "content": "

Vereenvoudig het inloggen voor de tenant en klantgebruikers met Single Sign-On-functionaliteit via OAuth 2.0.

Volg de documentatie over hoe u dit moet doen:

", + "how-to-configure-oauth2": "Hoe OAuth 2 te configureren" + }, + "step7": { + "title": "Functie configureren: Slack", + "content": "

Distribueer meldingen naar de tenant en klantgebruikers via Slack volgens de meldingsregels die u instelt.

Volg de documentatie over hoe u dit moet doen:

", + "how-to-configure-notifications": "Slack configureren" + } + }, + "tenant-admin": { + "step1": { + "title": "Device maken", + "content": "

Laten we uw eerste device via de gebruikersinterface op het platform aanmaken. Volg de documentatie over hoe u dit moet doen:

", + "how-to-create-device": "Hoe een device te maken" + }, + "step2": { + "title": "Device aansluiten", + "content-before": "

Om verbinding te maken met het device, moet u de device referenties ophalen. We raden u aan standaard automatisch gegenereerde referenties te gebruiken die toegangstoken zijn voor deze handleiding.

  • Ga naar de device tabel
  • Klik op de device rij om de apparaatgegevens te openen
  • Druk op de knop \"Toegangstoken kopiëren\"

Gebruik eenvoudige commando's om gegevens via HTTP te publiceren. Vergeet niet om $ACCESS_TOKEN te vervangen door het toegangstoken van uw device:

", + "ubuntu": { + "install-curl": "Installeer cURL voor Ubuntu:" + }, + "macos": { + "install-curl": "Installeer cURL voor MacOS:" + }, + "windows": { + "install-curl": "Vanaf Windows 10 b17063 is cURL standaard beschikbaar." + }, + "replace-access-token": "Vervang $ACCESS_TOKEN door het token van uw device:", + "content-after": "

U kunt ook andere protocollen gebruiken, zoals MQTT, CoAP, enz.

Volg de documentatie over hoe u dit moet doen:

", + "how-to-connect-device": "Hoe het device aan te sluiten" + }, + "step3": { + "title": "Dashboard maken", + "content": "

Maak een dashboard om gegevens van entiteiten zoals assets, devices, enz. te visualiseren.

Volg de documentatie over hoe u dit moet doen:

", + "how-to-create-dashboard": "Hoe maak je een dashboard?" + }, + "step4": { + "title": "Alarmregels configureren", + "alarm-rules": "Alarm regels", + "content": "

Laten we alarm slaan als de temperatuur 25°C bereikt. Volg de documentatie over hoe u dit moet doen:

", + "how-to-configure-alarm-rules": "Alarmregels configureren" + }, + "step5": { + "title": "Alarm maken", + "content-before": "

Om het alarm te activeren, verzendt u een nieuwe telemetriewaarde van 26°C of hoger.

", + "replace-access-token": "Vervang $ACCESS_TOKEN door het token van uw device:", + "content-after": "

Volg de documentatie over hoe u dit moet doen:

", + "how-to-create-alarm": "Hoe maak je een alarm aan?" + }, + "step6": { + "title": "Dashboard voor klanten maken en delen", + "content": "

Door dashboards voor eindgebruikers te maken, kan een klantgebruiker alleen zijn eigen devices zien en worden gegevens van een andere klant verborgen.

Volg de documentatie over hoe u dit moet doen:

", + "how-to-create-customer-and-share-dashboard": "Hoe maak je een klantdashboard en deel je het dashboard?" + } + } + } + }, + "icon": { + "icon": "Pictogram", + "select-icon": "Selecteer icoon", + "material-icons": "Materiaal iconen", + "show-all": "Toon alle iconen" + }, + "subscription": { + "entity-limit-text": "U kunt uw abonnement echter upgraden om uw limieten te verhogen.", + "upgrade-your-plan": "Abonnement upgraden", + "white-labeling-feature": "White labeling-functie", + "white-labeling-text-full": "Rebrand de webinterface van het ThingsBoard-platform in 2 minuten met uw bedrijfs- of productlogo en kleurenschema.

Verwijder \"Powered By\" in de voettekst van het dashboard.
Geen codering of herstart van de service vereist. Sta uw klanten toe om hun interface ook te whitelabelen.", + "enable-white-labeling": "Schakel nu de whitelabeling-functie in door uw abonnement te upgraden!", + "read-more": "Lees meer", + "white-labeling-video-text": "Zie onderstaande video-tutorial om te zien hoe deze functie werkt!" + }, + "subscription-error": { + "title": "Overtreding van het abonnement", + "warning-title": "Waarschuwing voor abonnement", + "upgrade-subscription-plan": "Upgrade uw abonnement", + "upgrade-subscription-plan-to-install-solution-template": "Om {{solutionTemplateName}} oplossing te installeren, moet u uw abonnement minimaal upgraden naar het {{planName}} abonnement!", + "limit-reached": { + "device-count": "Je hebt het maximale aantal devices ({{value}}) bereikt dat is toegestaan door je abonnement!", + "asset-count": "U hebt het maximale vermogen ({{value}}) bereikt dat is toegestaan door uw abonnement!" + }, + "feature-disabled": { + "white-labeling": "De White Labeling-functie is niet toegestaan door uw abonnement!" + } + }, + "phone-input": { + "phone-input-label": "Telefoonnummer", + "phone-input-required": "Telefoonnummer is verplicht", + "phone-input-validation": "Telefoonnummer is ongeldig of niet mogelijk", + "phone-input-pattern": "Ongeldig telefoonnummer. Moet in E.164-formaat zijn, bijv. {{phoneNumber}}", + "phone-input-hint": "Telefoonnummer in E.164-formaat, bijv. {{phoneNumber}}" + }, + "custom": { + "widget-action": { + "action-cell-button": "Actiecelknop", + "row-click": "Klik op rij", + "polygon-click": "Klik op polygoon", + "marker-click": "Klik op de markering", + "circle-click": "Klik op de cirkel", + "tooltip-tag-action": "Actie voor tooltip-tag", + "node-selected": "Op knooppunt geselecteerd", + "element-click": "Klik op het HTML-element op", + "pie-slice-click": "Klik op slice", + "row-double-click": "Dubbelklik op de rij" + } + }, + "paginator": { + "items-per-page": "Items per pagina:", + "first-page-label": "Eerste pagina", + "last-page-label": "Laatste pagina", + "next-page-label": "Volgende pagina", + "previous-page-label": "Vorige pagina", + "items-per-page-separator": "van" + }, + "language": { + "language": "Taal", + "locales": { + "ca_ES": "Catalaans", + "cs_CZ": "Česky", + "da_DK": "Dansk", + "de_DE": "Deutsch", + "el_GR": "Ελληνικά", + "en_US": "Engels", + "es_ES": "Español", + "fa_IR": "فارسي", + "fr_FR": "Français", + "it_IT": "Italiano", + "ja_JP": "日本語", + "ka_GE": "ქართული", + "ko_KR": "한국어", + "lv_LV": "Kanton Latviešu", + "pt_BR": "Português do Brasil", + "ro_RO": "Română", + "ru_RU": "Русский", + "sl_SI": "Slovenščina", + "tr_TR": "Türkçe", + "uk_UA": "Українська", + "zh_CN": "简体中文", + "zh_TW": "繁體中文" + } + } +} diff --git a/ui-ngx/src/assets/locale/locale.constant-ru_RU.json b/ui-ngx/src/assets/locale/locale.constant-ru_RU.json deleted file mode 100644 index 5e15a3496e..0000000000 --- a/ui-ngx/src/assets/locale/locale.constant-ru_RU.json +++ /dev/null @@ -1,1875 +0,0 @@ -{ - "access": { - "unauthorized": "Неавторизированный", - "unauthorized-access": "Несанкционированный доступ", - "unauthorized-access-text": "Вы должны войти в систему для получения доступа к этому ресурсу!", - "access-forbidden": "Доступ запрещен", - "access-forbidden-text": "У вас нет прав доступа к этому ресурсу!
Для получения доступа попробуйте войти под другим пользователем.", - "refresh-token-expired": "Сессия истекла", - "refresh-token-failed": "Не удалось обновить сессию" - }, - "action": { - "activate": "Активировать", - "suspend": "Приостановить", - "save": "Сохранить", - "saveAs": "Сохранить как", - "cancel": "Отмена", - "ok": "ОК", - "delete": "Удалить", - "add": "Добавить", - "yes": "Да", - "no": "Нет", - "update": "Обновить", - "remove": "Удалить", - "search": "Поиск", - "clear-search": "Очистить", - "assign": "Присвоить", - "unassign": "Отозвать", - "share": "Поделиться", - "make-private": "Закрыть для общего доступа", - "apply": "Применить", - "apply-changes": "Применить изменения", - "edit-mode": "Режим редактирования", - "enter-edit-mode": "Режим редактирования", - "decline-changes": "Отменить изменения", - "close": "Закрыть", - "back": "Назад", - "run": "Запуск", - "sign-in": "Войти", - "edit": "Редактировать", - "view": "Просмотреть", - "create": "Создать", - "drag": "Переместить", - "refresh": "Обновить", - "undo": "Откатить", - "copy": "Копировать", - "paste": "Вставить", - "copy-reference": "Копировать ссылку", - "paste-reference": "Вставить ссылку", - "import": "Импортировать", - "export": "Экспортировать", - "share-via": "Поделиться в {{provider}}", - "continue": "Продолжить", - "discard-changes": "Отменить изменения", - "done": "Завершено" - }, - "aggregation": { - "aggregation": "Агрегация", - "function": "Тип агрегации данных", - "limit": "Максимальное значение", - "group-interval": "Интервал группировки", - "min": "Мин", - "max": "Maкс", - "avg": "Среднее", - "sum": "Сумма", - "count": "Количество", - "none": "Без агрегации" - }, - "admin": { - "general": "Общие", - "general-settings": "Общие настройки", - "outgoing-mail": "Исходящая почта", - "outgoing-mail-settings": "Настройки исходящей почты", - "system-settings": "Системные настройки", - "test-mail-sent": "Пробное письмо успешно отправлено!", - "base-url": "Базовая URL", - "base-url-required": "Базовая URL обязательна.", - "mail-from": "Отправитель", - "mail-from-required": "Отправитель обязателен.", - "smtp-protocol": "SMTP протокол", - "smtp-host": "SMTP хост", - "smtp-host-required": "SMTP хост обязателен.", - "smtp-port": "SMTP порт", - "smtp-port-required": "SMTP порт обязателен.", - "smtp-port-invalid": "Недействительный SMTP порт.", - "timeout-msec": "Таймаут (мс)", - "timeout-required": "Таймаут обязателен.", - "timeout-invalid": "Недействительный таймаут.", - "enable-tls": "Включить TLS", - "tls-version" : "Версия TLS", - "send-test-mail": "Отправить пробное письмо", - "security-settings": "Настройки безопасности", - "password-policy": "Политика паролей", - "minimum-password-length": "Минимальная длина пароля", - "minimum-password-length-required": "Требуется минимальная длина пароля", - "minimum-password-length-range": "Минимальная длина пароля должна быть в диапазоне от 5 до 50", - "minimum-uppercase-letters": "Минимальное количество прописных букв", - "minimum-uppercase-letters-range": "Минимальное количество прописных букв не может быть отрицательным", - "minimum-lowercase-letters": "Минимальное количество строчных букв", - "minimum-lowercase-letters-range": "Минимальное количество строчных букв не может быть отрицательным", - "minimum-digits": "Минимальное количество цифр", - "minimum-digits-range": "Минимальное количество цифр не может быть отрицательным", - "minimum-special-characters": "Минимальное количество специальных символов", - "minimum-special-characters-range": "Минимальное количество специальных символов не может быть отрицательным", - "password-expiration-period-days": "Срок действия пароля в днях", - "password-expiration-period-days-range": "Срок действия пароля в днях не может быть отрицательным", - "password-reuse-frequency-days": "Частота повторного использования пароля в днях", - "password-reuse-frequency-days-range": "Частота повторного использования пароля в днях не может быть отрицательной", - "general-policy": "Общая политика", - "max-failed-login-attempts": "Максимальное количество неудачных попыток входа в систему, прежде чем учетная запись заблокирована", - "minimum-max-failed-login-attempts-range": "Максимальное количество неудачных попыток входа в систему не может быть отрицательным", - "user-lockout-notification-email": "В случае блокировки учетной записи пользователя отправьте уведомление на электронную почту", - "smpp-provider": { - "smpp-version": "SMPP версия", - "smpp-host": "SMPP хост", - "smpp-host-required": "SMPP хост обязателен.", - "smpp-port": "SMPP порт", - "smpp-port-required": "SMPP порт обязателен.", - "system-id": "ИД системи", - "system-id-required": "ИД системи обязателен.", - "password": "Пароль", - "password-required": "Пароль обязателен.", - "type-settings": "Настройки типов", - "source-settings": "Настройки источника", - "destination-settings": "Настройки назначения", - "additional-settings": "Дополнительные настройки", - "system-type": "Тип системы", - "bind-type": "Тип привязки", - "service-type": "Тип обслуживания", - "source-address": "Адрес источника", - "source-ton": "Тип номера источника", - "source-npi": "Идентификация плана нумерации источника", - "destination-ton": "Тип номера назничения", - "destination-npi": "Идентификация плана нумерации назначения", - "address-range": "Диапазон адресов", - "coding-scheme": "Схема кодирования" - } - }, - "alarm": { - "alarm": "Оповещение", - "alarms": "Оповещения", - "select-alarm": "Выбрать оповещение", - "no-alarms-matching": "Оповещения '{{entity}}' не найдены.", - "alarm-required": "Оповещение обязательно", - "alarm-status": "Статус оповещения", - "search-status": { - "ANY": "Все", - "ACTIVE": "Активные", - "CLEARED": "Сброшенные", - "ACK": "Подтвержденные", - "UNACK": "Неподтвержденные" - }, - "display-status": { - "ACTIVE_UNACK": "Активные неподтвержденные", - "ACTIVE_ACK": "Активные подтвержденные", - "CLEARED_UNACK": "Сброшенные неподтвержденные", - "CLEARED_ACK": "Сброшенные подтвержденные" - }, - "no-alarms-prompt": "Оповещения отсутствуют", - "created-time": "Время создания", - "type": "Тип", - "severity": "Уровень", - "originator": "Инициатор", - "originator-type": "Тип инициатора", - "details": "Подробности", - "status": "Статус", - "alarm-details": "Подробности об оповещении", - "start-time": "Время начала", - "end-time": "Время окончания", - "ack-time": "Время подтверждения", - "clear-time": "Время сброса", - "severity-critical": "Критический", - "severity-major": "Основной", - "severity-minor": "Второстепенный", - "severity-warning": "Предупреждение", - "severity-indeterminate": "Неопределенный", - "acknowledge": "Подтвердить", - "clear": "Сбросить", - "search": "Поиск оповещений", - "selected-alarms": "Выбрано { count, plural, =1 {1 оповещение} few {# оповещения} other {# оповещений} }", - "no-data": "Нет данных для отображения", - "polling-interval": "Интервал опроса оповещений (сек)", - "polling-interval-required": "Интервал опроса оповещений обязателен.", - "min-polling-interval-message": "Минимальный интервал опроса оповещений 1 секунда.", - "aknowledge-alarms-title": "Подтвердить { count, plural, =1 {1 оповещение} other {# оповещений} }", - "aknowledge-alarms-text": "Вы точно хотите подтвердить { count, plural, =1 {1 оповещение} other {# оповещений} }?", - "aknowledge-alarm-title": "Подтвердить оповещение", - "aknowledge-alarm-text": "Вы точно хотите подтвердить оповещение?", - "clear-alarms-title": "Сбросить { count, plural, =1 {1 оповещение} other {# оповещений} }", - "clear-alarms-text": "Вы точно хотите сбросить { count, plural, =1 {1 оповещение} other {# оповещений} }?", - "clear-alarm-title": "Сбросить оповещение", - "clear-alarm-text": "Вы точно хотите сбросить оповещение?", - "alarm-status-filter": "Фильтр оповещений", - "max-count-load": "Максимальное количество оповещений для загрузки (0 - неограниченно)", - "max-count-load-required": "Максимальное количество оповещений для загрузки обязателен.", - "max-count-load-error-min": "Минимальное значение 0.", - "fetch-size": "Размер пакета для загрузки", - "fetch-size-required": "Размер пакета для загрузки обязателен.", - "fetch-size-error-min": "Минимальное значение 10." - }, - "alias": { - "add": "Добавить псевдоним", - "edit": "Редактировать псевдоним", - "name": "Псевдоним", - "name-required": "Псевдоним обязателен", - "duplicate-alias": "Такой псевдоним уже существует.", - "filter-type-single-entity": "Отдельный объект", - "filter-type-entity-list": "Список объектов", - "filter-type-entity-name": "Название объекта", - "filter-type-state-entity": "Объект из состояния дашборда", - "filter-type-state-entity-description": "Объект, полученный из параметров состояния дашборда", - "filter-type-asset-type": "Тип актива", - "filter-type-asset-type-description": "Активы типа '{{assetTypes}}'", - "filter-type-asset-type-and-name-description": "Активы типа '{{assetTypes}}' и названием, начинающимся с '{{prefix}}'", - "filter-type-device-type": "Тип устройства", - "filter-type-device-type-description": "Устройства типа '{{deviceTypes}}'", - "filter-type-device-type-and-name-description": "Устройства типа '{{deviceTypes}}' и названием, начинающимся с '{{prefix}}'", - "filter-type-entity-view-type": "Тип Представления Объекта", - "filter-type-entity-view-type-description": "Представления Объекта типа '{{entityViewTypes}}'", - "filter-type-entity-view-type-and-name-description": "Представления Объекта типа '{{entityViewTypes}}' и названием, начинающимся с '{{prefix}}'", - "filter-type-relations-query": "Запрос по типу отношений", - "filter-type-relations-query-description": "{{entities}}, имеющие отношение типа {{relationType}} {{direction}} {{rootEntity}}", - "filter-type-asset-search-query": "Поисковый запрос по активам", - "filter-type-asset-search-query-description": "Активы типа {{assetTypes}}, имеющие отношение типа {{relationType}} {{direction}} {{rootEntity}}", - "filter-type-device-search-query": "Поисковый запрос по устройствам", - "filter-type-device-search-query-description": "Устройства типа {{deviceTypes}}, имеющие отношение типа {{relationType}} {{direction}} {{rootEntity}}", - "filter-type-entity-view-search-query": "Поисковый запрос по представлениям объектов", - "filter-type-entity-view-search-query-description": "Представления объектов типа {{entityViewTypes}}, имеющие отношение типа {{relationType}} {{direction}} {{rootEntity}}", - "entity-filter": "Фильтр объектов", - "resolve-multiple": "Принять как несколько объектов", - "filter-type": "Тип фильтра", - "filter-type-required": "Тип фильтра обязателен.", - "entity-filter-no-entity-matched": "Объекты, соответствующие фильтру, не найдены.", - "no-entity-filter-specified": "Не указан фильтр объектов", - "root-state-entity": "Использовать объект, полученный из дашборда, как корневой", - "last-level-relation": "Использовать только отношения последнего уровня", - "root-entity": "Корневой объект", - "state-entity-parameter-name": "Название объекта состояния", - "default-state-entity": "Объект состояния по умолчанию", - "default-entity-parameter-name": "По умолчанию", - "max-relation-level": "Максимальная глубина отношений", - "unlimited-level": "Неограниченная глубина", - "state-entity": "Объект состояния дашборда", - "all-entities": "Все объекты", - "any-relation": "не указано" - }, - "asset": { - "asset": "Актив", - "assets": "Активы", - "management": "Управление активами", - "view-assets": "Просмотреть активы", - "add": "Добавить актив", - "assign-to-customer": "Присвоить клиенту", - "assign-asset-to-customer": "Присвоить актив(ы) клиенту", - "assign-asset-to-customer-text": "Пожалуйста, выберите активы, которые нужно присвоить объекту", - "no-assets-text": "Активы не найдены", - "assign-to-customer-text": "Пожалуйста, выберите клиента, которому нужно присвоить актив(ы)", - "public": "Общедоступные", - "assignedToCustomer": "Присвоить клиенту", - "make-public": "Открыть общий доступ к активу", - "make-private": "Закрыть общий доступ к активу", - "unassign-from-customer": "Отозвать у клиента", - "delete": "Удалить актив", - "asset-public": "Актив общедоступный", - "asset-type": "Тип актива", - "asset-type-required": "Тип актива обязателен.", - "select-asset-type": "Выберите тип актива", - "enter-asset-type": "Введите тип актива", - "any-asset": "Любой актив", - "no-asset-types-matching": "Активы типа '{{entitySubtype}}' не найдены.", - "asset-type-list-empty": "Типы активов не выбраны.", - "asset-types": "Типы активов", - "name": "Название", - "name-required": "Название обязательно.", - "description": "Описание", - "type": "Тип", - "type-required": "Тип обязателен.", - "details": "Подробности", - "events": "События", - "add-asset-text": "Добавить новый актив", - "asset-details": "Подробности об активе", - "assign-assets": "Присвоить активы", - "assign-assets-text": "Присвоить { count, plural, =1 {1 актив} few {# актива} other {# активов} } клиенту", - "delete-assets": "Удалить активы", - "unassign-assets": "Отозвать активы", - "unassign-assets-action-title": "Отозвать { count, plural, =1 {1 актив} few {# актива} other {# активов} } у клиента", - "assign-new-asset": "Присвоить новый актив", - "delete-asset-title": "Вы точно хотите удалить '{{assetName}}'?", - "delete-asset-text": "Внимание, после подтверждения актив и все связанные с ним данные будут безвозвратно удалены.", - "delete-assets-title": "Вы точно хотите удалить { count, plural, =1 {1 актив} few {# актива} other {# активов} }", - "delete-assets-action-title": "Удалить { count, plural, =1 {1 актив} few {# актива} other {# активов} }", - "delete-assets-text": "Внимание, после подтверждения выбранные активы и все связанные с ними данные будут безвозвратно удалены.", - "make-public-asset-title": "Вы точно хотите открыть общий доступ к активу '{{assetName}}'?", - "make-public-asset-text": "Внимание, после подтверждения актив и все связанные с ним данные станут общедоступными.", - "make-private-asset-title": "Вы точно хотите закрыть общий доступ к активу '{{assetName}}'?", - "make-private-asset-text": "После подтверждения актив и все связанные с ним данные будут закрыты для общего доступа", - "unassign-asset-title": "Вы точно хотите отозвать актив '{{assetName}}'?", - "unassign-asset-text": "После подтверждения актив будут отозван, и клиент потеряет к нему доступ.", - "unassign-asset": "Отозвать актив", - "unassign-assets-title": "Вы точно хотите отозвать { count, plural, =1 {1 актив} few {# актива} other {# активов} }?", - "unassign-assets-text": "После подтверждения активы будут отозваны, и клиент потеряет к ним доступ.", - "copyId": "Копировать ИД актива", - "idCopiedMessage": "ИД актива скопировано в буфер обмена", - "select-asset": "Выбрать активы", - "no-assets-matching": "Активы, соответствующие '{{entity}}', не найдены.", - "asset-required": "Актив обязателен", - "name-starts-with": "Название актива, начинающееся с", - "import": "Импортировать активы", - "asset-file": "Файл с активами", - "label": "Метка" - }, - "attribute": { - "attributes": "Атрибуты", - "latest-telemetry": "Последняя телеметрия", - "attributes-scope": "Контекст атрибутов объекта", - "scope-latest-telemetry": "Последняя телеметрия", - "scope-client": "Клиентские атрибуты", - "scope-server": "Серверные атрибуты", - "scope-shared": "Общие атрибуты", - "add": "Добавить атрибут", - "key": "Ключ", - "last-update-time": "Последнее обновление", - "key-required": "Ключ атрибута обязателен.", - "value": "Значение", - "value-required": "Значение атрибута обязательно.", - "delete-attributes-title": "Вы уверенны, что хотите удалить { count, plural, =1 {1 атрибут} few {# атрибута} other {# атрибутов} }? ", - "delete-attributes-text": "Внимание, после подтверждения выбранные атрибуты будут удалены.", - "delete-attributes": "Удалить атрибуты", - "enter-attribute-value": "Введите значение атрибута", - "show-on-widget": "Показать на виджете", - "widget-mode": "Виджет-режим", - "next-widget": "Следующий виджет", - "prev-widget": "Предыдущий виджет", - "add-to-dashboard": "Добавить на дашборд", - "add-widget-to-dashboard": "Добавить виджет на дашборд", - "selected-attributes": "{ count, plural, =1 {Выбран} other {Выбраны} } { count, plural, =1 {1 атрибут} few {# атрибута} other {# атрибутов} }", - "selected-telemetry": "{ count, plural, =1 {Выбран} other {Выбраны} } { count, plural, =1 {1 параметр} few {# параметра} other {# параметров} } телеметрии" - }, - "audit-log": { - "audit": "Аудит", - "audit-logs": "Логи аудита", - "timestamp": "Время", - "entity-type": "Тип объекта", - "entity-name": "Название объекта", - "user": "Пользователь", - "type": "Тип", - "status": "Статус", - "details": "Подробности", - "type-added": "Добавленный", - "type-deleted": "Удаленный", - "type-updated": "Обновленный", - "type-attributes-updated": "Обновлены атрибуты", - "type-attributes-deleted": "Удалены атрибуты", - "type-rpc-call": "RPC вызов", - "type-credentials-updated": "Обновлены учетные данные", - "type-assigned-to-customer": "Присвоен клиенту", - "type-unassigned-from-customer": "Отозван у клиента", - "type-activated": "Активирован", - "type-suspended": "Приостановлен", - "type-credentials-read": "Чтение учетные данных", - "type-attributes-read": "Чтение атрибутов", - "type-relation-add-or-update": "Обновлены отношения", - "type-relation-delete": "Удалены отношения", - "type-relations-delete": "Удалены все отношения", - "type-alarm-ack": "Подтвержден", - "type-alarm-clear": "Сброшен", - "type-login": "Вход", - "type-logout": "Выход", - "type-lockout": "Заблокирован", - "status-success": "Успех", - "status-failure": "Сбой", - "audit-log-details": "Подробности аудит лога", - "no-audit-logs-prompt": "Логи не найдены", - "action-data": "Данные действия", - "failure-details": "Подробности сбоя", - "search": "Поиск аудит логов", - "clear-search": "Очистить поиск" - }, - "confirm-on-exit": { - "message": "У вас есть несохраненные изменения. Вы точно хотите покинуть эту страницу?", - "html-message": "У вас есть несохраненные изменения.
Вы точно хотите покинуть эту страницу?", - "title": "Несохраненные изменения" - }, - "contact": { - "country": "Страна", - "city": "Город", - "state": "Штат", - "postal-code": "Почтовый код", - "postal-code-invalid": "Допустимы только цифры", - "address": "Адрес", - "address2": "Адрес 2", - "phone": "Телефон", - "email": "Эл. адрес", - "no-address": "Адрес не указан" - }, - "common": { - "username": "Имя пользователя", - "password": "Пароль", - "enter-username": "Введите имя пользователя", - "enter-password": "Введите пароль", - "enter-search": "Введите условие поиска", - "created-time": "Время создания" - }, - "content-type": { - "json": "Json", - "text": "Текстовый", - "binary": "Бинарный (Base64)" - }, - "customer": { - "customer": "Клиент", - "customers": "Клиенты", - "management": "Управление клиентами", - "dashboard": "Дашборд клиента", - "dashboards": "Дашборды клиента", - "devices": "Устройства клиента", - "entity-views": "Представления объектов клиента", - "assets": "Активы клиента", - "public-dashboards": "Общедоступные дашборды", - "public-devices": "Общедоступные устройства", - "public-assets": "Общедоступные активы", - "public-entity-views": "Общедоступные представления объектов", - "add": "Добавить клиента", - "delete": "Удалить клиента", - "manage-customer-users": "Управление пользователями клиента", - "manage-customer-devices": "Управление устройствами клиента", - "manage-customer-dashboards": "Управление дашбордами клиента", - "manage-public-devices": "Управление общедоступными устройствами", - "manage-public-dashboards": "Управление общедоступными дашбордами", - "manage-customer-assets": "Управление активами клиента", - "manage-public-assets": "Управление общедоступными активами", - "add-customer-text": "Добавить нового клиента", - "no-customers-text": "Клиенты не найдены", - "customer-details": "Подробности о клиенте", - "delete-customer-title": "Вы точно хотите удалить клиента '{{customerTitle}}'?", - "delete-customer-text": "Внимание, после подтверждения клиент и все связанные с ним данные будут безвозвратно удалены.", - "delete-customers-title": "Вы точно хотите удалить { count, plural, =1 {1 клиент} few {# клиента} other {# клиентов} }?", - "delete-customers-action-title": "Удалить { count, plural, =1 {1 клиент} few {# клиента} other {# клиентов} }", - "delete-customers-text": "Внимание, после подтверждения выбранные клиенты и все связанные с ними данные будут безвозвратно удалены.", - "manage-users": "Управление пользователями", - "manage-assets": "Управление активами", - "manage-devices": "Управление устройствами", - "manage-dashboards": "Управление дашбордами", - "title": "Имя", - "title-required": "Название обязательно.", - "description": "Описание", - "details": "Подробности", - "events": "События", - "copyId": "Копировать ИД клиента", - "idCopiedMessage": "ИД клиента скопирован в буфер обмена", - "select-customer": "Выбрать клиента", - "no-customers-matching": "Клиенты, соответствующие '{{entity}}', не найдены.", - "customer-required": "Клиент обязателен", - "select-default-customer": "Выбрать клиента по умолчанию", - "default-customer": "Клиент по умолчанию", - "default-customer-required": "Клиент по умолчанию обязателен для отладки дашборда на уровне на уровне Владельца" - }, - "datetime": { - "date-from": "Дата с", - "time-from": "Время с", - "date-to": "Дата до", - "time-to": "Время до" - }, - "dashboard": { - "dashboard": "Дашборд", - "dashboards": "Дашборды", - "management": "Управление дашбордами", - "view-dashboards": "Просмотреть дашборды", - "add": "Добавить дашборд", - "assign-dashboard-to-customer": "Прикрепить дашборд(ы) к клиенту", - "assign-dashboard-to-customer-text": "Пожалуйста, выберите дашборды, которые нужно прикрепить к клиенту", - "assign-to-customer-text": "Пожалуйста, выберите клиента, к которому нужно прикрепить дашборд(ы)", - "assign-to-customer": "Прикрепить к клиенту", - "unassign-from-customer": "Отозвать у клиента", - "make-public": "Открыть дашборд для общего доступа", - "make-private": "Закрыть дашборд для общего доступа", - "manage-assigned-customers": "Управление назначенными клиентами", - "assigned-customers": "Назначенные клиенты", - "assign-to-customers": "Присвоить дашборд(ы) клиенту", - "assign-to-customers-text": "Пожалуйста, выбери клиентов, которым нужно присвоить дашборд(ы)", - "unassign-from-customers": "Отозвать дашборд(ы) у клиентов", - "unassign-from-customers-text": "Пожалуйста, выберите клиентов, у которых нужно отозвать дашборд(ы)", - "no-dashboards-text": "Дашборды не найдены", - "no-widgets": "Виджеты не сконфигурированы", - "add-widget": "Добавить новый виджет", - "title": "Название", - "select-widget-title": "Выберите виджет", - "copyId": "Копировать идентификатор дашборда", - "idCopiedMessage": "Идентификатор дашборда скопирован в буфер обмена", - "select-widget-subtitle": "Список доступных виджетов", - "delete": "Удалить дашборд", - "title-required": "Название обязательно.", - "description": "Описание", - "details": "Подробности", - "dashboard-details": "Подробности о дашборде", - "add-dashboard-text": "Добавить новый дашборд", - "assign-dashboards": "Прикрепить дашборды", - "assign-new-dashboard": "Прикрепить новый дашборд", - "assign-dashboards-text": "Прикрепить { count, plural, =1 {1 дашборд} few {# дашборда} other {# дашбордов} } к клиенту", - "unassign-dashboards-action-text": "Отозвать { count, plural, =1 {1 дашборд} few {# дашборда} other {# дашбордов} } у клиента", - "delete-dashboards": "Удалить дашборды", - "unassign-dashboards": "Отозвать дашборды", - "unassign-dashboards-action-title": "Отозвать { count, plural, =1 {1 дашборд} few {# дашборда} other {# дашбордов} } у клиента", - "delete-dashboard-title": "Вы точно хотите удалить дашборд '{{dashboardTitle}}'?", - "delete-dashboard-text": "Внимание, после подтверждения дашборд и все связанные с ним данные будут безвозвратно утеряны.", - "delete-dashboards-title": "Вы точно хотите удалить { count, plural, =1 {1 дашборд} few {# дашборда} other {# дашбордов} }?", - "delete-dashboards-action-title": "Удалить { count, plural, =1 {1 дашборд} few {# дашборда} other {# дашбордов} }", - "delete-dashboards-text": "Внимание, после подтверждения дашборды и все связанные с ними данные будут безвозвратно утеряны.", - "unassign-dashboard-title": "Вы точно хотите отозвать дашборд '{{dashboardTitle}}'?", - "unassign-dashboard-text": "После подтверждения дашборд не будет доступен клиенту.", - "unassign-dashboard": "Отозвать дашборд", - "unassign-dashboards-title": "Вы точно хотите отозвать { count, plural, =1 {1 дашборд} few {# дашборда} other {# дашбордов} }?", - "unassign-dashboards-text": "После подтверждения выбранные дашборды не будут доступны клиенту.", - "public-dashboard-title": "Теперь дашборд общедоступный", - "public-dashboard-text": "Теперь ваш дашборд {{dashboardTitle}} доступен всем по ссылке:", - "public-dashboard-notice": "Примечание: Для получения доступа к данным устройства нужно открыть общий доступ к этому устройству.", - "make-private-dashboard-title": "Вы точно хотите закрыть общий доступ к дашборду '{{dashboardTitle}}'?", - "make-private-dashboard-text": "После подтверждения дашборд будет закрыт для общего доступа.", - "make-private-dashboard": "Закрыть дашборд для общего доступа", - "socialshare-text": "'{{dashboardTitle}}' сделано ThingsBoard", - "socialshare-title": "'{{dashboardTitle}}' сделано ThingsBoard", - "select-dashboard": "Выберите дашборд", - "no-dashboards-matching": "Дашборд '{{entity}}' не найден.", - "dashboard-required": "Дашборд обязателен.", - "select-existing": "Выберите существующий дашборд", - "create-new": "Создать новый дашборд", - "new-dashboard-title": "Новое название дашборда", - "open-dashboard": "Открыть дашборд", - "set-background": "Установить фон", - "background-color": "Фоновый цвет", - "background-image": "Фоновая картинка", - "background-size-mode": "Размер фона", - "no-image": "Картинка не выбрана", - "drop-image": "Перетащите картинку или кликните для выбора файла.", - "settings": "Настройки", - "columns-count": "Количество колонок", - "columns-count-required": "Количество колонок обязательно.", - "min-columns-count-message": "Минимальное число колонок - 10.", - "max-columns-count-message": "Максимальное число колонок - 1000.", - "widgets-margins": "Величина отступа между виджетами", - "horizontal-margin": "Величина горизонтального отступа", - "horizontal-margin-required": "Величина горизонтального отступа обязательна.", - "min-horizontal-margin-message": "Минимальная величина горизонтального отступа - 0.", - "max-horizontal-margin-message": "Максимальная величина горизонтального отступа - 50.", - "vertical-margin": "Величина вертикального отступа", - "vertical-margin-required": "Величина вертикального отступа обязательна.", - "min-vertical-margin-message": "Минимальная величина вертикального отступа - 0.", - "max-vertical-margin-message": "Максимальная величина вертикального отступа - 50.", - "autofill-height": "Автозаполнение по высоте", - "mobile-layout": "Настройки мобильного режима", - "mobile-row-height": "Высота строки в мобильном режиме, px", - "mobile-row-height-required": "Высота строки в мобильном режиме обязательна.", - "min-mobile-row-height-message": "Минимальная высота строки в мобильном режиме составляет 5 px.", - "max-mobile-row-height-message": "Максимальная высота строки в мобильном режиме составляет 200 px.", - "display-title": "Показать название дашборда", - "toolbar-always-open": "Отображать панель инструментов", - "title-color": "Цвет названия", - "display-dashboards-selection": "Отображать выборку дашбордов", - "display-entities-selection": "Отображать выбору объектов", - "display-dashboard-timewindow": "Показать временное окно", - "display-dashboard-export": "Показать экспорт", - "import": "Импортировать дашборд", - "export": "Экспортировать дашборд", - "export-failed-error": "Не удалось экспортировать дашборд: {{error}}", - "create-new-dashboard": "Создать новый дашборд", - "dashboard-file": "Файл дашборда", - "invalid-dashboard-file-error": "Не удалось импортировать дашборд: неизвестная схема данных дашборда.", - "dashboard-import-missing-aliases-title": "Настроить псевдонимы импортированного дашборда", - "create-new-widget": "Создать новый виджет", - "import-widget": "Импортировать виджет", - "widget-file": "Виджет-файл", - "invalid-widget-file-error": "Не удалось импортировать виджет: неправильный формат данных.", - "widget-import-missing-aliases-title": "Настроить псевдонимы, которые использует импортированный виджет", - "open-toolbar": "Открыть панель инструментов дашборда", - "close-toolbar": "Закрыть панель инструментов", - "configuration-error": "Ошибка в настройках", - "alias-resolution-error-title": "Ошибка в настройках псевдонимов дашборда", - "invalid-aliases-config": "Не удалось найти устройство, соответствующее фильтру псевдонимов.
Пожалуйста, обратитесь к администратору для устранения неполадки.", - "select-devices": "Выберите устройства", - "assignedToCustomer": "Присвоенные клиенту", - "assignedToCustomers": "Присвоенные клиентам", - "public": "Публичный", - "public-link": "Публичная ссылка", - "copy-public-link": "Копировать публичную ссылку", - "public-link-copied-message": "Публичная ссылка на дашборд скопирована в буфер обмена.", - "manage-states": "Управление состоянием дашборда", - "states": "Состояния дашборда", - "search-states": "Поиск состояния дашборда", - "selected-states": "Выбрано { count, plural, =1 {1 состояние} few {# состояния} other {# состояний} } дашборда", - "edit-state": "Изменить состояние дашборда", - "delete-state": "Удалить состояние дашборда", - "add-state": "Добавить состояние дашборда", - "state": "Состояние дашборда", - "state-name": "Название", - "state-name-required": "Название состояния дашборда обязательно.", - "state-id": "ИД состояния", - "state-id-required": "ИД состояния дашборда обязателен.", - "state-id-exists": "Состояния дашборда с таким именем уже существует.", - "is-root-state": "Корневое состояние", - "delete-state-title": "Удалить состояние дашборда", - "delete-state-text": "Вы точно хотите удалить состояние дашборда '{{stateName}}'?", - "show-details": "Показать подробности", - "hide-details": "Скрыть подробности", - "select-state": "Выбрать состояние", - "state-controller": "Контроллер состояния" - }, - "datakey": { - "settings": "Настройки", - "advanced": "Дополнительно", - "label": "Метка", - "color": "Цвет", - "units": "Укажите символы, которые нужно указывать после значения", - "decimals": "Число знаков после запятой", - "data-generation-func": "Функция генерации данных", - "use-data-post-processing-func": "Использовать функцию пост-обработки данных", - "configuration": "Конфигурация ключа данных", - "timeseries": "Телеметрия", - "attributes": "Атрибуты", - "entity-field": "Поле объекта", - "alarm": "Параметры оповещения", - "timeseries-required": "Телеметрия объекта обязательна.", - "timeseries-or-attributes-required": "Телеметрия/атрибуты обязательны.", - "maximum-timeseries-or-attributes": "Максимальное количество параметров телеметрии или атрибутов равно {{count}}", - "alarm-fields-required": "Параметры оповещения обязательны.", - "function-types": "Тип функции", - "function-types-required": "Тип функции обязателен.", - "maximum-function-types": "Максимальное количество типов функции равно {{count}}", - "time-description": "время текущего значения;", - "value-description": "текущее значение;", - "prev-value-description": "результат предыдущего вызова функции;", - "time-prev-description": "время предыдущего значения;", - "prev-orig-value-description": "исходное предыдущее значение;" - }, - "datasource": { - "type": "Тип источника данных", - "name": "Название", - "add-datasource-prompt": "Пожалуйста, добавьте источник данных" - }, - "details": { - "edit-mode": "Режим редактирования", - "edit-json": "Редактировать JSON", - "toggle-edit-mode": "Режим редактирования" - }, - "device": { - "device": "Устройство", - "device-required": "Устройство обязательно.", - "devices": "Устройства", - "management": "Управление устройствами", - "view-devices": "Просмотреть устройства", - "device-alias": "Псевдоним устройства", - "aliases": "Псевдонимы устройства", - "no-alias-matching": "'{{alias}}' не найден.", - "no-aliases-found": "Псевдонимы не найдены.", - "no-key-matching": "'{{key}}' не найден.", - "no-keys-found": "Ключи не найдены.", - "create-new-alias": "Создать новый!", - "create-new-key": "Создать новый!", - "duplicate-alias-error": "Найден дублирующийся псевдоним '{{alias}}'.
В рамках дашборда псевдонимы устройств должны быть уникальными.", - "configure-alias": "Настроить '{{alias}}' псевдоним", - "no-devices-matching": "Устройство '{{entity}}' не найдено.", - "alias": "Псевдоним", - "alias-required": "Псевдоним устройства обязателен.", - "remove-alias": "Удалить псевдоним устройства", - "add-alias": "Добавить псевдоним устройства", - "name-starts-with": "Название начинается с", - "device-list": "Список устройств", - "use-device-name-filter": "Использовать фильтр", - "device-list-empty": "Устройства не выбраны.", - "device-name-filter-required": "Фильтр названия устройства обязателен.", - "device-name-filter-no-device-matched": "Устройства, названия которых начинаются с '{{device}}', не найдены.", - "add": "Добавить устройство", - "assign-to-customer": "Присвоить клиенту", - "assign-device-to-customer": "Присвоить устройство(а) клиенту", - "assign-device-to-customer-text": "Пожалуйста, выберите устройства, которые нужно присвоить клиенту", - "make-public": "Открыть общий доступ к устройству", - "make-private": "Закрыть общий доступ к устройству", - "no-devices-text": "Устройства не найдены", - "assign-to-customer-text": "Пожалуйста, выберите клиента, которому нужно присвоить устройство(а)", - "device-details": "Подробности об устройстве", - "add-device-text": "Добавить новое устройство", - "credentials": "Учетные данные", - "manage-credentials": "Управление учетными данными", - "delete": "Удалить устройство", - "assign-devices": "Присвоить устройство", - "assign-devices-text": "Присвоить { count, plural, =1 {1 устройство} few {# устройства} other {# устройств} } клиенту", - "delete-devices": "Удалить устройства", - "unassign-from-customer": "Отозвать у клиенту", - "unassign-devices": "Отозвать устройства", - "unassign-devices-action-title": "Отозвать у клиента { count, plural, =1 {1 устройство} few {# устройства} other {# устройств} }", - "assign-new-device": "Присвоить новое устройство", - "make-public-device-title": "Вы точно хотите открыть общий доступ к устройству '{{deviceName}}'?", - "make-public-device-text": "После подтверждения устройство и все связанные с ним данные будут общедоступными.", - "make-private-device-title": "Вы точно хотите закрыть общий доступ к устройству '{{deviceName}}'", - "make-private-device-text": "После подтверждения устройство и все связанные с ним данные будут закрыты для общего доступа.", - "view-credentials": "Просмотреть учетные данные", - "delete-device-title": "Вы точно хотите удалить устройство '{{deviceName}}'?", - "delete-device-text": "Внимание, после подтверждения устройство и все связанные с ним данные будут безвозвратно утеряны.", - "delete-devices-title": "Вы точно хотите удалить { count, plural, =1 {1 устройство} few {# устройства} other {# устройств} }?", - "delete-devices-action-title": "Удалить { count, plural, =1 {1 устройство} few {# устройства} other {# устройств} }", - "delete-devices-text": "Внимание, после подтверждения выбранные устройства и все связанные с ними данные будут безвозвратно утеряны..", - "unassign-device-title": "Вы точно хотите отозвать устройство '{{deviceName}}'?", - "unassign-device-text": "После подтверждения устройство будет недоступно клиенту.", - "unassign-device": "Отозвать устройство", - "unassign-devices-title": "Вы точно хотите отозвать { count, plural, =1 {1 устройство} few {# устройства} other {# устройств} }?", - "unassign-devices-text": "После подтверждения выбранные устройства будут недоступны клиенту.", - "device-credentials": "Учетные данные устройства", - "credentials-type": "Тип учетных данных", - "access-token": "Токен", - "access-token-required": "Токен обязателен.", - "access-token-invalid": "Длина токена должна быть от 1 до 32 символов.", - "secret": "Секрет", - "secret-required": "Секрет обязателен.", - "device-type": "Тип устройства", - "device-type-required": "Тип устройства обязатеен.", - "select-device-type": "Выберите тип устройства", - "enter-device-type": "Введите тип устройства", - "any-device": "Любое устройство", - "no-device-types-matching": "Тип устройства, соответствующий '{{entitySubtype}}', не найден.", - "device-type-list-empty": "Не выбран тип устройства.", - "device-types": "Типы устройств", - "name": "Название", - "name-required": "Название обязательно.", - "description": "Описание", - "events": "События", - "details": "Подробности", - "copyId": "Копировать идентификатор устройства", - "copyAccessToken": "Копировать токен", - "idCopiedMessage": "Идентификатор устройства скопирован в буфер обмена", - "accessTokenCopiedMessage": "Токен устройства скопирован в буфер обмена", - "assignedToCustomer": "Присвоен клиенту", - "unable-delete-device-alias-title": "Не удалось удалить псевдоним устройства", - "unable-delete-device-alias-text": "Не удалось удалить псевдоним '{{deviceAlias}}' устройства, т.к. он используется следующими виджетами:
{{widgetsList}}", - "is-gateway": "Гейтвей", - "public": "Общедоступный", - "device-public": "Устройство общедоступно", - "select-device": "Выбрать устройство", - "import": "Импортировать устройства", - "device-file": "Файл с устройствами" - }, - "dialog": { - "close": "Закрыть диалог" - }, - "direction": { - "column": "Колонка", - "row": "Строка" - }, - "error": { - "unable-to-connect": "Не удалось подключиться к серверу! Пожалуйста, проверьте интернет-соединение.", - "unhandled-error-code": "Код необработанной ошибки: {{errorCode}}", - "unknown-error": "Неизвестная ошибка" - }, - "entity": { - "entity": "Объект", - "entities": "Объекты", - "aliases": "Псевдонимы объекта", - "entity-alias": "Псевдоним объекта", - "unable-delete-entity-alias-title": "Не удалось удалить псевдоним объекта", - "unable-delete-entity-alias-text": "Псевдоним объекта '{{entityAlias}}' не может быть удален, так как используется следующим(и) виджетом(ами):
{{widgetsList}}", - "duplicate-alias-error": "Найден дубликат псевдонима '{{alias}}'.
В рамках одного дашборда псевдонимы объектов должны быть уникальными.", - "missing-entity-filter-error": "Отсутствует фильтр для псевдонима '{{alias}}'.", - "configure-alias": "Настроить псевдоним '{{alias}}'", - "alias": "Псевдоним", - "alias-required": "Псевдоним объекта обязателен.", - "remove-alias": "Убрать псевдоним объекта", - "add-alias": "Добавить псевдоним объекта", - "entity-list": "Список объектов", - "entity-type": "Тип объекта", - "entity-types": "Типы объекта", - "entity-type-list": "Список типов объекта", - "any-entity": "Любой объект", - "enter-entity-type": "Введите тип объекта", - "no-entities-matching": "Объекты, соответствующие '{{entity}}', не найдены.", - "no-entity-types-matching": "Типы объектов, соответствующие '{{entityType}}', не найдены.", - "name-starts-with": "Название, начинающееся с", - "use-entity-name-filter": "Использовать фильтр", - "entity-list-empty": "Не выбраны объекты.", - "entity-name-filter-required": "Фильтр по названию объекта обязателен.", - "entity-name-filter-no-entity-matched": "Объекты, чье название начинается с '{{entity}}', не найдены.", - "all-subtypes": "Все", - "select-entities": "Выберите объекты", - "no-aliases-found": "Псевдонимы не найдены.", - "no-alias-matching": "Псевдоним '{{alias}}' не найден.", - "create-new-alias": "Создать новый!", - "key": "Ключ", - "key-name": "Название ключа", - "no-keys-found": "Ключ не найден.", - "no-key-matching": "Ключ '{{key}}' не найден.", - "create-new-key": "Создать новый!", - "type": "Тип", - "type-required": "Тип объекта обязателен.", - "type-device": "Устройство", - "type-devices": "Устройства", - "list-of-devices": "{ count, plural, =1 {Одно устройство} other {Список из # устройств} }", - "device-name-starts-with": "Устройства, чьи название начинается с '{{prefix}}'", - "type-asset": "Актив", - "type-assets": "Активы", - "list-of-assets": "{ count, plural, =1 {Один актив} other {Список из # активов} }", - "asset-name-starts-with": "Активы, чьи название начинается с '{{prefix}}'", - "type-entity-view": "Представление Объекта", - "type-entity-views": "Представления Объекта", - "list-of-entity-views": "{ count, plural, =1 {Одно представление объекта} other {Список из # представлений объекта} }", - "entity-view-name-starts-with": "Представления Объекта, чьи название начинается с '{{prefix}}'", - "type-rule": "Правило", - "type-rules": "Правила", - "list-of-rules": "{ count, plural, =1 {Одно правило} other {Список из # правил} }", - "rule-name-starts-with": "Правила, чьи названия начинаются с '{{prefix}}'", - "type-plugin": "Плагин", - "type-plugins": "Плагины", - "list-of-plugins": "{ count, plural, =1 {Один плагин} other {Список из # плагинов} }", - "plugin-name-starts-with": "Плагины, чьи имена начинаются с '{{prefix}}'", - "type-tenant": "Владелец", - "type-tenants": "Владельцы", - "list-of-tenants": "{ count, plural, =1 {Один владелец} other {Список из # владельцев} }", - "tenant-name-starts-with": "Владельцы, чьи имена начинаются с '{{prefix}}'", - "type-customer": "Клиент", - "type-customers": "Клиенты", - "list-of-customers": "{ count, plural, =1 {Один клиент} other {Список из # клиентов} }", - "customer-name-starts-with": "Клиенты, чьи имена начинаются с '{{prefix}}'", - "type-user": "Пользователь", - "type-users": "Пользователи", - "list-of-users": "{ count, plural, =1 {Один пользователь} other {Список из # пользователей} }", - "user-name-starts-with": "Пользователи, чьи имена начинаются с '{{prefix}}'", - "type-dashboard": "Дашборд", - "type-dashboards": "Дашборды", - "list-of-dashboards": "{ count, plural, =1 {Один дашборд} other {Список из # дашбордов} }", - "dashboard-name-starts-with": "Дашборды, чьи названия начинаются с '{{prefix}}'", - "type-alarm": "Оповещение", - "type-alarms": "Оповещения", - "list-of-alarms": "{ count, plural, =1 {Одно оповещение} other {Список из # оповещений} }", - "alarm-name-starts-with": "Оповещения, чьи названия начинаются с '{{prefix}}'", - "type-rulechain": "Цепочка правил", - "type-rulechains": "Цепочки правил", - "list-of-rulechains": "{ count, plural, =1 {Одна цепочка правил} other {Список из # цепочек правил} }", - "rulechain-name-starts-with": "Цепочки правил, чьи названия начинаются с '{{prefix}}'", - "type-rulenode": "Правило", - "type-rulenodes": "Правила", - "list-of-rulenodes": "{ count, plural, =1 {Одно правило} other {Список из # правил} }", - "rulenode-name-starts-with": "Правила, чьи названия начинаются с '{{prefix}}'", - "type-current-customer": "Текущий клиент", - "type-current-tenant": "Текущий владелец", - "search": "Поиск объектов", - "selected-entities": "Выбран(ы) { count, plural, =1 {1 объект} few {# объекта} other {# объектов} }", - "entity-name": "Название объекта", - "entity-label": "Метка объекта", - "details": "Подробности об объекте", - "no-entities-prompt": "Объекты не найдены", - "no-data": "Нет данных для отображения", - "columns-to-display": "Отобразить следующие колонки" - }, - "entity-field": { - "created-time": "Время создания", - "name": "Название", - "type": "Тип", - "first-name": "Имя", - "last-name": "Фамилия", - "email": "Электронная почта", - "title": "Название", - "country": "Страна", - "state": "Штат/Область", - "city": "Город", - "address": "Адрес", - "address2": "Адрес 2", - "zip": "Индекс", - "phone": "Телефон", - "label": "Метка" - }, - "entity-view": { - "entity-view": "Представление Объекта", - "entity-view-required": "Представление объекта обязательно.", - "entity-views": "Представления Объектов", - "management": "Управление представлениями объектов", - "view-entity-views": "Просмотр представлений объектов", - "entity-view-alias": "Псевдоним Представления Объекта", - "aliases": "Псевдонимы Представления Объекта", - "no-alias-matching": "Псевдоним '{{alias}}' не найден.", - "no-aliases-found": "Псевдонимы не найдены.", - "no-key-matching": "Ключ '{{key}}' не найден.", - "no-keys-found": "Ключи не найдены.", - "create-new-alias": "Создать новый!", - "create-new-key": "Создать новый!", - "duplicate-alias-error": "Найден дубликат псевдонима '{{alias}}'.
В рамках одного дашборда псевдонимы представлений объектов должны быть уникальными.", - "configure-alias": "Настроить псевдоним '{{alias}}'", - "no-entity-views-matching": "Объекты, соответствующие '{{entity}}', не найдены.", - "alias": "Псевдоним", - "alias-required": "Псевдоним представления объекта обязателен.", - "remove-alias": "Убрать псевдоним представления объекта", - "add-alias": "Добавить псевдоним представления объекта", - "name-starts-with": "Представления объектов, чьи название начинается с", - "entity-view-list": "Список представлений объектов", - "use-entity-view-name-filter": "Использовать фильтр", - "entity-view-list-empty": "Не выбраны представления объектов.", - "entity-view-name-filter-required": "Для представлений объектов фильтр по названиям обязателен.", - "entity-view-name-filter-no-entity-view-matched": "Представление объектов, чьи название начинаются с '{{entityView}}', не найдены.", - "add": "Представление объекта", - "assign-to-customer": "Назначить клиенту", - "assign-entity-view-to-customer": "Назначить представление(я) объекта(ов) клиенту", - "assign-entity-view-to-customer-text": "Пожалуйста, выберите представления объектов, которые нужно назначить клиенту", - "no-entity-views-text": "Представления объектов не найдены", - "assign-to-customer-text": "Пожалуйста, выберите клиента, которому нужно назначить представления объектов", - "entity-view-details": "Подробности о представлении объекта", - "add-entity-view-text": "Добавить новое представление объекта", - "delete": "Удалить представление объекта", - "assign-entity-views": "Назначить представления объектов", - "assign-entity-views-text": "Назначить клиенту { count, plural, =1 {1 представление объекта} few {# представления объектов} other {# представлений объектов} }", - "delete-entity-views": "Удалить представления объектов", - "unassign-from-customer": "Отозвать у клиента", - "unassign-entity-views": "Отозвать представления объектов", - "unassign-entity-views-action-title": "Отозвать у клиента { count, plural, =1 {1 представление объекта} few {# представления объектов} other {# представлений объектов} }", - "assign-new-entity-view": "Назначит новое представление объекта", - "delete-entity-view-title": "Вы точно хотите удалить представление объекта '{{entityViewName}}'?", - "delete-entity-view-text": "Внимание, после подтверждения представление объекта и все связанные с ним данные будут безвозвратно удалены.", - "delete-entity-views-title": "Вы точно хотите удалить { count, plural, =1 {1 представление объекта} few {# представления объектов} other {# представлений объектов} }?", - "delete-entity-views-action-title": "Удалить { count, plural, =1 {1 представление объекта} few {# представления объектов} other {# представлений объектов} }", - "delete-entity-views-text": "Внимание, после подтверждения выбранные представления объектов и все связанные с ними данные будут безвозвратно удалены.", - "unassign-entity-view-title": "Вы точно хотите отозвать представление объекта '{{entityViewName}}'?", - "unassign-entity-view-text": "После подтверждение представление объекта будет недоступно клиенту.", - "unassign-entity-view": "Отозвать представление объекта", - "unassign-entity-views-title": "Вы точно хотите отозвать { count, plural, =1 {1 представление объекта} few {# представления объектов} other {# представлений объектов} }?", - "unassign-entity-views-text": "После подтверждение выбранные представления объектов будет недоступно клиенту.", - "entity-view-type": "Тип представления объекта", - "entity-view-type-required": "Тип представления объекта обязателен.", - "select-entity-view-type": "Выберите тип представления объекта", - "enter-entity-view-type": "Введите тип представления объекта", - "any-entity-view": "Любое представление объекта", - "no-entity-view-types-matching": "Типы представления объекта, соответствующие '{{entitySubtype}}', не найдены.", - "entity-view-type-list-empty": "Не выбраны типы представления объекта.", - "entity-view-types": "Типы представления объекта", - "name": "Название", - "name-required": "Название обязательно.", - "description": "Описание", - "events": "События", - "details": "Подробности", - "copyId": "Копировать ИД представление объекта", - "assignedToCustomer": "Назначено клиенту", - "unable-entity-view-device-alias-title": "Не удалось удалить псевдоним представления объекта", - "unable-entity-view-device-alias-text": "Не удалось удалить псевдоним устройства '{{entityViewAlias}}', т.к. он используется следующими виджетами:
{{widgetsList}}", - "select-entity-view": "Выбрать представление объекта", - "make-public": "Открыть общий доступ к представлению объекта", - "make-private": "Закрыть общий доступ к представлению объекта", - "start-date": "Дата начала", - "start-ts": "Время начала", - "end-date": "Дата окончания", - "end-ts": "Время окончания", - "date-limits": "Временной лимит", - "client-attributes": "Клиентские атрибуты", - "shared-attributes": "Общие атрибуты", - "server-attributes": "Серверные атрибуты", - "timeseries": "Телеметрия", - "client-attributes-placeholder": "Клиентские атрибуты", - "shared-attributes-placeholder": "Общие атрибуты", - "server-attributes-placeholder": "Серверные атрибуты", - "timeseries-placeholder": "Телеметрия", - "target-entity": "Целевой объект", - "attributes-propagation": "Пробросить атрибуты", - "attributes-propagation-hint": "Представление объекта автоматически копирует указанные атрибуты с Целевого Объекта каждый раз, когда вы сохраняете или обновляете это представление. В целях производительности атрибуты целевого объекта не пробрасываются в представление объекта на каждом их изменении. Вы можете включить автоматический проброс, настроив в вашей цепочке правило \"copy to view\" и соединив его с сообщениями типа \"Post attributes\" и \"Attributes Updated\".", - "timeseries-data": "Данные телеметрии", - "timeseries-data-hint": "Настроить ключи данных телеметрии целевого объекта, которые будут доступны представлению объекта. Эти данные только для чтения.", - "make-public-entity-view-title": "Вы уверенны, что хотите открыть общий доступ к представленю объекта '{{entityViewName}}'?", - "make-public-entity-view-text": "После подтверждения представление объекта и все связанные с ним данные станут публичными и доступными для других пользователей.", - "make-private-entity-view-title": "Вы уверенны, что хотите закрыть общий доступ к представлению объекта '{{entityViewName}}'?", - "make-private-entity-view-text": "После подтверждения представление объекта и все звязанные с ним данные станут приватными и не будут доступны для других пользователей." - }, - "event": { - "event-type": "Тип события", - "type-error": "Ошибка", - "type-lc-event": "Событие жизненного цикла", - "type-stats": "Статистика", - "type-debug-rule-node": "Отладка", - "type-debug-rule-chain": "Отладка", - "no-events-prompt": "События не найдены", - "error": "Ошибка", - "alarm": "Аварийное оповещение", - "event-time": "Время возникновения события", - "server": "Сервер", - "body": "Тело", - "method": "Метод", - "type": "Тип", - "message-id": "ИД сообщения", - "message-type": "Тип сообщения", - "data-type": "Тип данных", - "relation-type": "Тип отношения", - "metadata": "Метаданные", - "data": "Данные", - "event": "Событие", - "status": "Статус", - "success": "Успех", - "failed": "Неудача", - "messages-processed": "Сообщения обработаны", - "errors-occurred": "Возникли ошибки", - "all-events": "Все", - "entity-type": "Тип объекта", - "clear-request-title": "Удалить все события", - "clear-request-text": "Вы точно хотите удалить все события?" - }, - "extension": { - "extensions": "Расширение", - "selected-extensions": "Выбрано { count, plural, =1 {1 расширение} few {# расширения} other {# расширений} }", - "type": "Тип", - "key": "Ключ", - "value": "Значение", - "id": "ИД", - "extension-id": "ИД расширения", - "extension-type": "Тип расширения", - "transformer-json": "JSON *", - "unique-id-required": "Такое ИД расширения уже существует.", - "delete": "Удалить расширение", - "add": "Добавить расширение", - "edit": "Редактировать расширение", - "delete-extension-title": "Вы точно хотите удалить расширение '{{extensionId}}'?", - "delete-extension-text": "Внимание, после подтверждения расширение и все связанные с ним данные будут безвозвратно удалены.", - "delete-extensions-title": "Вы точно хотите удалить { count, plural, =1 {1 расширение} few {# расширения} other {# расширений} }?", - "delete-extensions-text": "Внимание, после подтверждения выбранные расширения будут удалены.", - "converters": "Конвертеры", - "converter-id": "ИД конвертера", - "configuration": "Конфигурация", - "converter-configurations": "Конфигурация конвертера", - "token": "Токен безопасности", - "add-converter": "Добавить конвертер", - "add-config": "Добавить конфигурацию конвертера", - "device-name-expression": "Маска названия устройства", - "device-type-expression": "Маска типа устройства", - "custom": "Пользовательский", - "to-double": "To Double", - "transformer": "Преобразователь", - "json-required": "JSON преобразователя обязателен.", - "json-parse": "Не удалось распознать JSON преобразователя.", - "attributes": "Атрибуты", - "add-attribute": "Добавить атрибут", - "add-map": "Добавить элемент сопоставления", - "timeseries": "Телеметрия", - "add-timeseries": "Добавить параметр телеметрии", - "field-required": "Параметр обязателен", - "brokers": "Брокеры", - "add-broker": "Добавить брокер", - "host": "Хост", - "port": "Порт", - "port-range": "Значение порта лежит в диапазоне от 1 до 65535.", - "ssl": "SSL", - "credentials": "Учетные данные", - "username": "Имя пользователя", - "password": "Пароль", - "retry-interval": "Интервал повтора в миллисекундах", - "anonymous": "Анонимный", - "basic": "Общий", - "pem": "PEM", - "ca-cert": "Файл CA сертификата *", - "private-key": "Файл приватного ключа *", - "cert": "Файл сертификата *", - "no-file": "Не выбран файл.", - "drop-file": "Перетяните файл или нажмите для выбора файла.", - "mapping": "Сопоставление", - "topic-filter": "Фильтр тем", - "converter-type": "Тип конвертера", - "converter-json": "JSON", - "json-name-expression": "JSON выражение для названия устройства", - "topic-name-expression": "Выражение для названия устройства в названии темы", - "json-type-expression": "JSON выражение для типа устройства", - "topic-type-expression": "Выражение для типа устройства в названии темы", - "attribute-key-expression": "Выражение для атрибута", - "attr-json-key-expression": "JSON выражение для атрибута", - "attr-topic-key-expression": "Выражение для атрибута в названии темы", - "request-id-expression": "Выражение для ИД запроса", - "request-id-json-expression": "JSON выражение для ИД запроса", - "request-id-topic-expression": "Выражение для ИД запроса в названии темы", - "response-topic-expression": "Выражение для темы ответов", - "value-expression": "Выражение для значения", - "topic": "Тема", - "timeout": "Таймаут в миллисекундах", - "converter-json-required": "JSON конвертер обязателен.", - "converter-json-parse": "Не удалось распознать JSON конвертера.", - "filter-expression": "Выражение для фильтрации", - "connect-requests": "Запросы о подключении устройства", - "add-connect-request": "Добавить запросы о подключении устройства", - "disconnect-requests": "Запросы об отсоединении устройства", - "add-disconnect-request": "Добавить запрос об отсоединении устройства", - "attribute-requests": "Запросы для атрибутов", - "add-attribute-request": "Добавить запрос для атрибутов", - "attribute-updates": "Обновление атрибутов", - "add-attribute-update": "Добавить обновление атрибутов", - "server-side-rpc": "Серверный RPC", - "add-server-side-rpc-request": "Добавить серверный RPC", - "device-name-filter": "Фильтр для названия устройства", - "attribute-filter": "Фильтр для атрибутов", - "method-filter": "Фильтр для процедур", - "request-topic-expression": "Выражение для темы запросов", - "response-timeout": "Время ожидания ответа в миллисекундах", - "topic-expression": "Выражение для названия темы", - "client-scope": "Клиентский", - "add-device": "Добавить устройство", - "opc-server": "Серверы", - "opc-add-server": "Добавить сервер", - "opc-add-server-prompt": "Пожалуйста, добавьте сервер", - "opc-application-name": "Название приложения", - "opc-application-uri": "URI приложения", - "opc-scan-period-in-seconds": "Частота сканирования в секундах", - "opc-security": "Безопасность", - "opc-identity": "Идентификация", - "opc-keystore": "Хранилище ключей", - "opc-type": "Тип", - "opc-keystore-type": "Тип", - "opc-keystore-location": "Расположение *", - "opc-keystore-password": "Пароль", - "opc-keystore-alias": "Псевдоним", - "opc-keystore-key-password": "Пароль для ключ", - "opc-device-node-pattern": "Паттерн OPC узла устройства", - "opc-device-name-pattern": "Паттерн названия устройства", - "modbus-server": "Серверы/ведомые устройства", - "modbus-add-server": "Добавить сервер/ведомое устройство", - "modbus-add-server-prompt": "Пожалуйста, добавить сервер/ведомое устройство", - "modbus-transport": "Транспорт", - "modbus-tcp-reconnect": "Переподключатсься автоматически", - "modbus-port-name": "Название последовательного порта", - "modbus-encoding": "Кодирование символов", - "modbus-parity": "Паритет", - "modbus-baudrate": "Скорость передачи", - "modbus-databits": "Биты данных", - "modbus-stopbits": "Стоп-биты", - "modbus-databits-range": "Параметр \"Биты данных\" может принимать значения 7 или 8.", - "modbus-stopbits-range": "Параметр \"Стоп-биты\" может принимать значения 1 или 2.", - "modbus-unit-id": "ИД устройства", - "modbus-unit-id-range": "ИД устройства должен быть в диапазоне от 1 до 247.", - "modbus-device-name": "Название устройства", - "modbus-poll-period": "Частота опроса (в миллисекундах)", - "modbus-attributes-poll-period": "Частота опроса для атрибутов (в миллисекундах)", - "modbus-timeseries-poll-period": "Частота опроса для телеметрии (в миллисекундах)", - "modbus-poll-period-range": "Значение параметра \"Частота опроса\" должно быть больше ноля.", - "modbus-tag": "Тег", - "modbus-function": "Modbus функция", - "modbus-register-address": "Адрес регистра", - "modbus-register-address-range": "Адрес регистра должен быть в диапазоне от 0 до 65535.", - "modbus-register-bit-index": "Номер бита", - "modbus-register-bit-index-range": "Номер бита должен быть в диапазоне от 0 до 15.", - "modbus-register-count": "Количество регистров", - "modbus-register-count-range": "Количество регистров должно быть больше ноля.", - "modbus-byte-order": "Порядок байтов", - "sync": { - "status": "Статус", - "sync": "Синхронизирован", - "not-sync": "Не синхронизирован", - "last-sync-time": "Время последней синхронизации", - "not-available": "Не доступен" - }, - "export-extensions-configuration": "Экспортировать конфигурацию расширений", - "import-extensions-configuration": "Импортировать конфигурацию расширений", - "import-extensions": "Импортировать расширения", - "import-extension": "Импортировать расширение", - "export-extension": "Экспортировать расширение", - "file": "Файл расширений", - "invalid-file-error": "Не правильный формат файла" - }, - "fullscreen": { - "expand": "Во весь экран", - "exit": "Выйти из полноэкранного режима", - "toggle": "Во весь экран", - "fullscreen": "Полноэкранный режим" - }, - "function": { - "function": "Функция" - }, - "grid": { - "delete-item-title": "Вы точно хотите удалить этот объект?", - "delete-item-text": "Внимание, после подтверждения объект и все связанные с ним данные будут безвозвратно утеряны.", - "delete-items-title": "Вы точно хотите удалить { count, plural, =1 {1 объект} few {# объекта} other {# объектов} }?", - "delete-items-action-title": "Удалить { count, plural, =1 {1 объект} few {# объекта} other {# объектов} }", - "delete-items-text": "Внимание, после подтверждения выбранные объекты и все связанные с ними данные будут безвозвратно утеряны.", - "add-item-text": "Добавить новый объект", - "no-items-text": "Объекты не найдены", - "item-details": "Подробности об объекте", - "delete-item": "Удалить объект", - "delete-items": "Удалить объекты", - "scroll-to-top": "Прокрутка к началу" - }, - "help": { - "goto-help-page": "Перейти к справке" - }, - "home": { - "home": "Главная", - "profile": "Профиль", - "logout": "Выйти из системы", - "menu": "Меню", - "avatar": "Аватар", - "open-user-menu": "Открыть меню пользователя" - }, - "import": { - "no-file": "Файл не выбран", - "drop-file": "Перетащите JSON файл или кликните для выбора файла.", - "drop-file-csv": "Перетащите CSV файл или кликните для выбора файла.", - "column-value": "Значение", - "column-title": "Название", - "column-example": "Пример значений данных", - "column-key": "Ключ атрибута/телеметрии", - "csv-delimiter": "Разделитель в CSV файле", - "csv-first-line-header": "Первая строка содержит названия колонок", - "csv-update-data": "Обновить атрибут/телеметрию", - "import-csv-number-columns-error": "Файл должен содержать как минимум две колонки", - "import-csv-invalid-format-error": "Неверный формат данных. Строка: '{{line}}'", - "column-type": { - "name": "Название", - "type": "Тип", - "label": "Метка", - "column-type": "Тип колонки", - "client-attribute": "Клиентский атрибут", - "shared-attribute": "Общий атрибут", - "server-attribute": "Серверный атрибут", - "timeseries": "Телеметрия", - "entity-field": "Entity field", - "access-token": "Токен" - }, - "stepper-text": { - "select-file": "Выберите файл", - "configuration": "Конфигурация импорта", - "column-type": "Выберите тип колонок", - "creat-entities": "Создание новых объектов" - }, - "message": { - "create-entities": "{{count}} новый(х) объект(ов) было успешно создано.", - "update-entities": "{{count}} объект(ов) успешно обновлено.", - "error-entities": "Возникла ошибка при создании {{count}} объекта(ов)." - } - }, - "item": { - "selected": "Выбранные" - }, - "js-func": { - "no-return-error": "Функция должна возвращать значение!", - "return-type-mismatch": "Функция должна возвращать значение типа '{{type}}'!" - }, - "key-val": { - "key": "Ключ", - "value": "Значение", - "remove-entry": "Удалить элемент", - "add-entry": "Добавить элемент", - "no-data": "Элементы отсутствуют" - }, - "layout": { - "layout": "Макет", - "manage": "Управление макетами", - "settings": "Настройки макета", - "color": "Цвет", - "main": "Основной", - "right": "Правый", - "select": "Выбрать макет" - }, - "legend": { - "direction": "Расположение элементов легенды", - "position": "Расположение легенды", - "show-max": "Показать максимальное значение", - "show-min": "Показать минимальное значение", - "show-avg": "Показать среднее значение", - "show-total": "Показать сумму", - "settings": "Настройки легенды", - "min": "Мин", - "max": "Макс", - "avg": "Среднее", - "total": "Сумма", - "comparison-time-ago": { - "days": "(день назад)", - "weeks": "(неделю назад)", - "months": "(месяц назад)", - "years": "(год назад)" - } - }, - "login": { - "login": "Войти", - "request-password-reset": "Запрос на сброс пароля", - "reset-password": "Сбросить пароль", - "create-password": "Создать пароль", - "passwords-mismatch-error": "Введенные пароли должны быть одинаковыми!", - "password-again": "Введите пароль еще раз", - "sign-in": "Пожалуйста, войдите в систему", - "username": "Имя пользователя (эл. адрес)", - "remember-me": "Запомнить меня", - "forgot-password": "Забыли пароль?", - "password-reset": "Пароль сброшен", - "expired-password-reset-message": "Срок действия Вашего пароля закончился! Пожалуйста, создайте новый пароль.", - "new-password": "Новый пароль", - "new-password-again": "Повторите новый пароль", - "password-link-sent-message": "Ссылка для сброса пароля была успешно отправлена!", - "email": "Эл. адрес", - "login-with": "Войти через {{name}}", - "or": "или" - }, - "position": { - "top": "Верх", - "bottom": "Низ", - "left": "Левый край", - "right": "Правый край" - }, - "profile": { - "profile": "Профиль", - "last-login-time": "Время последнего входа в систему", - "change-password": "Изменить пароль", - "current-password": "Текущий пароль", - "copy-jwt-token": "Копировать JWT токен", - "tokenCopiedMessage": "JWT токен скопирован в буфер обмена", - "tokenCopiedWarnMessage": "JWT токен недействителен! Перезагрузите страницу." - }, - "relation": { - "relations": "Отношения", - "direction": "Направления", - "search-direction": { - "FROM": "От", - "TO": "К" - }, - "direction-type": { - "FROM": "от", - "TO": "к" - }, - "from-relations": "Исходящие отношения", - "to-relations": "Входящие отношения", - "selected-relations": "Выбрано { count, plural, =1 {1 отношение} few {# отношения} other {# отношений} }", - "type": "Тип", - "to-entity-type": "К типу объекта", - "to-entity-name": "К объекта", - "from-entity-type": "От типа объекта", - "from-entity-name": "От объекта", - "to-entity": "К объекту", - "from-entity": "От объекта", - "delete": "Удалить отношение", - "relation-type": "Тип отношения", - "relation-type-required": "Тип отношения обязателен.", - "any-relation-type": "Любой тип", - "add": "Добавить отношение", - "edit": "Редактировать отношение", - "delete-to-relation-title": "Вы точно хотите удалить отношение, идущее к объекту '{{entityName}}'?", - "delete-to-relation-text": "Внимание, после подтверждения объект '{{entityName}}' будет отвязан от текущего объекта.", - "delete-to-relations-title": "Вы точно хотите удалить { count, plural, =1 {1 отношение} few {# отношения} other {# отношений} }?", - "delete-to-relations-text": "Внимание, после подтверждения выбранные объекты будут отвязаны от текущего объекта.", - "delete-from-relation-title": "Вы точно хотите удалить отношение, идущее от объекта '{{entityName}}'?", - "delete-from-relation-text": "Внимание, после подтверждения текущий объект будет отвязан от объекта '{{entityName}}'.", - "delete-from-relations-title": "Вы точно хотите удалить { count, plural, =1 {1 отношение} few {# отношения} other {# отношений} }?", - "delete-from-relations-text": "Внимание, после подтверждения выбранные объекты будут отвязаны от соответствующих объектов.", - "remove-relation-filter": "Удалить фильтр отношений", - "add-relation-filter": "Добавить фильтр отношений", - "any-relation": "Любое отношение", - "relation-filters": "Фильтры отношений", - "additional-info": "Дополнительная информация (JSON)", - "invalid-additional-info": "Не удалось распознать JSON с дополнительной информацией." - }, - "rulechain": { - "rulechain": "Цепочка правил", - "rulechains": "Цепочки правил", - "root": "Корневая", - "delete": "Удалить цепочку правил", - "name": "Названия", - "name-required": "Название необходимо.", - "description": "Описание", - "add": "Добавить цепочку правил", - "set-root": "Сделать цепочку корневой", - "set-root-rulechain-title": "Вы точно хотите сделать цепочку правил '{{ruleChainName}}' корневой?", - "set-root-rulechain-text": "После подтверждения цепочка правил станет корневой и будет обрабатывать все входящие сообщения.", - "delete-rulechain-title": "Вы точно хотите удалить цепочку правил '{{ruleChainName}}'?", - "delete-rulechain-text": "Внимание, после подтверждения цепочка правил и все связанные с ней данные будут безвозвратно удалены.", - "delete-rulechains-title": "Вы точно хотите удалить { count, plural, =1 {1 цепочку правил} few {# цепочки правил} other {# цепочек правил} }?", - "delete-rulechains-action-title": "Удалить { count, plural, =1 {1 цепочку правил} few {# цепочки правил} other {# цепочек правил} }", - "delete-rulechains-text": "Внимание, после подтверждения выбранные цепочки правил и все связанные с ними данные будут безвозвратно удалены.", - "add-rulechain-text": "Добавить новую цепочку правил", - "no-rulechains-text": "Цепочки правил не найдены", - "rulechain-details": "Подробности о цепочке правил", - "details": "Подробности", - "events": "События", - "system": "Системная", - "import": "Импортировать цепочку правил", - "export": "Экспортировать цепочку правил", - "export-failed-error": "Не удалось экспортировать цепочку правил: {{error}}", - "create-new-rulechain": "Создать новую цепочку правил", - "rulechain-file": "Файл цепочки правил", - "invalid-rulechain-file-error": "Не удалось импортировать цепочку правил: неправильный формат.", - "copyId": "Копировать ИД цепочки правил", - "idCopiedMessage": "ИД цепочки правил скопирован в буфер обмена", - "select-rulechain": "Выбрать цепочку правил", - "no-rulechains-matching": "Цепочки правил, соответствующие '{{entity}}', не найдены.", - "rulechain-required": "Цепочка правил обязательна", - "management": "Управление цепочками правил", - "debug-mode": "Режим отладки" - }, - "rulenode": { - "details": "Подробности", - "events": "События", - "search": "Поиск правил", - "open-node-library": "Открыть библиотеку правил", - "add": "Добавить правило", - "name": "Название", - "name-required": "Название обязательно.", - "type": "Тип", - "delete": "Удалить правило", - "select-all-objects": "Выделить все правила и связи", - "deselect-all-objects": "Отменить выделение правил и связей", - "delete-selected-objects": "Удалить выделенные правила и связи", - "delete-selected": "Удалить выделенные", - "select-all": "Выделить всё", - "copy-selected": "Копировать выделенное", - "deselect-all": "Отменить выделение", - "rulenode-details": "Подробности о правиле", - "debug-mode": "Режим отладки", - "configuration": "Настройки", - "link": "Связь", - "link-details": "Подробности о связи правила", - "add-link": "Добавить связь", - "link-label": "Метка связи", - "link-label-required": "Метка связи обязателен.", - "custom-link-label": "Пользовательская метка связи", - "custom-link-label-required": "Пользовательская метка связи обязателен.", - "link-labels": "Метки связи", - "link-labels-required": "Метки связи обязательны.", - "no-link-labels-found": "Метки связи не найдены", - "no-link-label-matching": "Метка '{{label}}' не найдена.", - "create-new-link-label": "Создать новую!", - "type-filter": "Фильтр", - "type-filter-details": "Фильтр входящих сообщений с заданными условиями", - "type-enrichment": "Насыщение", - "type-enrichment-details": "Добавить данные в метадату сообщения", - "type-transformation": "Преобразование", - "type-transformation-details": "Изменить содержимое сообщение и его метадату", - "type-action": "Действие", - "type-action-details": "Выполнить заданное действие", - "type-external": "Сторонние", - "type-external-details": "Взаимодействовать со сторонними системами", - "type-rule-chain": "Цепочка правил", - "type-rule-chain-details": "Перенаправить входящее сообщение в другую цепочку правил", - "type-input": "Вход", - "type-input-details": "Логический вход цепочки правил перенаправляет входящие сообщения в следующее правило", - "type-unknown": "Неизвестный", - "type-unknown-details": "Неопределенное правило", - "directive-is-not-loaded": "Указанная директива конфигурации '{{directiveName}}' не доступна.", - "ui-resources-load-error": "Не удалось загрузить UI ресурсы.", - "invalid-target-rulechain": "Не удалось определить целевую цепочку правил!", - "test-script-function": "Протестировать скрипт", - "message": "Сообщение", - "message-type": "Тип сообщения", - "select-message-type": "Выбрать тип сообщения", - "message-type-required": "Тип сообщения обязателен", - "metadata": "Метаданные", - "metadata-required": "Метаданные объекта не могут быть пустыми.", - "output": "Выход", - "test": "Протестировать", - "help": "Помощь", - "reset-debug-mode": "Сбросить режим отладки во всех правилах" - }, - "queue": { - "select_name": "Выберите имя для Queue", - "name": "Имя для Queue", - "name_required": "Поле 'Имя для Queue' обязательно к заполнению!" - }, - "tenant": { - "tenant": "Владелец", - "tenants": "Владельцы", - "management": "Управление владельцами", - "add": "Добавить владельца", - "admins": "Администраторы", - "manage-tenant-admins": "Управление администраторами владельца", - "delete": "Удалить владельца", - "add-tenant-text": "Добавить нового владельца", - "no-tenants-text": "Владельцы не найдены", - "tenant-details": "Подробности об владельце", - "delete-tenant-title": "Вы точно хотите удалить владельца '{{tenantTitle}}'?", - "delete-tenant-text": "Внимание, после подтверждения владелец и все связанные с ним данные будут безвозвратно утеряны.", - "delete-tenants-title": "Вы точно хотите удалить { count, plural, =1 {1 владельца} other {# владельцев} }?", - "delete-tenants-action-title": "Удалить { count, plural, =1 {1 владельца} other {# владельцев} }", - "delete-tenants-text": "Внимание, после подтверждения выбранные Владельцы и все связанные с ними данные будут безвозвратно утеряны.", - "title": "Имя", - "title-required": "Имя обязательно.", - "description": "Описание", - "details": "Подробности", - "events": "События", - "copyId": "Копировать ИД владельца", - "idCopiedMessage": "ИД владельца скопирован в буфер обмена", - "select-tenant": "Выбрать владельца", - "no-tenants-matching": "Владельцы, соответствующие '{{entity}}', не найдены.", - "tenant-required": "Владелец обязателен" - }, - "timeinterval": { - "seconds-interval": "{ seconds, plural, =1 {1 секунда} few {# секунды} other {# секунд} }", - "minutes-interval": "{ minutes, plural, =1 {1 минута} few {# минуты} other {# минут} }", - "hours-interval": "{ hours, plural, =1 {1 час} few {# часа} other {# часов} }", - "days-interval": "{ days, plural, =1 {1 день} few {# дня} other {# дней} }", - "days": "Дни", - "hours": "Часы", - "minutes": "Минуты", - "seconds": "Секунды", - "advanced": "Дополнительно" - }, - "timewindow": { - "days": "{ days, plural, =1 {1 день} few {# дня} other {# дней} }", - "hours": "{ hours, plural, =1 {1 час} few {# часа} other {# часов} }", - "minutes": "{ minutes, plural, =1 {1 минута} few {# минуты} other {# минут} }", - "seconds": "{ seconds, plural, =1 {1 секунда} few {# секунды} other {# секунд} }", - "realtime": "Режим реального времени", - "history": "История", - "last-prefix": "Последние", - "period": "с {{ startTime }} до {{ endTime }}", - "edit": "Изменить временное окно", - "date-range": "Диапазон дат", - "last": "Последние", - "time-period": "Период времени", - "hide": "Скрыть" - }, - "user": { - "user": "Пользователь", - "users": "Пользователи", - "customer-users": "Пользователи клиента", - "tenant-admins": "Администраторы владельца", - "sys-admin": "Системный администратор", - "tenant-admin": "Администратор владельца", - "customer": "Клиент", - "anonymous": "Аноним", - "add": "Добавить пользователя", - "delete": "Удалить пользователя", - "add-user-text": "Добавить нового пользователя", - "no-users-text": "Пользователи не найдены", - "user-details": "Подробности о пользователе", - "delete-user-title": "Вы точно хотите удалить пользователя '{{userEmail}}'?", - "delete-user-text": "Внимание, после подтверждения пользователь и все связанные с ним данные будут безвозвратно утеряны.", - "delete-users-title": "Вы точно хотите удалить { count, plural, =1 {1 пользователя} other {# пользователей} }?", - "delete-users-action-title": "Удалить { count, plural, =1 {1 пользователя} other {# пользователей} }", - "delete-users-text": "Внимание, после подтверждения выбранные пользователи и все связанные с ними данные будут безвозвратно утеряны.", - "activation-email-sent-message": "Активационное письмо успешно отправлено!", - "resend-activation": "Повторить отправку активационного письма", - "email": "Эл. адрес", - "email-required": "Эл. адрес обязателен.", - "invalid-email-format": "Неправильный формат эл. адреса'.", - "first-name": "Имя", - "last-name": "Фамилия", - "description": "Описание", - "default-dashboard": "Дашборд по умолчанию", - "always-fullscreen": "Всегда в полноэкранном режиме", - "select-user": "Выбрать пользователя", - "no-users-matching": "Пользователи, соответствующие '{{entity}}', не найдены.", - "user-required": "Необходимо указать пользователя", - "activation-method": "Метод активации", - "display-activation-link": "Отобразить ссылку для активации", - "send-activation-mail": "Отправить активационное письмо", - "activation-link": "Активационная ссылка для пользователя", - "activation-link-text": "Для активации пользователя используйте ссылку :", - "copy-activation-link": "Копировать активационную ссылку", - "activation-link-copied-message": "Ссылка для активации пользователя скопирована в буфер обмена", - "details": "Подробности", - "login-as-tenant-admin": "Войти как администратор владельца", - "login-as-customer-user": "Войти как пользователь клиента", - "disable-account": "Отключить учетную запись пользователя", - "enable-account": "Включить учетную запись пользователя", - "enable-account-message": "Учетная запись пользователя была успешно включена!", - "disable-account-message": "Учетная запись пользователя была успешно отключена!", - "copyId": "Копировать ИД пользователя", - "idCopiedMessage": "ИД пользователя скопирован в буфер обмена" - }, - "value": { - "type": "Тип значения", - "string": "Строка", - "string-value": "Строковое значение", - "integer": "Целое число", - "integer-value": "Целочисленное значение", - "invalid-integer-value": "Неправильный формат целого числа", - "double": "Число двойной точности", - "double-value": "Значение двойной точности", - "boolean": "Логический тип", - "boolean-value": "Логическое значение", - "false": "Ложь", - "true": "Правда", - "long": "Целое число" - }, - "widget": { - "widget-library": "Галерея виджетов", - "widget-bundle": "Набор виджетов", - "select-widgets-bundle": "Выберите набор виджетов", - "management": "Управление виджетами", - "editor": "Редактор виджетов", - "widget-type-not-found": "Ошибка при загрузке конфигурации виджета.
Возможно, связанный с ней\n тип виджета уже удален.", - "widget-type-load-error": "Не удалось загрузить виджет по следующим причинам:", - "remove": "Удалить виджет", - "edit": "Редактировать виджет", - "remove-widget-title": "Вы точно хотите удалить виджет '{{widgetTitle}}'?", - "remove-widget-text": "Внимание, после подтверждения виджет и все связанные с ним данные будут безвозвратно утеряны.", - "timeseries": "Телеметрия", - "search-data": "Поиск данных", - "no-data-found": "Данные не найдено", - "latest": "Последние значения", - "rpc": "Управляющий виджет", - "alarm": "Виджет оповещений", - "static": "Статический виджет", - "select-widget-type": "Выберите тип виджета", - "missing-widget-title-error": "Укажите название виджета!", - "widget-saved": "Виджет сохранен", - "unable-to-save-widget-error": "Не удалось сохранить виджет! Виджет содержит ошибки!", - "save": "Сохранить виджет", - "saveAs": "Сохранить виджет как", - "save-widget-type-as": "Сохранить тип виджета как", - "save-widget-type-as-text": "Пожалуйста, введите название виджета и/или укажите целевой набор виджетов", - "toggle-fullscreen": "Во весь экран", - "run": "Запустить виджет", - "title": "Название виджета", - "title-required": "Название виджета обязательно.", - "type": "Тип виджета", - "resources": "Ресурсы", - "resource-url": "JavaScript/CSS URL", - "remove-resource": "Удалить ресурс", - "add-resource": "Добавить ресурс", - "html": "HTML", - "tidy": "Форматировать", - "css": "CSS", - "settings-schema": "Схема конфигурации", - "datakey-settings-schema": "Схема конфигурации ключа данных", - "javascript": "Javascript", - "add-widget-type": "Добавить новый тип виджета", - "widget-template-load-failed-error": "Не удалось загрузить шаблон виджета!", - "add": "Добавить виджет", - "undo": "Откатить изменения в виджете", - "export": "Экспортировать виджет" - }, - "widget-action": { - "header-button": "Кнопка заголовка виджета", - "open-dashboard-state": "Перейти к новому состоянию дашборда", - "update-dashboard-state": "Обновить текущее состояние дашборда", - "open-dashboard": "Перейти к другому дашборду", - "custom": "Пользовательское действие", - "custom-pretty": "Пользовательское действие (с HTML шаблоном)", - "target-dashboard-state": "Целевое состояние дашборда", - "target-dashboard-state-required": "Целевое состояние дашборда обязательно", - "set-entity-from-widget": "Установить объект из виджета", - "target-dashboard": "Целевой дашборд", - "open-right-layout": "Открыть мобильный режим дашборда" - }, - "widgets-bundle": { - "current": "Текущий набор", - "widgets-bundles": "Наборы виджетов", - "add": "Добавить набор виджетов", - "delete": "Удалить набор виджетов", - "title": "Название", - "title-required": "Название обязательно.", - "add-widgets-bundle-text": "Добавить новый набор виджетов", - "no-widgets-bundles-text": "Наборы виджетов не найдены", - "empty": "Пустой набор виджетов", - "details": "Подробности", - "widgets-bundle-details": "Подробности о наборе виджетов", - "delete-widgets-bundle-title": "Вы точно хотите удалить набор виджетов '{{widgetsBundleTitle}}'?", - "delete-widgets-bundle-text": "Внимание, после подтверждения набор виджетов и все связанные с ним данные будут безвозвратно утеряны.", - "delete-widgets-bundles-title": "Вы точно хотите удалить { count, plural, =1 {1 набор виджетов} few {# набора виджетов} other {# наборов виджетов} }?", - "delete-widgets-bundles-action-title": "Удалить { count, plural, =1 {1 набор виджетов} few {# набора виджетов} other {# наборов виджетов} }", - "delete-widgets-bundles-text": "Внимание, после подтверждения выбранные наборы виджетов и все связанные с ними данные будут безвозвратно утеряны..", - "no-widgets-bundles-matching": "Набор виджетов '{{widgetsBundle}}' не найден.", - "widgets-bundle-required": "Набор виджетов обязателен.", - "system": "Системный", - "import": "Импортировать набор виджетов", - "export": "Экспортировать набор виджетов", - "export-failed-error": "Не удалось экспортировать набор виджетов: {{error}}", - "create-new-widgets-bundle": "Создать новый набор виджетов", - "widgets-bundle-file": "Файл набора виджетов", - "invalid-widgets-bundle-file-error": "Не удалось импортировать набор виджетов: неизвестная схема данных набора виджетов." - }, - "widget-config": { - "data": "Данные", - "settings": "Настройки", - "advanced": "Дополнительно", - "title": "Название", - "general-settings": "Общие настройки", - "display-title": "Показать название на виджете", - "drop-shadow": "Тень", - "enable-fullscreen": "Во весь экран", - "background-color": "Цвет фона", - "text-color": "Цвет текста", - "padding": "Отступ", - "margin": "Margin", - "widget-style": "Стиль виджета", - "title-style": "Стиль названия", - "mobile-mode-settings": "Мобильный режим", - "order": "Порядок", - "height": "Высота", - "units": "Специальный символ после значения", - "decimals": "Количество цифр после запятой", - "timewindow": "Временное окно", - "use-dashboard-timewindow": "Использовать временное окно дашборда", - "display-timewindow": "Показывать временное окно", - "legend": "Легенда", - "display-legend": "Показать легенду", - "datasources": "Источники данных", - "maximum-datasources": "Максимальной количество источников данных равно {{count}}", - "datasource-type": "Тип", - "datasource-parameters": "Параметры", - "remove-datasource": "Удалить источник данных", - "add-datasource": "Добавить источник данных", - "target-device": "Целевое устройство", - "alarm-source": "Источник оповещения", - "actions": "Действия", - "action": "Действие", - "add-action": "Добавить действие", - "search-actions": "Поиск действий", - "action-source": "Источник действий", - "action-source-required": "Источник действий обязателен.", - "action-name": "Название", - "action-name-required": "Название действия обязательно.", - "action-name-not-unique": "Действие с таким именем уже существует.
Название должно быть уникально в рамках одного источника действий.", - "action-icon": "Иконка", - "action-type": "Тип", - "action-type-required": "Тип действий обязателен.", - "edit-action": "Редактировать действие", - "delete-action": "Удалить действие", - "delete-action-title": "Удалить действие виджета", - "delete-action-text": "Вы точно хотите удалить действие виджета '{{actionName}}'?", - "title-icon": "Иконка в названии виджета", - "display-icon": "Показывать иконку в названии виджета", - "icon-color": "Цвет иконки", - "icon-size": "Размер иконки", - "advanced-settings": "Расширенные настройки", - "data-settings": "Настройки данных", - "no-data-display-message": "\"Нет данных для отображения\" альтернативный текст" - }, - "widget-type": { - "import": "Импортировать тип виджета", - "export": "Экспортировать тип виджета", - "export-failed-error": "Не удалось экспортировать тип виджета: {{error}}", - "create-new-widget-type": "Создать новый тип виджета", - "widget-type-file": "Файл типа виджета", - "invalid-widget-type-file-error": "Не удалось импортировать виджет: неизвестная схема данных типа виджета." - }, - "widgets": { - "date-range-navigator": { - "localizationMap": { - "Sun": "Вс", - "Mon": "Пн", - "Tue": "Вт", - "Wed": "Ср", - "Thu": "Чт", - "Fri": "Пт", - "Sat": "Сб", - "Jan": "Янв.", - "Feb": "Февр.", - "Mar": "Март", - "Apr": "Апр.", - "May": "Май", - "Jun": "Июнь", - "Jul": "Июль", - "Aug": "Авг.", - "Sep": "Сент.", - "Oct": "Окт.", - "Nov": "Нояб.", - "Dec": "Дек.", - "January": "Январь", - "February": "Февраль", - "March": "Март", - "April": "Апрель", - "June": "Июнь", - "July": "Июль", - "August": "Август", - "September": "Сентябрь", - "October": "Октября", - "November": "Ноябрь", - "December": "Декабрь", - "Custom Date Range": "Пользовательский диапазон дат", - "Date Range Template": "Шаблон диапазона дат", - "Today": "Сегодня", - "Yesterday": "Вчера", - "This Week": "На этой неделе", - "Last Week": "Прошлая неделя", - "This Month": "Этот месяц", - "Last Month": "Прошлый месяц", - "Year": "Год", - "This Year": "В этом году", - "Last Year": "Прошлый год", - "Date picker": "Выбор даты", - "Hour": "Час", - "Day": "День", - "Week": "Неделю", - "2 weeks": "2 Недели", - "Month": "Месяц", - "3 months": "3 Месяца", - "6 months": "6 Месяцев", - "Custom interval": "Пользовательский интервал", - "Interval": "Интервал", - "Step size": "Размер шага", - "Ok": "Ok" - } - }, - "input-widgets": { - "attribute-not-allowed": "Атрибут не может быть выбран в этом виджете", - "date": "Дата", - "blocked-location": "Геолокация заблокирована в вашем браузере", - "claim-device": "Подтвердить устройство", - "claim-failed": "Не удалось подтвердить устройство!", - "claim-not-found": "Устройство не найдено!", - "claim-successful": "Устройство успешно подтверждено!", - "discard-changes": "Отменить изменения", - "device-name": "Название устройства", - "device-name-required": "Необходимо указать название устройства", - "entity-attribute-required": "Значение атрибута обязателено", - "entity-coordinate-required": "Необходимо указать широту и долготу", - "entity-timeseries-required": "Значение телеметрии обязательно", - "get-location": "Получить текущее местоположение", - "latitude": "Широта", - "longitude": "Долгота", - "not-allowed-entity": "Выбраный объект не имеет общих атрибутов", - "no-attribute-selected": "Атрибут не выбран", - "no-datakey-selected": "Ни один datakey не выбран", - "no-entity-selected": "Объект не выбран", - "no-coordinate-specified": "Ключ для широты/долготы не указан", - "no-support-geolocation": "Ваш браузер не поддерживает геолокацию", - "no-image": "Нет изображения", - "no-support-web-camera": "Нет поддерживаемой веб-камеры", - "no-timeseries-selected": "Параметр телеметрии не выбран", - "secret-key": "Секретный ключ", - "secret-key-required": "Необходимо указать секретный ключ", - "switch-attribute-value": "Изменить значение атрибута", - "switch-camera": "Изменить камеру", - "switch-timeseries-value": "Изменить значение телеметрии", - "take-photo": "Сделать фото", - "time": "Время", - "timeseries-not-allowed": "Телеметрия не может быть выбрана в этом виджете", - "update-failed": "Не удалось обновить", - "update-successful": "Успешно обновлено", - "update-attribute": "Обновить атрибут", - "update-timeseries": "Обновить телеметрию", - "value": "Значение" - }, - "persistent-table": { - "rpc-id": "RPC ID", - "message-type": "Тип сообщения", - "method": "Метод", - "params": "Параметры", - "created-time": "Время создания", - "expiration-time": "Время жизни", - "retries": "Повторные попытки", - "status": "Статус", - "filter": "Фильтр", - "refresh": "Обновить", - "add": "Добавить RPC запрос", - "details": "Детали", - "delete": "Удалить", - "delete-request-title": "Удалить RPC запрос", - "delete-request-text": "Вы точно хотите удалить RPC запрос?", - "details-title": "Детали RPC ID: ", - "additional-info": "Дополнительная информация", - "response": "Ответ", - "any-status": "Любой статус", - "rpc-status-list": "Список RPC статусов", - "no-request-prompt": "Запросы не найдены", - "send-request": "Отправить запрос", - "add-title": "Добавить новый RPC запрос", - "method-error": "Метод обязателен.", - "white-space-error": "Пробелы не допускаются.", - "rpc-status": { - "QUEUED": "В ОЧЕРЕДИ", - "SENT": "ОТПРАВЛЕННО", - "DELIVERED": "ДОСТАВЛЕННО", - "SUCCESSFUL": "УСПЕШНО", - "TIMEOUT": "ВРЕМЯ ИСТЕКЛО", - "EXPIRED": "ПРОСРОЧЕНО", - "FAILED": "НЕУДАЧНО" - }, - "rpc-search-status-all": "ВСЕ", - "message-types": { - "false": "Двусторонний", - "true": "Односторонний" - } - } - }, - "icon": { - "icon": "Иконка", - "select-icon": "Выбрать иконку", - "material-icons": "Иконки в стиле Material", - "show-all": "Показать все иконки" - }, - "custom": { - "widget-action": { - "action-cell-button": "Кнопка действия в ячейке таблицы", - "row-click": "Действий при щелчке на строку", - "marker-click": "Действия при щелчке на маркер", - "polygon-click": "Действия при щелчке на полигон", - "tooltip-tag-action": "Действие при нажатии на ссылку в подсказке", - "node-selected": "Действий при выборе ноды", - "element-click": "Действий при щелчке на HTML элементе", - "pie-slice-click": "Действий при щелчке на секции круговой диаграммы", - "row-double-click": "Действий при двойном щелчке на строку" - } - }, - "language": { - "language": "Язык" - } -} diff --git a/ui-ngx/src/assets/locale/locale.constant-tr_TR.json b/ui-ngx/src/assets/locale/locale.constant-tr_TR.json index e9be2e691a..b5b70cd8f9 100644 --- a/ui-ngx/src/assets/locale/locale.constant-tr_TR.json +++ b/ui-ngx/src/assets/locale/locale.constant-tr_TR.json @@ -2430,7 +2430,6 @@ "search": "Kural Ara", "selected-rulechains": "{ count, plural, =1 {1 kural} other {# kural} } seçildi", "open-rulechain": "Kuralı Aç", - "assign-new-rulechain": "Yeni kural zinciri atayın", "edge-template-root": "Şablon Kökü", "assign-to-edge": "Uca Ata", "edge-rulechain": "Uç kuralı zinciri", diff --git a/ui-ngx/src/assets/locale/locale.constant-uk_UA.json b/ui-ngx/src/assets/locale/locale.constant-uk_UA.json index da3b6ecaee..dce1bf0a2e 100644 --- a/ui-ngx/src/assets/locale/locale.constant-uk_UA.json +++ b/ui-ngx/src/assets/locale/locale.constant-uk_UA.json @@ -6,13 +6,20 @@ "access-forbidden": "Доступ заборонено", "access-forbidden-text": "Недостатньо прав для доступу!
Спробуйте увійти як інший користувач, якщо ви все ще хочете отримати доступ до цього ресурсу.", "refresh-token-expired": "Дані про сесію застарілі", - "refresh-token-failed": "Не вдається відновити сеанс" + "refresh-token-failed": "Не вдається відновити сеанс", + "permission-denied": "У дозволі відмовлено", + "permission-denied-text": "Ви не маєте дозволу на виконання цієї операції!" + }, + "account": { + "account": "Обліковий запис", + "notification-settings": "Налаштування сповіщень" }, "action": { "activate": "Активувати", "suspend": "Призупинити", "save": "Зберегти", "saveAs": "Зберегти як", + "move": "Перемістити", "cancel": "Скасувати", "ok": "OK", "delete": "Видалити", @@ -21,6 +28,7 @@ "no": "Ні", "update": "Оновити", "remove": "Видалити", + "select": "Вибрати", "search": "Пошук", "clear-search": "Очистити пошук", "assign": "Надати", @@ -32,6 +40,7 @@ "edit-mode": "Режим редагування", "enter-edit-mode": "Ввійти в режим редагування", "decline-changes": "Відхилити зміни", + "decline": "Відхилити", "close": "Закрити", "back": "Назад", "run": "Запустити", @@ -51,9 +60,27 @@ "share-via": "Поділитися через {{provider}}", "continue": "Продовжити", "discard-changes": "Скасувати зміни", - "move": "Перемістити", - "select": "Вибрати", - "done": "Завершено" + "download": "Завантажити", + "next": "Наступний", + "next-with-label": "Наступний: {{label}}", + "read-more": "Прочитати більше", + "hide": "Приховати", + "done": "Завершено", + "print": "Друкувати", + "restore": "Відновити", + "confirm": "Підтвердити", + "more": "Більше", + "less": "Менше", + "skip": "Пропустити", + "send": "Надіслати", + "reset": "Скидання", + "show-more": "Показати більше", + "dont-show-again": "Більше не показувати", + "see-documentation": "Див. документацію", + "clear": "Очистити", + "upload": "Надіслати", + "delete-anyway": "Все одно видалити", + "delete-selected": "Видалити вибране" }, "aggregation": { "aggregation": "Агрегація", @@ -68,6 +95,7 @@ "none": "Відсутня" }, "admin": { + "settings": "Налаштування", "general": "Загальне", "general-settings": "Загальні налаштування", "outgoing-mail": "Поштовий сервер", @@ -126,15 +154,15 @@ "minimum-max-failed-login-attempts-range": "Максимальна кількість невдалих спроб входу не може бути негативною", "user-lockout-notification-email": "У разі блокування облікового запису користувача, надішліть сповіщення на електронну пошту", "smpp-provider": { - "smpp-version": "SMPP верія", + "smpp-version": "SMPP верcія", "smpp-host": "SMPP хост", "smpp-host-required": "Хост SMPP обов'язковий.", "smpp-port": "SMPP порт", "smpp-port-required": "Порт SMPP обов'язковий.", "system-id": "Id системи", - "system-id-required": "Id системи обязателен.", + "system-id-required": "ID системи обов'язковий.", "password": "Пароль", - "password-required": "Пароль обязателен.", + "password-required": "Пароль обов'язковий.", "type-settings": "Налаштування типів", "source-settings": "Налаштування джерела", "destination-settings": "Налаштування призначення", @@ -144,12 +172,13 @@ "service-type": "Тип обслуговування", "source-address": "Адреса джерела", "source-ton": "Тип номера джерела", - "source-npi": "Идентификация плана нумерации джерела", + "source-npi": "Ідентифікація плану нумерації джерела", "destination-ton": "Тип номера призначення", "destination-npi": "Ідентифікація плану нумерації призначення", "address-range": "Діапазон адрес", "coding-scheme": "Схема кодування" - } + }, + "resources": "Ресурси" }, "alarm": { "alarm": "Сигнал тривоги", @@ -249,8 +278,8 @@ "filter-type": "Тип фільтра", "filter-type-required": "Необхідно вказати тип фільтра.", "entity-filter-no-entity-matched": "Не знайдено жодних сутностей, які відповідають вказаному фільтру.", - "no-entity-filter-specified": "Фільтр обїектів не вказано", - "root-state-entity": "Використовувати сутінсть стану як кореневу", + "no-entity-filter-specified": "Фільтр сутностей не вказано", + "root-state-entity": "Використовувати сутність стану як кореневу", "last-level-relation": "Використовувати лише відношення останнього рівня", "group-state-entity": "Використовувати групу сутностей стану як кореневу", "root-entity": "Коренева сутність", @@ -323,7 +352,7 @@ "copyId": "Копіювати Id активу", "idCopiedMessage": "Id активу був скопійований у буфер обміну", "select-asset": "Виберіть актив", - "no-assets-matching": "Не знайдено жодних активів, що відповідають'{{entity}}'.", + "no-assets-matching": "Не знайдено жодних активів, що відповідають '{{entity}}'.", "asset-required": "Необхідно задати актив", "name-starts-with": "Назва активу починається з", "selected-assets": "{ count, plural, =1 {1 актив} other {# активи} } selected", @@ -367,6 +396,9 @@ "selected-attributes": "{ count, plural, =1 {1 attribute} other {# attributes} } selected ...вибрані вибрати", "selected-telemetry": "{ count, plural, =1 {1 telemetry unit} other {# telemetry units} } selected" }, + "api-usage": { + "api-usage": "Використання API" + }, "audit-log": { "audit": "Операція", "audit-logs": "Журнал операцій", @@ -476,14 +508,14 @@ "test": "Тест", "metadata": "Метадані", "metadata-required": "Записи метаданих не можуть бути порожніми.", - "integration-metadata": "Метедані інтеграції", + "integration-metadata": "Метадані інтеграції", "integration-metadata-required": "Параметри метаданих інтеграції не можуть бути порожніми.", "output": "Вихідні дані", "import": "Імпорт перетворювача даних", "export": "Експорт перетворювача даних", "export-failed-error": "Неможливо експортувати перетворювач даних: {{помилка}}", "create-new-converter": "Створити новий перетворювач даних", - "converter-file": "Файл перетворювача даних(конвектер файл)", + "converter-file": "Файл перетворювача даних", "invalid-converter-file-error": "Неможливо імпортувати перетворювач даних: недійсна структура даних перетворювача.", "type": "Тип", "type-required": "Необхідно задати тип.", @@ -620,7 +652,7 @@ "unassign-dashboard-text": "Після підтвердження, клієнт буде позбавлений панелі приладів. Панель приладів і пов'язані з нею дані будуть недоступні клієнтові.", "unassign-dashboard": "Позбавити панелі приладів", "unassign-dashboards-title": "Ви впевнені, що хочете позбавити { count, plural, =1 {1 панелі приладів} other {# панелей приладів} }?", - "unassign-dashboards-text": "Після підтвердження, клієтн буде позбавлений усіх вибраних панелей приладів і даних, які з ними пов'язані.", + "unassign-dashboards-text": "Після підтвердження, клієнт буде позбавлений усіх вибраних панелей приладів і даних, які з ними пов'язані.", "public-dashboard-title": "Панель приладів тепер публічна", "public-dashboard-text": "Ваша панель приладів {{dashboardTitle}} тепер публічна і доступна іншим link:", "public-dashboard-notice": "Note: Не забудьте зробити спільні пристрої загальнодоступними, щоб отримати доступ до їхніх даних.", @@ -645,7 +677,7 @@ "settings": "Налаштування", "columns-count": "Кількість стовпців", "columns-count-required": "Необхідно вказати кількість стовпців.", - "min-columns-count-message": "Дозволений мінімум -10 стовпців.", + "min-columns-count-message": "Дозволений мінімум - 10 стовпців.", "max-columns-count-message": "Дозволений максимум - 1000 стовпців.", "widgets-margins": "Відступ між віджетами", "horizontal-margin": "Горизонтальний відступ", @@ -686,8 +718,8 @@ "widget-file": "Файл віджета", "invalid-widget-file-error": "Неможливо імпортувати віджет: неправильна структура даних віджета.", "widget-import-missing-aliases-title": "Налаштувати псевдоніми, що використовуються імпортованим віджетом", - "open-toolbar": "Відкрити панель інструменів ", - "close-toolbar": "Закрити панель інструменів", + "open-toolbar": "Відкрити панель інструментів", + "close-toolbar": "Закрити панель інструментів", "configuration-error": "Помилка конфігурації", "alias-resolution-error-title": "Помилка конфігурації псевдонімів панелі візуалізації", "invalid-aliases-config": "Неможливо знайти пристрої, які відповідають певному фільтру псевдонімів.
Зверніться до свого адміністратора, щоб вирішити цю проблему.", @@ -717,7 +749,7 @@ "show-details": "Показати деталі", "hide-details": "Приховати деталі", "select-state": "Виберіть цільовий стан", - "state-controller": "Контроллер стану" + "state-controller": "Контролер стану" }, "datakey": { "settings": "Налаштування", @@ -732,11 +764,11 @@ "timeseries": "Телеметрія", "attributes": "Атрибути", "entity-field": "Поле сутності", - "alarm": "Поля сигнала тривоги", + "alarm": "Поля сигналу тривоги", "timeseries-required": "Необхідно вказати Телеметрія.", "timeseries-or-attributes-required": "Необхідно вказати телеметрію/атрибути.", "maximum-timeseries-or-attributes": "Максимальні { count, plural, =1 {1 телеметрія/атрибут дозволені.} other {# телеметрія/атрибути дозволені} }", - "alarm-fields-required": "Необхідно вказати поля сигнала тривоги.", + "alarm-fields-required": "Необхідно вказати поля сигналу тривоги.", "function-types": "Типи функцій", "function-types-required": "Необхідно вказати типи функцій.", "maximum-function-types": "Maximum { count, plural, =1 {1 function type is allowed.} other {# function types are allowed} }", @@ -771,7 +803,7 @@ "no-keys-found": "Ключі не знайдено.", "create-new-alias": "Створити новий!", "create-new-key": "Створити новий!", - "duplicate-alias-error": "Псевдонім з таким іменем '{{alias}}' вже існює.
Псевдоніми пристроїв повинні бути унікальними на панелі візуалізації.", + "duplicate-alias-error": "Псевдонім з таким іменем '{{alias}}' вже існує.
Псевдоніми пристроїв повинні бути унікальними на панелі візуалізації.", "configure-alias": "Налаштувати псевдонім '{{alias}}'", "no-devices-matching": "Не знайдено жодних пристроїв, які відповідають '{{entity}}'.", "alias": "Псевдонім", @@ -861,6 +893,14 @@ "list-of-groups": "{ count, plural, =1 {Одна група пристроїв} other {Список # груп пристроїв} }", "group-name-starts-with": "Групи пристроїв, імена яких починаються з '{{prefix}}'" }, + "asset-profile": { + "asset-profile": "Профіль активу", + "asset-profiles": "Профілі активів" + }, + "device-profile": { + "device-profile": "Профіль пристрою", + "device-profiles": "Профілі пристроїв" + }, "dialog": { "close": "Закрити діалогове вікно" }, @@ -868,6 +908,11 @@ "column": "Колонка", "row": "Рядок" }, + "edge": { + "management": "Керування Edge", + "instances": "Інстанси", + "rulechain-templates": "Шаблони ланцюжків правил" + }, "error": { "unable-to-connect": "Неможливо підключитися до сервера! Перевірте підключення до Інтернету.", "unhandled-error-code": "Неопрацьований помилковий код: {{errorCode}}", @@ -879,7 +924,7 @@ "aliases": "Псевдоніми сутності", "entity-alias": "Псевдонім сутності", "unable-delete-entity-alias-title": "Неможливо видалити псевдонім сутності", - "unable-delete-entity-alias-text": "Псевдонім сутності'{{entityAlias}}' неможливо видалити, так як це використовується наступним віджетом(s):
{{widgetsList}}", + "unable-delete-entity-alias-text": "Псевдонім сутності '{{entityAlias}}' неможливо видалити, оскільки він використовується наступним віджетом(s):
{{widgetsList}}", "duplicate-alias-error": "Знайдено повторюваний псевдонім '{{alias}}'.
Псевдоніми сутностей повинні бути унікальними на панелі візуалізації.", "missing-entity-filter-error": "Відсутній фільтр для псевдоніма '{{alias}}'.", "configure-alias": "Налаштувати '{{alias}}' псевдонім", @@ -1118,9 +1163,9 @@ "view-entity-views": "Переглянути представлення сутностей", "entity-view-alias": "Псевдонім представлення сутності", "aliases": "Псевдоніми представлення сутності", - "no-alias-matching": "Псевдонім'{{alias}}' не знайдено.", + "no-alias-matching": "Псевдонім '{{alias}}' не знайдено.", "no-aliases-found": "Псевдоніми не знайдено.", - "no-key-matching": "'Ключ {{key}}' не знайдено.", + "no-key-matching": "Ключ '{{key}}' не знайдено.", "no-keys-found": "Ключі не знайдено.", "create-new-alias": "Створити новий!", "create-new-key": "Створити новий!", @@ -1135,7 +1180,7 @@ "entity-view-list": "Список представленнь сутності", "use-entity-view-name-filter": "Використати фільтр", "entity-view-list-empty": "Не вибрано жодного представлення сутності.", - "entity-view-name-filter-required": "Необхідно вказвти фільтр назв представлення сутності.", + "entity-view-name-filter-required": "Необхідно вказати фільтр назв представлення сутності.", "entity-view-name-filter-no-entity-view-matched": "Представлення сутностей, назви яких починаються з '{{entityView}}' не знайдено.", "add": "Додати представлення сутності", "assign-to-customer": "Призначити клієнту", @@ -1398,8 +1443,11 @@ "import-extension": "Імпортувати розширення", "export-extension": "Експортувати розширення", "file": "Файл розширень", - "invalid-file-error": "Не правильний формат файла" + "invalid-file-error": "Неправильний формат файлу" }, + "feature": { + "advanced-features": "Додаткові можливості" + }, "fullscreen": { "expand": "Відкрити у повноекранному режимі", "exit": "Вийти з повноекранного режиму", @@ -1410,7 +1458,7 @@ "function": "Функція" }, "grid": { - "delete-item-title": "Ви впенені, що хочете видалити цей елемент?", + "delete-item-title": "Ви впевнені, що хочете видалити цей елемент?", "delete-item-text": "Будьте обережні, після підтвердження, цей елемент і всі пов'язані з ним дані, стануть недоступними.", "delete-items-title": "Ви впенені, що хочете видалити { count, plural, =1 {1 елемент} other {# елементи} }?", "delete-items-action-title": "Видалити{ count, plural, =1 {1 елемент} other {# елементи} }", @@ -1695,6 +1743,12 @@ "login-with": "Увійти через {{name}}", "or": "або" }, + "notification": { + "notification-center": "Центр сповіщень" + }, + "ota-update": { + "ota-updates": "Оновлення OTA" + }, "position": { "top": "Угорі", "bottom": "Знизу", @@ -1710,6 +1764,12 @@ "tokenCopiedMessage": "JWT токен скопійовано в буфер обміну", "tokenCopiedWarnMessage": "JWT токен не є дійсним! Перезавантажте сторінку." }, + "profiles": { + "profiles": "Профілі" + }, + "security": { + "security": "Безпека" + }, "relation": { "relations": "Відношення", "direction": "Напрямок", @@ -1752,41 +1812,44 @@ "additional-info": "Додаткова інформація (JSON)", "invalid-additional-info": "Не вдалося розібрати JSON з додатковою інформацією ." }, + "resource": { + "resources-library": "Бібліотека ресурсів" + }, "rulechain": { - "rulechain": "Ланцюг правил", - "rulechains": "Ланцюги правил", + "rulechain": "Ланцюжок правил", + "rulechains": "Ланцюжки правил", "root": "Основний", - "delete": "Видалити ланцюг правил", + "delete": "Видалити ланцюжок правил", "name": "Ім'я", "name-required": "Необхідно вказати ім'я.", "description": "Опис", - "add": "Додати ланцюг правил", - "set-root": "Зробити ланцюг правил основним", - "set-root-rulechain-title": "Ви впевнені, що хочете зробити ланцюг правил '{{ruleChainName}}' основним?", - "set-root-rulechain-text": "Після підтвердження ланцюг правил стане основним і буде обробляти всі вхідні транспортні повідомлення.", - "delete-rulechain-title": "Ви впевнені, що хочете видалити ланцюг правил '{{ruleChainName}}'?", - "delete-rulechain-text": "Будьте обережні, після підтвердження ланцюг правил і всі пов'язані з ним дані стануть недоступними.", + "add": "Додати ланцюжок правил", + "set-root": "Зробити ланцюжок правил основним", + "set-root-rulechain-title": "Ви впевнені, що хочете зробити ланцюжок правил '{{ruleChainName}}' основним?", + "set-root-rulechain-text": "Після підтвердження ланцюжок правил стане основним і буде обробляти всі вхідні транспортні повідомлення.", + "delete-rulechain-title": "Ви впевнені, що хочете видалити ланцюжок правил '{{ruleChainName}}'?", + "delete-rulechain-text": "Будьте обережні, після підтвердження ланцюжок правил і всі пов'язані з ним дані стануть недоступними.", "delete-rulechains-title": "Ви впевнені, що хочете видалити { count, plural, =1 {1 ланцюг правил} other {# ланцюги правил} }?", "delete-rulechains-action-title": "Видалити{ count, plural, =1 {1 ланцюг правил} other {# ланцюги правил} }", - "delete-rulechains-text": "Будьте обережні, після підтвердження, вибрані ланцюги правил і всі пов'язані з ними дані стануть недоступними.", - "add-rulechain-text": "Додати новий ланцюг правил", - "no-rulechains-text": "Ланцюг правил не знайдено", - "rulechain-details": "Деталі ланцюга правил", + "delete-rulechains-text": "Будьте обережні, після підтвердження, вибрані ланцюжки правил і всі пов'язані з ними дані стануть недоступними.", + "add-rulechain-text": "Додати новий ланцюжок правил", + "no-rulechains-text": "Ланцюжок правил не знайдено", + "rulechain-details": "Деталі ланцюжка правил", "details": "Деталі", "events": "Події", "system": "Система", - "import": "Імпортувати ланцюг правил", - "export": "Експортувати ланцюг правил", - "export-failed-error": "Не вдалося експортувати ланцюг правил: {{error}}", - "create-new-rulechain": "Створити новий ланцюг правил", - "rulechain-file": "Файл ланцюга правил", - "invalid-rulechain-file-error": "Неможливо імпортувати ланцюг правил: недійсна структуру даних ланцюга правил.", - "copyId": "Копіювати Id ланцюга правил", - "idCopiedMessage": "Id ланцюга правил скопійовано в буфер обміну", - "select-rulechain": "Вибрати ланцюг правил", - "no-rulechains-matching": "Не знайдено жодних ланцюгів правил, які відповідають '{{entity}}'.", - "rulechain-required": "Необхідно вказати ланцюг правил", - "management": "Управління ланцюгами правил", + "import": "Імпортувати ланцюжок правил", + "export": "Експортувати ланцюжок правил", + "export-failed-error": "Не вдалося експортувати ланцюжок правил: {{error}}", + "create-new-rulechain": "Створити новий ланцюжок правил", + "rulechain-file": "Файл ланцюжка правил", + "invalid-rulechain-file-error": "Неможливо імпортувати ланцюжок правил: недійсна структуру даних ланцюжка правил.", + "copyId": "Копіювати Id ланцюжка правил", + "idCopiedMessage": "Id ланцюжка правил скопійовано в буфер обміну", + "select-rulechain": "Вибрати ланцюжок правил", + "no-rulechains-matching": "Не знайдено жодних ланцюжків правил, які відповідають '{{entity}}'.", + "rulechain-required": "Необхідно вказати ланцюжок правил", + "management": "Управління ланцюжками правил", "debug-mode": "Режим налагодження" }, "rulenode": { @@ -1820,7 +1883,7 @@ "link-labels": "Мітки посилання", "link-labels-required": "Необхідно вказати мітки посилання.", "no-link-labels-found": "Не знайдено жодних міток посилання", - "no-link-label-matching": "Мітка'{{label}}' не знайдена.", + "no-link-label-matching": "Мітку '{{label}}' не знайдено.", "create-new-link-label": "Створити нову!", "type-filter": "Фільтр", "type-filter-details": "Фільтрувати вхідні повідомлення з заданими умовами", @@ -1834,15 +1897,15 @@ "type-analytics-details": "Виконує аналіз потокових або збережених даних", "type-external": "Зовнішній", "type-external-details": "Взаємодіє з зовнішньою системою", - "type-rule-chain": "Ланцюг правил", - "type-rule-chain-details": "Перенаправити вхідне повідомлення на вказаний ланцюг правил", + "type-rule-chain": "Ланцюжок правил", + "type-rule-chain-details": "Перенаправити вхідне повідомлення на вказаний ланцюжок правил", "type-input": "Вхід", - "type-input-details": "Логічний вхід ланцюга правил, перенаправляє вхідні повідомлення на наступний пов'язаний вузол правил", + "type-input-details": "Логічний вхід ланцюжка правил, перенаправляє вхідні повідомлення на наступний пов'язаний вузол правил", "type-unknown": "Невідомий", "type-unknown-details": "Невизначений вузол правил", "directive-is-not-loaded": "Вказана директива конфігурації '{{directiveName}}' недоступна.", "ui-resources-load-error": "Не вдалося завантажити UI ресурси.", - "invalid-target-rulechain": "Не вдається визначити цільовий ланцюг правил!", + "invalid-target-rulechain": "Не вдається визначити цільовий ланцюжок правил!", "test-script-function": "Протестувати скрипт", "message": "Повідомлення", "message-type": "Тип повідомлення", @@ -1860,7 +1923,7 @@ "scheduler-event": "Подія планувальника", "select-scheduler-event": "Вибрати подію", "no-scheduler-events-matching": "Не знайдено жодних подій, які відповідають '{{entity}}'.", - "scheduler-event-required": "Необхвдно вказати заплановану подію", + "scheduler-event-required": "Необхідно вказати заплановану подію", "management": "Управління планувальником", "scheduler-events": "Планування подій", "add-scheduler-event": "Додати подію", @@ -1902,7 +1965,7 @@ "repeat-on-monday": "Повторити в понеділок", "repeat-on-tuesday": "Повторити у вівторок", "repeat-on-wednesday": "Повторити в середу", - "repeat-on-thursday": "Повторити в червер", + "repeat-on-thursday": "Повторити в четвер", "repeat-on-friday": "Повторити в п'ятницю", "repeat-on-saturday": "Повторити в суботу", "event-type": "Тип події", @@ -1915,7 +1978,7 @@ "week": "Тиждень", "day": "День", "agenda-week": "Порядок тижня", - "agenda-day": "Порялок дня", + "agenda-day": "Порядок дня", "list-year": "Список року", "list-month": "Список місяця", "list-week": "Список тижня", @@ -1994,7 +2057,7 @@ "download-blob-entity": "Завантажити файл", "delete-blob-entity": "Видалити файл", "delete-blob-entity-title": "Ви впевнені, що хочете видалити файл '{{blobEntityName}}'?", - "delete-blob-entity-text": "Будьте обережні, після підствердження, дані файлу стануть недоступними." + "delete-blob-entity-text": "Будьте обережні, після підтвердження, дані з файлу стануть недоступними для відновлення." }, "timezone": { "timezone": "Часовий пояс", @@ -2018,7 +2081,7 @@ "add-tenant-text": "Додати нового власника", "no-tenants-text": "Не знайдено жодного власника", "tenant-details": "Подробиці про власника", - "delete-tenant-title": "Ви впевнені, що хочете видалити власника'{{tenantTitle}}'?", + "delete-tenant-title": "Ви впевнені, що хочете видалити власника '{{tenantTitle}}'?", "delete-tenant-text": "Будьте обережні, після підтвердження власник і всі пов'язані з ним дані стануть недоступними.", "delete-tenants-title": "Ви впевнені, що хочете видалити { count, plural, =1 {1 власник} other {# власники} }?", "delete-tenants-action-title": "Видалити { count, plural, =1 {1 власник} other {# власники} }", @@ -2076,7 +2139,7 @@ "add-user-text": "Додати нового користувача", "no-users-text": "Не знайдено жодного користувача", "user-details": "Подробиці про користувача", - "delete-user-title": "Ви впевнені, що хочете видалити користувача'{{userEmail}}'?", + "delete-user-title": "Ви впевнені, що хочете видалити користувача '{{userEmail}}'?", "delete-user-text": "Будьте обережні, після підтвердження, користувач і всі пов'язані з ним дані стануть недоступними.", "delete-users-title": "Ви впевнені, що хочете видалити { count, plural, =1 {1 користувача} other {# користувачів} }?", "delete-users-action-title": "Видалити { count, plural, =1 {1 користувача} other {# користувачів} }", @@ -2128,6 +2191,9 @@ "true": "Правдиве", "long": "Довге" }, + "version-control": { + "version-control": "Керування версіями" + }, "widget": { "widget-library": "Бібліотека віджетів", "widget-bundle": "Пакет віджетів", @@ -2145,7 +2211,7 @@ "no-data-found": "Даних не знайдено", "latest": "Останні значення", "rpc": "Керуючий віджет", - "alarm": "Віджет сигнала тривоги", + "alarm": "Віджет сигналу тривоги", "static": "Статичний віджет", "select-widget-type": "Вибрати тип віджета", "missing-widget-title-error": "Необхідно вказати назву віджета!", @@ -2252,7 +2318,7 @@ "remove-datasource": "Видалити джерело даних", "add-datasource": "Додати джерело даних", "target-device": "Цільовий пристрій", - "alarm-source": "Джерело сигнала тривоги", + "alarm-source": "Джерело сигналу тривоги", "actions": "Дії", "action": "Дія", "add-action": "Додати дію", @@ -2367,7 +2433,7 @@ "no-coordinate-specified": "Ключ для широти/довготи не вказаний", "no-support-geolocation": "Ваш браузер не підтримує геолокацію", "no-image": "Немає зображення", - "no-support-web-camera": "Нет поддерживаемой веб-камеры", + "no-support-web-camera": "Немає підтримуваної веб-камери", "no-timeseries-selected": "Параметр телеметрії не вибрано", "secret-key": "Секретний ключ", "secret-key-required": "Необхідно вказати секретний ключ", @@ -2412,10 +2478,10 @@ "rpc-status": { "QUEUED": "В ЧЕРЗІ", "SENT": "ВІДПРАВЛЕНО", - "DELIVERED": "ДОСТАВЛЕННО", + "DELIVERED": "ДОСТАВЛЕНО", "SUCCESSFUL": "УСПІШНО", "TIMEOUT": "ЧАС МИНУВ", - "EXPIRED": "ПРОСРОЧЕНО", + "EXPIRED": "ПРОТЕРМІНОВАНО", "FAILED": "НЕ ВДАЛО" }, "rpc-search-status-all": "ВСІ", @@ -2426,7 +2492,7 @@ } }, "white-labeling": { - "white-labeling": "Білий маркування", + "white-labeling": "Біле маркування", "login-white-labeling": "Login White Labeling", "preview": "Попередній перегляд", "app-title": "Назва програми", @@ -2441,7 +2507,7 @@ "logo-size-error": "Зображення логотипу занадто велике. Максимально дозволений розмір зображення логотипу{{kbSize}} KBytes.", "logo-type-error": "Недійсний формат файлу логотипу. Приймаються тільки зображення.", "drop-logo-image": "Зніміть зображення логотипу або клацніть, щоб вибрати файл для завантаження.", - "no-logo-image": "Не вибрано жожного логотипу", + "no-logo-image": "Не вибрано жодного логотипу", "logo-height": "Висота логотипу, px", "primary-palette": "Основна палітра", "accent-palette": "Палітра акцент", diff --git a/ui-ngx/src/assets/locale/locale.constant-zh_CN.json b/ui-ngx/src/assets/locale/locale.constant-zh_CN.json index 2c241a1c44..28c4d20f59 100644 --- a/ui-ngx/src/assets/locale/locale.constant-zh_CN.json +++ b/ui-ngx/src/assets/locale/locale.constant-zh_CN.json @@ -10,11 +10,16 @@ "permission-denied": "权限被拒绝", "permission-denied-text": "您没有执行此操作的权限!" }, + "account": { + "account": "账号", + "notification-settings": "通知设置" + }, "action": { "activate": "激活", "suspend": "暂停", "save": "保存", "saveAs": "另存为", + "move": "移动", "cancel": "取消", "ok": "确定", "delete": "删除", @@ -35,6 +40,7 @@ "edit-mode": "编辑模式", "enter-edit-mode": "进入编辑模式", "decline-changes": "撤销更改", + "decline": "撤销", "close": "关闭", "back": "后退", "run": "运行", @@ -66,7 +72,12 @@ "more": "更多", "less": "更少", "skip": "跳过", - "send": "发送" + "send": "发送", + "reset": "重置", + "show-more": "显示更多", + "dont-show-again": "不再显示", + "see-documentation": "查看文档", + "clear": "清除" }, "aggregation": { "aggregation": "聚合", @@ -94,6 +105,23 @@ "base-url-required": "基本URL必填。", "prohibit-different-url": "禁止从客户端请求头中使用主机名", "prohibit-different-url-hint": "应为生产环境启用此设置。禁用时可能会导致安全问题", + "device-connectivity": { + "device-connectivity": "设备连接", + "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": "如果主机或端口字段为空,将使用默认的协议值。", + "host": "主机", + "port": "端口", + "port-pattern": "端口必须是正整数。", + "port-range": "端口应在1到65535的范围内。" + }, "mail-from": "邮件来自", "mail-from-required": "邮件发件人必填。", "smtp-protocol": "SMTP协议", @@ -173,6 +201,7 @@ "domain-name-unique": "域名和协议必须是唯一的。", "domain-name-max-length": "域名应该少于256个字符。", "error-verification-url": "域名不应包含符号 “/” 和 “:”。例:thingsboard.io", + "connection-settings": "连接设置", "oauth2": { "access-token-uri": "访问令牌URI", "access-token-uri-required": "访问令牌 URI 必填。", @@ -263,7 +292,28 @@ "platform-android": "Android", "platform-ios": "iOS", "all-platforms": "所有平台", - "allowed-platforms": "允许平台" + "smtp-provider": "SMTP提供商", + "allowed-platforms": "允许的平台", + "authentication": "身份验证", + "basic": "基本", + "provider": "提供商", + "redirect-url": "重定向URL", + "domain-name": "域名", + "redirect-url-template": "重定向URL模板", + "microsoft-tenant-id": "目录(租户)ID", + "microsoft-tenant-id-required": "需要目录(租户)ID", + "token-uri": "令牌URI", + "token-uri-required": "需要令牌URI", + "redirect-uri": "重定向URI", + "google-provider": "谷歌", + "microsoft-provider": "Office 365", + "sendgrid-provider": "Sendgrid", + "custom-provider": "自定义", + "generate-access-token": "生成访问令牌", + "update-access-token": "更新访问令牌", + "access-token-status": "访问令牌状态:", + "token-status-generated": "已生成", + "token-status-not-generated": "未生成" }, "smpp-provider": { "smpp-version": "SMPP版本", @@ -481,6 +531,7 @@ "severity-indeterminate": "不确定", "acknowledge": "应答", "clear": "清除", + "delete": "删除", "search": "查找告警", "selected-alarms": "已选择 { count, plural, =1 {1 个告警} other {# 个告警} }", "no-data": "无数据显示", @@ -491,10 +542,14 @@ "aknowledge-alarms-text": "确定要确认 { count, plural, =1 {1 个告警} other {# 个告警} }吗?", "aknowledge-alarm-title": "确认告警", "aknowledge-alarm-text": "确定要确认告警吗?", + "selected-alarms-are-acknowledged": "所选的告警已经被确认", "clear-alarms-title": "清除 { count, plural, =1 {1 个告警} other {# 个告警} }", "clear-alarms-text": "确定要清除 { count, plural, =1 {1 个告警} other {# 个告警} }?", - "clear-alarm-title": "清除警报", - "clear-alarm-text": "确定要清除警报吗?", + "clear-alarm-title": "清除告警", + "clear-alarm-text": "确定要清除告警吗?", + "delete-alarms-title": "删除 { count, plural, =1 {1 个告警} other {# 个告警} }", + "delete-alarms-text": "您确定要删除 { count, plural, =1 {1 个告警} other {# 个告警} } 吗?", + "selected-alarms-are-cleared": "所选的告警已清除", "alarm-status-filter": "告警状态筛选器", "alarm-filter-title": "告警筛选器", "assigned": "已分配", @@ -512,7 +567,11 @@ "search-propagated-alarms": "检索已传递的警报", "comments": "告警评论", "show-more": "显示更多", - "additional-info": "附加信息" + "additional-info": "附加信息", + "alarm-type": "告警类型", + "enter-alarm-type": "输入告警类型", + "no-alarm-types-matching": "找不到与 '{{entitySubtype}}' 相匹配的告警类型。", + "alarm-type-list-empty": "未选择告警类型。" }, "alarm-activity": { "add": "添加评论", @@ -666,6 +725,7 @@ "attribute": { "attributes": "属性", "latest-telemetry": "最新遥测数据", + "no-latest-telemetry": "没有最新的遥测数据", "attributes-scope": "设备属性范围", "scope-telemetry": "遥测", "scope-latest-telemetry": "最新遥测数据", @@ -679,6 +739,8 @@ "key-required": "属性键必填。", "value": "数值", "value-required": "属性值必填。", + "telemetry-key-required": "需要遥测键", + "telemetry-value-required": "需要遥测数值", "delete-attributes-title": "确定要删除 { count, plural, =1 {1 个属性} other {# 个属性} }吗?", "delete-attributes-text": "注意,确认后所有选中的属性都会被删除。", "delete-attributes": "删除属性", @@ -694,7 +756,19 @@ "no-attributes-text": "未找到属性", "no-telemetry-text": "未找到遥测数据", "copy-key": "复制键", - "copy-value": "复制值" + "add-telemetry": "添加遥测数据", + "copy-value": "复制数值", + "delete-timeseries": { + "start-time": "开始时间", + "ends-on": "结束时间", + "strategy": "策略", + "delete-strategy": "删除策略", + "all-data": "删除所有数据", + "all-data-except-latest-value": "删除除最新值外的所有数据", + "latest-value": "删除最新值", + "all-data-for-time-period": "删除指定时间段的所有数据", + "rewrite-latest-value": "重写最新值" + } }, "api-usage": { "api-features": "Api统计", @@ -713,8 +787,14 @@ "email-messages-monthly-activity": "每月产生的邮件消息", "exceptions": "异常", "executions": "执行数", + "scripts": "Scripts", + "scripts-hourly-activity": "脚本每小时活动", + "scripts-daily-activity": "脚本每日活动", + "scripts-monthly-activity": "脚本每月活动", "javascript": "JavaScript", "javascript-executions": "JavaScript 执行数", + "tbel": "TBEL", + "tbel-executions": "TBEL 执行数", "latest-error": "最新错误", "messages": "消息", "notifications": "通知", @@ -753,6 +833,18 @@ "view-details": "查看详细信息", "view-statistics": "查看统计信息" }, + "api-limit": { + "cassandra-queries": "Cassandra查询次数", + "entity-version-creation": "实体版本创建次数", + "entity-version-load": "实体版本加载次数", + "notification-requests": "通知请求次数", + "notification-requests-per-rule": "每个规则的通知请求次数", + "rest-api-requests": "REST API请求次数", + "rest-api-requests-per-customer": "每个客户的REST API请求次数", + "transport-messages": "传输消息次数", + "transport-messages-per-device": "每个设备的传输消息次数", + "ws-updates-per-session": "每个会话的WS更新次数" + }, "audit-log": { "audit": "审计", "audit-logs": "审计日志", @@ -804,7 +896,8 @@ "type-provision-success": "设备已预配置", "type-provision-failure": "设备预配置失败", "type-timeseries-updated": "遥测数据已更新", - "type-timeseries-deleted": "遥测数据已删除" + "type-timeseries-deleted": "遥测数据已删除", + "type-sms-sent": "短信发送" }, "confirm-on-exit": { "message": "有未保存的更改,确定要离开此页吗?", @@ -835,7 +928,9 @@ "created-time": "创建时间", "loading": "正在加载中...", "proceed": "继续", - "open-details-page": "打开详情页" + "open-details-page": "打开详情页", + "not-found": "未找到", + "documentation": "文档" }, "content-type": { "json": "Json", @@ -898,6 +993,13 @@ "edges": "客户边缘实例", "manage-edges": "管理边缘" }, + "date": { + "last-update-n-ago": "N分钟前的最后更新", + "last-update-n-ago-text": "最后更新{{ agoText }}", + "custom-date": "自定义日期", + "format": "格式", + "preview": "预览" + }, "datetime": { "date-from": "开始日期", "time-from": "开始时间", @@ -927,6 +1029,7 @@ "no-dashboards-text": "未找到仪表板", "no-widgets": "没有配置部件", "add-widget": "添加部件", + "add-widget-button-text": "添加部件", "title": "标题", "image": "仪表板图片", "mobile-app-settings": "移动端应用设置", @@ -973,7 +1076,7 @@ "no-dashboards-matching": "未找到匹配 '{{entity}}' 的仪表板。", "dashboard-required": "仪表板必填。", "select-existing": "选择现有仪表板", - "create-new": "创建新的仪表板", + "create-new": "创建仪表板", "new-dashboard-title": "新仪表板标题", "open-dashboard": "打开仪表板", "set-background": "设置背景", @@ -1030,11 +1133,11 @@ "import": "导入仪表板", "export": "导出仪表板", "export-failed-error": "无法导出仪表板: {{error}}", - "create-new-dashboard": "创建新的仪表板", + "create-new-dashboard": "创建仪表板", "dashboard-file": "仪表板文件", "invalid-dashboard-file-error": "无法导入仪表板: 仪表板数据结构无效。", "dashboard-import-missing-aliases-title": "配置导入仪表板使用的别名", - "create-new-widget": "创建新部件", + "create-new-widget": "创建部件", "import-widget": "导入部件", "widget-file": "部件文件", "invalid-widget-file-error": "无法导入窗口部件: 窗口部件数据结构无效。", @@ -1055,6 +1158,7 @@ "public-link-copied-message": "仪表板的公共链接已被复制到剪贴板", "manage-states": "仪表板状态管理", "states": "仪表板状态", + "states-short": "状态", "search-states": "仪表板状态检索", "selected-states": "已选择 { count, plural, =1 {1 个仪表板状态} other {# 个仪表板状态} }", "edit-state": "仪表板状态编辑", @@ -1083,11 +1187,14 @@ "unassign-dashboards-from-edge-text": "确认后,所有选定的仪表板将被取消分配,边缘将无法访问。", "assign-dashboard-to-edge": "将仪表板分配给边缘", "assign-dashboard-to-edge-text": "请选择要分配给边缘的仪表板", - "non-existent-dashboard-state-error": "找不到ID为 \"{{ stateId }}\" 的仪表板状态。" + "non-existent-dashboard-state-error": "找不到ID为 '{{ stateId }}' 的仪表板状态。", + "edit-mode": "编辑模式" }, "datakey": { "settings": "设置", + "general": "常规", "advanced": "高级", + "key": "键", "label": "标签", "color": "颜色", "units": "单位符号", @@ -1107,6 +1214,10 @@ "function-types": "函数类型", "function-type": "函数类型", "function-types-required": "函数类型必填。", + "data-keys": "数据键", + "data-key": "数据键", + "data-keys-required": "数据键是必须的。", + "data-key-required": "数据键是必须的。", "alarm-keys": "告警数据键", "alarm-key": "告警数据键", "alarm-key-functions": "告警数据键函数", @@ -1139,7 +1250,13 @@ "delta-calculation-result": "增量计算结果", "delta-calculation-result-previous-value": "上个值", "delta-calculation-result-delta-absolute": "绝对值", - "delta-calculation-result-delta-percent": "百分比" + "delta-calculation-result-delta-percent": "百分比", + "source": "来源", + "latest": "最新", + "latest-value": "最新值", + "delta": "增量", + "percent": "百分比", + "absolute": "绝对值" }, "datasource": { "type": "数据源类型", @@ -1166,8 +1283,8 @@ "no-aliases-found": "未找到别名。", "no-key-matching": "'{{key}}' 未找到。", "no-keys-found": "未找到密钥。", - "create-new-alias": "创建一个新的!", - "create-new-key": "创建一个新的!", + "create-new-alias": "创建别名", + "create-new-key": "创建键", "duplicate-alias-error": "找到重复别名 '{{alias}}'。
设备别名必须是唯一的。", "configure-alias": "配置 '{{alias}}' 别名", "no-devices-matching": "未找到与 '{{entity}}' 匹配的设备。", @@ -1273,7 +1390,7 @@ "client-id-pattern": "包含无效字符。", "user-name": "用户名", "user-name-required": "用户名必填。", - "client-id-or-user-name-necessary": "客户端ID和/或用户名是必需的", + "client-id-or-user-name-necessary": "客户端ID或用户名是必需的", "password": "密码", "secret": "密钥", "secret-required": "密钥必填", @@ -1284,6 +1401,7 @@ "any-device": "任意设备", "no-device-types-matching": "未找到匹配 '{{entitySubtype}}' 的设备类型。", "device-type-list-empty": "未选择设备类型", + "device-profile-type-list-empty": "至少应选择一个设备配置。", "device-types": "设备类型", "name": "名称", "name-required": "名称必填。", @@ -1325,7 +1443,25 @@ "device-details": "设备详细信息" }, "unassign-devices-from-edge-title": "确定要取消分配 { count, plural, =1 {1 个设备} other {# 个设备} } 吗?", - "unassign-devices-from-edge-text": "确认后,设备将被取消分配,边缘将无法访问。" + "unassign-devices-from-edge-text": "确认后,设备将被取消分配,边缘将无法访问。", + "time": "时间", + "connectivity": { + "check-connectivity": "检查连通性", + "device-created-check-connectivity": "设备已创建,检查连通性!", + "loading-check-connectivity-command": "正在加载检查连通性命令...", + "use-following-instructions": "请使用以下说明代表设备发送遥测数据", + "execute-following-command": "执行以下命令", + "install-curl-windows": "从 Windows 10 b17063 开始,cURL 已默认安装", + "install-curl-macos": "从 Mac OS X 10.2 6C115(Jaguar)开始,cURL 已默认安装", + "install-mqtt-windows": "使用说明下载、安装、设置和运行 mosquitto_pub", + "install-coap-client": "使用说明下载、安装、设置和运行 coap-client", + "install-necessary-client-tools": "安装必要的客户端工具", + "mqtts-x509-command": "使用以下文档通过 MQTT 连接带有 X509 授权的设备", + "coaps-x509-command": "使用以下文档通过基于 DTLS 的 CoAP 连接带有 X509 授权的设备", + "snmp-command": "使用以下文档通过 SNMP 连接设备。", + "sparkplug-command": "使用以下文档通过 MQTT Sparkplug 连接设备。", + "lwm2m-command": "使用以下文档通过 LWM2M 连接设备。" + } }, "asset-profile": { "asset-profile": "资产配置", @@ -1364,12 +1500,12 @@ "set-default-asset-profile-title": "确定要将 '{{assetProfileName}}' 设为默认资产配置吗?", "set-default-asset-profile-text": "确认后,资产配置将被标记为默认,并将用于未指定配置的新资产。", "no-asset-profiles-found": "未不到资产配置。", - "create-new-asset-profile": "创建一个新的!", + "create-new-asset-profile": "创建资产配置", "create-asset-profile": "创建资产配置", "import": "导入资产配置", "export": "导出资产配置", "export-failed-error": "无法导出资产配置: {{error}}", - "asset-profile-file": "资产配置文件", + "asset-profile-file": "资产配置", "invalid-asset-profile-file-error": "无法导入资产配置:无效的资产配置数据结构。" }, "device-profile": { @@ -1389,8 +1525,6 @@ "delete": "删除设备配置", "copyId": "复制设备配置 ID", "name-max-length": "名称长度必须少于256个字符", - "new-device-profile-name": "设备配置名称", - "new-device-profile-name-required": "设备配置名称必填。", "name": "名称", "name-required": "名称是必需的。", "type": "配置类型", @@ -1409,6 +1543,7 @@ "transport-type-lwm2m-hint": "LWM2M传输类型", "transport-type-snmp": "SNMP", "transport-type-snmp-hint": "指定 SNMP 传输配置", + "transport-type-http": "HTTP", "description": "说明", "default": "默认", "profile-configuration": "配置", @@ -1426,7 +1561,7 @@ "set-default-device-profile-title": "确定要将设备配置 '{{deviceProfileName}}' 设为默认值吗?", "set-default-device-profile-text": "确认后,设备配置将被标记为默认,并将用于未指定配置的新设备。", "no-device-profiles-found": "未找到设备配置。", - "create-new-device-profile": "创建一个新的!", + "create-new-device-profile": "创建设备配置", "mqtt-device-topic-filters": "MQTT 设备 Topic 筛选器", "mqtt-device-topic-filters-unique": "MQTT设备 Topic 筛选器必须唯一。", "mqtt-device-topic-filters-spark-plug": "MQTT Sparkplug B边缘网络(EoN)节点", @@ -1507,6 +1642,9 @@ "condition-duration-value-required": "持续时间值必填。", "condition-duration-time-unit-required": "时间单位必填。", "advanced-settings": "高级设置", + "alarm-rule-additional-info": "附加信息", + "edit-alarm-rule-additional-info": "编辑附加信息", + "alarm-rule-additional-info-placeholder": "请在此处提供评论和调整,以便在附加信息下的告警详情中显示", "alarm-rule-additional-info-hint": "提示: 使用 ${keyName} 来替代告警规则条件中使用的属性或遥测键的值。", "alarm-rule-mobile-dashboard": "移动端仪表板", "alarm-rule-mobile-dashboard-hint": "作为移动端告警详情仪表板使用。", @@ -1523,7 +1661,7 @@ "provision-strategy": "预配置策略", "provision-strategy-required": "预配置策略必填。", "provision-strategy-disabled": "禁用", - "provision-strategy-created-new": "允许创建新设备", + "provision-strategy-created-new": "允许创建设备", "provision-strategy-check-pre-provisioned": "检查预配置的设备", "provision-device-key": "预配置设备密钥名", "provision-device-key-required": "预配置设备密钥名必填。", @@ -1536,8 +1674,8 @@ "provision-strategy-x509": { "certificate-chain": "X509 证书链", "certificate-chain-hint": "X.509 证书策略用于通过客户端证书在双向TLS通信中提供设备的方式。", - "allow-create-new-devices": "创建新设备", - "allow-create-new-devices-hint": "如果选择创建新设备,则将客户端证书用作设备凭据。", + "allow-create-new-devices": "创建设备", + "allow-create-new-devices-hint": "如果选择创建设备,则将客户端证书用作设备凭据。", "certificate-value": "PEM 格式的证书", "certificate-value-required": "PEM 格式的证书必填。", "cn-regex-variable": "CN 正则表达式变量", @@ -1582,8 +1720,8 @@ "create-device-profile": "创建设备配置", "import": "导入设备配置", "export": "导出设备配置", - "export-failed-error": "无法导出设备配置文件: {{error}}", - "device-profile-file": "设备配置文件", + "export-failed-error": "无法导出设备配置: {{error}}", + "device-profile-file": "设备配置", "invalid-device-profile-file-error": "无法导入设备配置:无效的设备配置数据结构。", "power-saving-mode": "节能模式", "power-saving-mode-type": { @@ -1692,7 +1830,7 @@ "account-after-timeout-required": "帐户超时必填。", "account-after-timeout-pattern": "帐户超时必须是一个正整数。", "account-after-timeout-tooltip": "Bootstrap-Server帐户资源的超时值。", - "server-type": "Server type", + "server-type": "服务器类型", "add-new-server-title": "添加新的服务器配置", "add-server-config": "添加服务器配置", "add-lwm2m-server-config": "添加LwM2M服务器", @@ -1840,6 +1978,8 @@ "make-private-edge-text": "确认后,边缘及其所有数据将被设为私有,不被其他人访问。", "import": "导入边缘", "install-connect-instructions": "安装和连接说明", + "install-connect-instructions-edge-created": "边缘已创建!请检查安装和连接说明", + "loading-edge-instructions": "正在加载边缘说明...", "label": "标签", "load-entity-error": "加载数据失败,实体已经被删除。", "assign-new-edge": "分配新边缘", @@ -1891,11 +2031,15 @@ "type-rule-chain-metadata": "规则链元数据", "type-edge": "边缘", "type-user": "用户", + "type-tenant": "租户", + "type-tenant-profile": "租户配置", "type-customer": "客户", "type-relation": "关联", "type-widgets-bundle": "部件包", "type-widgets-type": "部件类型", "type-admin-settings": "管理员设置", + "type-ota-package": "OTA包", + "type-queue": "队列", "action-type-added": "增加", "action-type-deleted": "删除", "action-type-updated": "更新", @@ -1911,6 +2055,8 @@ "action-type-rpc-call": "RPC调用", "action-type-alarm-ack": "告警确认", "action-type-alarm-clear": "告警清除", + "action-type-alarm-assigned": "告警已分配", + "action-type-alarm-unassigned": "告警未分配", "action-type-assigned-to-edge": "分配给边缘", "action-type-unassigned-from-edge": "取消分配边缘", "action-type-credentials-request": "认证请求", @@ -1927,6 +2073,7 @@ "entities-count": "实体数量", "alarms-count": "告警数量", "aliases": "实体别名", + "aliases-short": "别名", "entity-alias": "实体别名", "unable-delete-entity-alias-title": "无法删除实体别名", "unable-delete-entity-alias-text": "实体别名 '{{entityAlias}}' 被以下部件使用不能删除:
{{widgetsList}}", @@ -1942,6 +2089,7 @@ "entity-types": "实体类型", "entity-type-list": "实体类型列表", "any-entity": "任意实体", + "add-entity-type": "添加实体类型", "enter-entity-type": "输入实体类型", "no-entities-matching": "未找到匹配 '{{entity}}' 的实体。", "no-entity-types-matching": "未找到匹配 '{{entityType}}' 类型的实体。", @@ -1949,18 +2097,20 @@ "help-text": "根据需要可以使用'%'进行匹配,例如:'%entity_name_contains%', '%entity_name_ends', 'entity_starts_with'。", "use-entity-name-filter": "用户筛选器", "entity-list-empty": "没有选择实体。", + "entity-type-list-required": "至少应选择一个实体类型。", "entity-name-filter-required": "实体名筛选器必填。", "entity-name-filter-no-entity-matched": "未找到以 '{{entity}}' 开头的实体", "all-subtypes": "全部", "select-entities": "选择实体", "no-aliases-found": "未找到别名", "no-alias-matching": "未找到 '{{alias}}'", - "create-new-alias": "创建一个新的!", + "create-new-alias": "创建别名", + "create-new": "创建", "key": "键名", "key-name": "键名", "no-keys-found": "未找到键名", "no-key-matching": "未找到键名 '{{key}}'", - "create-new-key": "创建一个新的!", + "create-new-key": "创建键", "type": "类型", "type-required": "实体类型必填。", "type-device": "设备", @@ -1969,6 +2119,7 @@ "device-name-starts-with": "以 '{{prefix}}' 开头的设备", "type-device-profile": "设备配置", "type-device-profiles": "设备配置", + "clear-selected-profiles": "清除已选择的配置", "list-of-device-profiles": "{ count, plural, =1 {1 个设备配置} other {# 个设备配置} }", "device-profile-name-starts-with": "名称以 '{{prefix}}' 开头的设备配置", "type-asset-profile": "资产配置", @@ -2030,6 +2181,9 @@ "type-widgets-bundle": "部件包", "type-widgets-bundles": "部件包", "list-of-widgets-bundles": "{ count, plural, =1 {1 个部件包} other {# 个部件包} }", + "type-widget": "部件", + "type-widgets": "部件", + "list-of-widgets": "{ count, plural, =1 {1 个部件} other {# 个部件} }", "search": "实体检索", "selected-entities": "已选择 { count, plural, =1 {1 个实体} other {# 个实体} }", "entity-name": "实体名", @@ -2049,9 +2203,15 @@ "type-queue": "队列", "type-notification": "通知", "type-notification-rule": "通知规则", + "type-notification-rules": "通知规则", + "list-of-notification-rules": "{ count, plural, =1 {1 个通知规则} other {# 个通知规则} }", "type-notification-target": "通知收件人", + "type-notification-targets": "通知接收者", + "list-of-notification-targets": "{ count, plural, =1 {1 个通知接收者} other {# 个通知接收者} }", "type-notification-request": "通知请求", - "type-notification-template": "通知模板" + "type-notification-template": "通知模板", + "type-notification-templates": "通知模板", + "list-of-notification-templates": "{ count, plural, =1 {1 个通知模板} other {# 个通知模板} }" }, "entity-field": { "created-time": "创建时间", @@ -2082,8 +2242,8 @@ "no-aliases-found": "未找到别名。", "no-key-matching": "'{{key}}' 未找到。", "no-keys-found": "未找到密钥。", - "create-new-alias": "创建一个新的!", - "create-new-key": "创建一个新的!", + "create-new-alias": "创建别名", + "create-new-key": "创建键", "duplicate-alias-error": "找到重复别名 '{{alias}}'。
实体视图别名必须是唯一的。", "configure-alias": "配置 '{{alias}}' 别名", "no-entity-views-matching": "未找到与 '{{entity}}' 匹配的实体视图。", @@ -2410,6 +2570,7 @@ "add-filter-prompt": "请添加筛选器", "no-filter-matching": "未找到 '{{filter}}' 。", "create-new-filter": "请新增!", + "create-new": "创建", "filter-required": "筛选器必填。", "operation": { "operation": "操作", @@ -2454,7 +2615,10 @@ "attribute": "属性", "timeseries": "Timeseries", "entity-field": "实体", - "constant": "常量" + "constant": "常量", + "client-attribute": "客户端属性", + "server-attribute": "服务端属性", + "shared-attribute": "共享属性" }, "value-type": { "value-type": "值类型", @@ -2497,6 +2661,11 @@ }, "gateway": { "add-entry": "添加配置", + "advanced": "高级", + "checking-device-activity": "检查设备活动", + "command": "Docker命令", + "command-copied-message": "Docker命令已复制到剪贴板", + "configuration": "配置", "connector-add": "添加连接器", "connector-enabled": "启用连接器", "connector-name": "连接器名称", @@ -2504,31 +2673,140 @@ "connector-type": "连接器类型", "connector-type-required": "连接器类型必填。", "connectors": "连接器配置", - "create-new-gateway": "创建新网关", + "connectors-config": "连接器配置", + "connectors-table-enabled": "已启用", + "connectors-table-name": "名称", + "connectors-table-type": "类型", + "connectors-table-status": "状态", + "connectors-table-actions": "操作", + "connectors-table-key": "键", + "connectors-table-class": "类", + "rpc-command-send": "发送", + "rpc-command-result": "结果", + "rpc-command-edit-params": "编辑参数", + "gateway-configuration": "通用配置", + "create-new-gateway": "创建网关", "create-new-gateway-text": "确定要创建名为 '{{gatewayName}}' 的新网关?", + "created-time": "创建时间", + "configuration-delete-dialog-header": "配置将被删除", + "configuration-delete-dialog-body": "只有对网关进行物理访问时,才有可能关闭远程配置。所有先前的配置都将被删除。

\n要关闭配置,请在下面输入网关名称", + "configuration-delete-dialog-input": "网关名称", + "configuration-delete-dialog-input-required": "网关名称是必需的", + "configuration-delete-dialog-confirm": "关闭", "delete": "删除配置", "download-tip": "下载配置", + "drop-file": "将文件拖放到此处或", "gateway": "网关", "gateway-exists": "同名设备已存在。", "gateway-name": "网关名称", "gateway-name-required": "网关名称必填。", "gateway-saved": "已成功保存网关配置。", + "grpc": "GRPC", + "grpc-keep-alive-timeout": "保持连接超时(毫秒)", + "grpc-keep-alive-timeout-required": "需要保持连接超时", + "grpc-keep-alive-timeout-min": "保持连接超时不能小于1", + "grpc-keep-alive-timeout-pattern": "保持连接超时无效", + "grpc-keep-alive": "保持连接(毫秒)", + "grpc-keep-alive-required": "需要保持连接", + "grpc-keep-alive-min": "保持连接不能小于1", + "grpc-keep-alive-pattern": "保持连接无效", + "grpc-min-time-between-pings": "最小Ping间隔(毫秒)", + "grpc-min-time-between-pings-required": "需要最小Ping间隔", + "grpc-min-time-between-pings-min": "最小Ping间隔不能小于1", + "grpc-min-time-between-pings-pattern": "最小Ping间隔无效", + "grpc-min-ping-interval-without-data": "无数据时的最小Ping间隔(毫秒)", + "grpc-min-ping-interval-without-data-required": "需要无数据时的最小Ping间隔", + "grpc-min-ping-interval-without-data-min": "无数据时的最小Ping间隔不能小于1", + "grpc-min-ping-interval-without-data-pattern": "无数据时的最小Ping间隔无效", + "grpc-max-pings-without-data": "无数据时的最大Ping数", + "grpc-max-pings-without-data-required": "需要无数据时的最大Ping数", + "grpc-max-pings-without-data-min": "无数据时的最大Ping数不能小于1", + "grpc-max-pings-without-data-pattern": "无数据时的最大Ping数无效", + "inactivity-check-period-seconds": "不活跃检查期(秒)", + "inactivity-check-period-seconds-required": "需要不活跃检查期", + "inactivity-check-period-seconds-min": "不活跃检查期不能小于1", + "inactivity-check-period-seconds-pattern": "不活跃检查期无效", + "inactivity-timeout-seconds": "不活跃超时(秒)", + "inactivity-timeout-seconds-required": "需要不活跃超时", + "inactivity-timeout-seconds-min": "不活跃超时不能小于1", + "inactivity-timeout-seconds-pattern": "不活跃超时无效", "json-parse": "无效的JSON。", "json-required": "字段不能为空。", + "logs": { + "logs": "日志", + "days": "天", + "hours": "小时", + "minutes": "分钟", + "seconds": "秒", + "date-format": "日期格式", + "date-format-required": "需要日期格式", + "log-format": "日志格式", + "log-type": "日志类型", + "log-format-required": "需要日志格式", + "remote": "远程日志记录", + "remote-logs": "远程日志", + "local": "本地日志记录", + "level": "日志级别", + "file-path": "文件路径", + "file-path-required": "需要文件路径", + "saving-period": "日志保存期限", + "saving-period-min": "日志保存期限不能小于1", + "saving-period-required": "需要日志保存期限", + "backup-count": "备份数量", + "backup-count-min": "备份数量不能小于1", + "backup-count-required": "需要备份数量" + }, + "min-pack-send-delay": "最小包发送延迟(毫秒)", + "min-pack-send-delay-required": "最小包发送延迟是必需的", + "min-pack-send-delay-min": "最小包发送延迟不能小于0", "no-connectors": "无连接器", "no-data": "没有配置", "no-gateway-found": "未找到网关。", "no-gateway-matching": "未找到 '{{item}}' 。", "path-logs": "日志文件的路径", "path-logs-required": "路径是必需的。", + "permit-without-calls": "保持连接许可,无需响应", "remote": "远程配置", "remote-logging-level": "日志记录级别", "remove-entry": "删除配置", + "remote-shell": "远程Shell", + "remote-configuration": "远程配置", + "other": "其他", "save-tip": "保存配置", "security-type": "安全类型", "security-types": { "access-token": "访问令牌", - "tls": "TLS" + "username-password": "用户名和密码", + "tls": "TLS", + "tls-access-token": "TLS + 访问令牌", + "tls-private-key": "TLS + 私钥" + }, + "server-port": "服务器端口", + "statistics": { + "statistic": "统计信息", + "statistics": "统计信息", + "statistic-commands-empty": "无可用统计信息", + "commands": "命令", + "send-period": "统计信息发送周期(秒)", + "send-period-required": "统计信息发送周期是必需的", + "send-period-min": "统计信息发送周期不能小于60", + "send-period-pattern": "统计信息发送周期无效", + "check-connectors-configuration": "检查连接器配置(秒)", + "check-connectors-configuration-required": "检查连接器配置是必需的", + "check-connectors-configuration-min": "检查连接器配置不能小于1", + "check-connectors-configuration-pattern": "检查连接器配置无效", + "add": "添加命令", + "timeout": "超时时间", + "timeout-ms": "超时时间(毫秒)", + "timeout-required": "超时时间是必需的", + "timeout-min": "超时时间不能小于1", + "timeout-pattern": "超时时间无效", + "attribute-name": "属性名称", + "attribute-name-required": "属性名称是必需的", + "command": "命令", + "command-required": "命令是必需的", + "command-pattern": "命令无效", + "remove": "删除命令" }, "storage": "存储", "storage-max-file-records": "文件中的最大记录数", @@ -2540,6 +2818,16 @@ "storage-max-records-min": "最小记录数为1。", "storage-max-records-pattern": "数字无效。", "storage-max-records-required": "最大记录项必填。", + "storage-read-record-count": "存储中的读取记录数", + "storage-read-record-count-min": "最小记录数为1。", + "storage-read-record-count-pattern": "数字不合法。", + "storage-read-record-count-required": "需要读取记录数。", + "storage-max-read-record-count": "存储中的最大读取记录数", + "storage-max-read-record-count-min": "最小记录数为1。", + "storage-max-read-record-count-pattern": "数字不合法。", + "storage-max-read-record-count-required": "最大读取记录数必需。", + "storage-data-folder-path": "数据文件夹路径", + "storage-data-folder-path-required": "需要数据文件夹路径。", "storage-pack-size": "最大事件包大小", "storage-pack-size-min": "最小值为1。", "storage-pack-size-pattern": "数字无效。", @@ -2549,9 +2837,11 @@ "storage-type": "存储类型", "storage-types": { "file-storage": "文件存储", - "memory-storage": "内存存储" + "memory-storage": "内存存储", + "sqlite": "SQLITE" }, "thingsboard": "ThingsBoard", + "general": "常规", "thingsboard-host": "ThingsBoard主机", "thingsboard-host-required": "主机必填。", "thingsboard-port": "ThingsBoard端口", @@ -2564,10 +2854,61 @@ "title-connectors-json": "连接器 {{typeName}} 配置", "tls-path-ca-certificate": "网关上CA证书的路径", "tls-path-client-certificate": "网关上客户端证书的路径", + "messages-ttl-check-in-hours": "消息TTL检查小时数", + "messages-ttl-check-in-hours-required": "需要提供消息TTL检查小时数。", + "messages-ttl-check-in-hours-min": "最小值为1。", + "messages-ttl-check-in-hours-pattern": "数字无效。", + "messages-ttl-in-days": "消息TTL天数", + "messages-ttl-in-days-required": "需要提供消息TTL天数。", + "messages-ttl-in-days-min": "最小值为1。", + "messages-ttl-in-days-pattern": "数字无效。", + "mqtt-qos": "QoS", + "mqtt-qos-required": "需要提供QoS", + "mqtt-qos-range": "QoS值的范围是从0到1", "tls-path-private-key": "网关上私钥的路径", "toggle-fullscreen": "切换全屏", "transformer-json-config": "配置JSON*", - "update-config": "添加/更新配置JSON" + "update-config": "添加/更新配置JSON", + "hints": { + "remote-configuration": "启用对网关的远程配置和管理", + "remote-shell": "通过远程Shell小部件启用对网关操作系统的远程控制", + "host": "ThingsBoard 主机名或IP地址", + "port": "ThingsBoard MQTT服务端口", + "token": "ThingsBoard 网关访问令牌", + "client-id": "ThingsBoard 网关MQTT客户端ID", + "username": "ThingsBoard 网关MQTT用户名", + "password": "ThingsBoard 网关MQTT密码", + "ca-cert": "CA证书文件的路径", + "date-form": "日志消息中的日期格式", + "data-folder": "包含数据的文件夹的路径(相对或绝对路径)", + "log-format": "日志消息格式", + "remote-log": "启用对网关的远程日志记录和日志读取", + "backup-count": "如果备份计数大于0,则在执行轮换时,最多保留备份计数个文件-最旧的文件将被删除", + "storage": "提供将数据发送到平台之前保存传入数据的配置", + "max-file-count": "将创建的文件的最大数量", + "max-read-count": "从存储中获取的消息计数并发送到ThingsBoard", + "max-records": "一个文件中存储的最大记录数", + "read-record-count": "从存储中获取的消息计数并发送到ThingsBoard", + "max-records-count": "在将数据发送到ThingsBoard之前,存储中的最大数据计数", + "ttl-check-hour": "网关多久检查一次数据是否过时", + "ttl-messages-day": "存储将保存数据的最大天数", + "commands": "用于收集附加统计信息的命令", + "attribute": "统计遥测键", + "timeout": "命令执行的超时时间", + "command": "命令执行的结果,将用作遥测的值", + "check-device-activity": "启用监视每个连接设备的活动", + "inactivity-timeout": "在此时间后,网关将断开设备的连接", + "inactivity-period": "设备活动检查的周期", + "minimal-pack-delay": "发送消息包之间的延迟(减小此设置会导致增加CPU使用率)", + "qos": "MQTT消息传递的服务质量(0-至多一次,1-至少一次)", + "server-port": "GRPC服务器侦听传入连接的网络端口", + "grpc-keep-alive-timeout": "在考虑连接死亡之前,服务器等待keepalive ping响应的最长时间", + "grpc-keep-alive": "没有活动RPC调用时两个连续keepalive ping消息之间的持续时间", + "grpc-min-time-between-pings": "服务器在发送keepalive ping消息之间应等待的最小时间量", + "grpc-max-pings-without-data": "在没有接收到任何数据之前,服务器可以发送的keepalive ping消息的最大数量,然后将连接视为死亡", + "grpc-min-ping-interval-without-data": "在没有发送或接收数据时,服务器在发送keepalive ping消息之间应等待的最小时间量", + "permit-without-calls": "允许服务器在没有活动RPC调用时保持GRPC连接活动" + } }, "grid": { "delete-item-title": "确定要删除此项吗?", @@ -2599,8 +2940,10 @@ "browse-files": "浏览文件" }, "image-input": { - "drop-image-or": "拖放一张图片或者", "drop-images-or": "拖放一张或多张图片", + "drag-and-drop": "拖放", + "or": "或", + "browse": "浏览", "no-images": "未选择任何图片", "images": "图片" }, @@ -2651,6 +2994,12 @@ "lwm2m-server-secret-key": "LwM2M server证书密钥", "lwm2m-server-public-key-id": "LwM2M server公钥" }, + "snmp": { + "host": "SNMP 主机地址", + "port": "SNMP 端口", + "version": "SNMP 版本 (例如:v1, v2c, 或 v3)", + "community-string": "SNMP 团体字符串" + }, "isgateway": "是否网关", "activity-time-from-gateway-device": "来自网关设备的活动时间", "description": "说明", @@ -2661,7 +3010,7 @@ "select-file": "选择一个文件", "configuration": "导入配置", "column-type": "选择列类型", - "creat-entities": "创建新实体" + "creat-entities": "创建实体" }, "message": { "create-entities": "{{count}} 个新实体已成功创建。", @@ -2687,6 +3036,7 @@ }, "layout": { "layout": "布局", + "layouts": "布局", "manage": "布局管理", "settings": "布局设置", "color": "颜色", @@ -2712,6 +3062,12 @@ "legend": { "direction": "图例方向", "position": "图例位置", + "show-values": "显示数值", + "min-option": "最小值", + "max-option": "最大值", + "average-option": "平均值", + "total-option": "总数", + "latest-option": "最新值", "sort-legend": "在图例中排序数据键", "show-max": "显示最大值", "show-min": "显示最小值", @@ -2731,7 +3087,9 @@ "weeks": "(一周前)", "months": "(一个月前)", "years": "(一年前)" - } + }, + "label": "标签", + "value": "值" }, "login": { "login": "登录", @@ -2746,7 +3104,7 @@ "remember-me": "记住我", "forgot-password": "忘记密码?", "password-reset": "密码重置", - "expired-password-reset-message": "您的凭据已过期!请创建新密码。", + "expired-password-reset-message": "您的凭据已过期!请创建密码。", "new-password": "新密码", "new-password-again": "再次输入新密码", "password-link-sent-message": "密码重置链接已成功发送!", @@ -2793,6 +3151,7 @@ "api-feature-hint": "如果字段为空,则触发器将应用于所有API功能", "api-usage-trigger-settings": "API使用触发设置", "new-platform-version-trigger-settings": "新平台版本触发设置", + "rate-limits-trigger-settings": "超出速率限制触发设置", "at-least-one-should-be-selected": "至少需要选择一个", "basic-settings": "基本设置", "button-text": "按钮文本", @@ -2833,6 +3192,8 @@ "email-preview": "Email 通知预览", "slack": "Slack", "slack-preview": "Slack 通知预览", + "microsoft-teams" : "Microsoft Teams", + "microsoft-teams-preview" : "Microsoft Teams 通知预览", "sms": "SMS", "sms-preview": "SMS 通知预览", "web": "Web", @@ -2870,6 +3231,7 @@ "dashboard": "打开仪表板", "link": "打开URL链接" }, + "loading-notifications": "加载通知中…", "management": "通知管理", "mark-all-as-read": "全部标记为已读", "mark-as-read": "标记为已读", @@ -2910,20 +3272,20 @@ "only-rule-chain-lifecycle-failures": "仅在规则链生命周期故障时通知", "only-rule-node-lifecycle-failures": "仅在规则节点生命周期故障时通知", "platform-users": "平台用户", + "rate-limits": "速率限制", + "rate-limits-hint": "如果该字段为空,则触发器将应用于所有速率限制", "recipient": "收件人", "recipient-group": "收件人组", "recipient-type": { "affected-tenant-administrators": "受影响的租户管理员", "affected-user": "受影响的用户", - "affected-user-hint": "受影响用户的提示", "all-users": "所有用户", "customer-users": "客户用户", "system-administrators": "系统管理员", "tenant-administrators": "租户管理员", "user-filters": "用户筛选器", "user-list": "用户列表", - "users-entity-owner": "实体所有者的用户", - "users-entity-owner-hint": "实体所有者用户的提示" + "users-entity-owner": "实体所有者的用户" }, "recipients": "收件人", "notification-recipients": "通知 / 收件人", @@ -2943,6 +3305,8 @@ "rule-engine-filter": "规则引擎筛选器", "rule-name": "规则名称", "rule-name-required": "名称必填。", + "rule-disable": "禁用通知规则", + "rule-enable": "启用通知规则", "rule-node-filter": "规则节点筛选器", "rules": "规则", "notification-rules": "通知 / 规则", @@ -2986,13 +3350,15 @@ "general": "通用", "rule-engine-lifecycle-event": "规则引擎生命周期事件", "rule-node": "规则节点", - "new-platform-version": "新的平台版本" + "new-platform-version": "新的平台版本", + "rate-limits": "超过速率限制" }, "templates": "模板", "notification-templates": "通知 / 模板", - "tenant-profiles-list-rule-hint": "如果字段为空,触发器将应用于所有租户配置文件", + "tenant-profiles-list-rule-hint": "如果字段为空,触发器将应用于所有租户配置", "tenants-list-rule-hint": "如果字段为空,触发器将应用于所有租户", "threshold": "阈值", + "theme-color": "主题颜色", "time": "时间", "track-rule-node-events": "追踪规则节点事件", "trigger": { @@ -3005,6 +3371,7 @@ "entity-action": "实体操作", "rule-engine-lifecycle-event": "规则引擎生命周期事件", "new-platform-version": "新的平台版本", + "rate-limits": "超过速率限制", "trigger": "触发器", "trigger-required": "触发器必填。" }, @@ -3013,7 +3380,21 @@ "updated": "已更新", "use-template": "使用模板", "view-all": "查看全部", - "warning": "警告" + "warning": "警告", + "webhook-url": "Webhook URL", + "webhook-url-required": "需要填写Webhook URL", + "channel-name": "频道名称", + "channel-name-required": "需要填写频道名称", + "settings": { + "notification-settings": "通知设置", + "reset-all": "重置全部设置", + "reset-all-title": "您确定要将表单重置吗?", + "reset-all-text": "确认后,设置表单将重置为默认值并保存。", + "type": "类型", + "enable-all": "全部启用", + "disable-all": "全部禁用", + "delivery-not-configured": "未配置传递方式" + } }, "ota-update": { "add": "添加包", @@ -3028,7 +3409,7 @@ "checksum-copied-message": "包校验和已复制到剪贴板", "change-firmware": "固件的更改可能会导致 { count, plural, =1 {1 个设备} other {# 个设备} } 的更新。", "change-software": "软件的更改可能会导致 { count, plural, =1 {1 个设备} other {# 个设备} } 的更新。", - "chose-compatible-device-profile": "上传的包仅适用于具有所选配置文件的设备。", + "chose-compatible-device-profile": "上传的包仅适用于具有所选配置的设备。", "chose-firmware-distributed-device": "选择将分发到设备的固件", "chose-software-distributed-device": "选择将分发到设备的软件", "content-type": "内容类型", @@ -3103,6 +3484,13 @@ "security": { "security": "安全", "general-settings": "通用安全设置", + "access-token": "访问令牌", + "access-token-required": "需要访问令牌", + "clientId": "客户端ID", + "clientId-required": "需要客户端ID", + "username": "用户名", + "username-required": "需要用户名", + "ca-cert": "CA证书", "2fa": { "2fa": "双因素认证", "2fa-description": "双因素认证可保护您的帐户免受未经授权的访问。在登录时必须输入安全验证码。", @@ -3175,6 +3563,7 @@ "relation": { "relations": "关联", "direction": "方向", + "clear-relation-type": "清除关系类型", "search-direction": { "FROM": "从", "TO": "到" @@ -3209,6 +3598,7 @@ "delete-from-relations-title": "确定删除 { count, plural, =1 {1 个关联} other {# 个关联} } 吗?", "delete-from-relations-text": "确定删除所有选择的关联关系后,当前实体将与对应的实体取消关联", "remove-relation-filter": "移除关联筛选器", + "remove-filter": "移除过滤器", "add-relation-filter": "添加关联筛选器", "any-relation": "任意关联", "relation-filters": "关联筛选器", @@ -3218,6 +3608,7 @@ }, "resource": { "add": "添加资源", + "all-types": "全部", "copyId": "复制资源ID", "delete": "删除资源", "delete-resource-text": "请注意:确认后,资源将不可恢复。", @@ -3243,7 +3634,13 @@ "system": "系统", "title": "标题", "title-required": "标题是必填项。", - "title-max-length": "标题长度应该少于256个字符。" + "title-max-length": "标题长度应该少于256个字符。", + "type": { + "jks": "JKS", + "js-module": "JS 模块", + "lwm2m-model": "LWM2M 模型", + "pkcs-12": "PKCS #12" + } }, "rulechain": { "rulechain": "规则链", @@ -3273,7 +3670,7 @@ "import": "导入规则链", "export": "导出规则链", "export-failed-error": "无法导出规则链:{{error}}", - "create-new-rulechain": "创建新的规则链", + "create-new-rulechain": "创建规则链", "rulechain-file": "规则链文件", "invalid-rulechain-file-error": "不能导入规则链:无效的规则链数据格式。", "copyId": "复制规则链ID", @@ -3286,7 +3683,6 @@ "search": "查找规则链", "selected-rulechains": "已选择 { count, plural, =1 {1 个规则链} other {# 个规则链} }", "open-rulechain": "打开规则链", - "assign-new-rulechain": "分配新的规则链", "edge-template-root": "模版根链", "assign-to-edge": "分配给边缘", "edge-rulechain": "边缘规则链", @@ -3314,11 +3710,13 @@ "events": "事件", "search": "查找节点", "open-node-library": "打开节点库", + "close-node-library": "关闭节点库", "add": "添加规则节点", "name": "名称", "name-required": "名称必填。", "name-max-length": "名称长度应该少于256个字符。", "type": "类型", + "rule-node-description": "规则节点描述", "delete": "删除规则节点", "select-all-objects": "选择所有节点和连接", "deselect-all-objects": "取消选择所有节点和连接", @@ -3343,7 +3741,7 @@ "link-labels-required": "链接标签必填。", "no-link-labels-found": "未找到链接标签", "no-link-label-matching": "未找到匹配 '{{label}}' 的链接标签。", - "create-new-link-label": "创建一个新的!", + "create-new-link-label": "创建链接标签", "type-filter": "筛选器", "type-filter-details": "使用配置条件筛选传入消息", "type-enrichment": "属性集", @@ -3377,7 +3775,8 @@ "output": "输出", "test": "测试", "help": "帮助", - "reset-debug-mode": "重置所有节点中的调试模式" + "reset-debug-mode": "重置所有节点中的调试模式", + "test-with-this-message": "使用此消息进行{{test}}测试" }, "timezone": { "timezone": "时区", @@ -3451,6 +3850,8 @@ "description": "说明", "description-hint": "此文本将显示在队列说明中,而不是所选策略中", "alt-description": "提交策略:{{submitStrategy}},处理策略:{{processingStrategy}}", + "custom-properties": "自定义属性", + "custom-properties-hint": "自定义队列(主题)创建属性,例如 'retention.ms:604800000;retention.bytes:1048576000'", "strategies": { "sequential-by-originator-label": "按发起者顺序处理", "sequential-by-originator-hint": "在确认设备A的前一条消息之前,不会提交设备A的新消息", @@ -3551,12 +3952,12 @@ "set-default-tenant-profile-title": "确定要将租户配置 '{{tenantProfileName}}' 设为默认值吗?", "set-default-tenant-profile-text": "确认后,此租户配置将被标记为默认配置,并将用于未指定配置的新租户。", "no-tenant-profiles-found": "未找到租户配置。", - "create-new-tenant-profile": "创建一个新的!", - "create-tenant-profile": "创建新的租户配置", + "create-new-tenant-profile": "创建租户配置", + "create-tenant-profile": "创建租户配置", "import": "导入租户配置", "export": "导出租户配置", "export-failed-error": "无法导出租户配置: {{error}}", - "tenant-profile-file": "租户配置文件", + "tenant-profile-file": "租户配置", "invalid-tenant-profile-file-error": "无法导入租户配置:无效的租户配置数据结构。", "advanced-settings": "高级设置", "entities": "实体", @@ -3612,6 +4013,9 @@ "max-j-s-executions": "最大 JavaScript 执行数", "max-j-s-executions-required": "最大 JavaScript 执行数必填。", "max-j-s-executions-range": "最大 JavaScript 执行数不能为负数", + "max-tbel-executions": "最大 TBEL 执行数", + "max-tbel-executions-required": "需要指定最大 TBEL 执行数。", + "max-tbel-executions-range": "最大 TBEL 执行数不能为负数。", "max-d-p-storage-days": "最大存储点天", "max-d-p-storage-days-required": "最大存储点天必填。", "max-d-p-storage-days-range": "最大存储点天不能为负数", @@ -3624,12 +4028,19 @@ "rpc-ttl-days": "RPC TTL天数", "rpc-ttl-days-required": "RPC TTL天数必填。", "rpc-ttl-days-days-range": "RPC TTL天数不能为负数", + "queue-stats-ttl-days": "队列统计信息TTL天数", + "queue-stats-ttl-days-required": "需要指定队列统计信息TTL天数", + "queue-stats-ttl-days-range": "队列统计信息TTL天数不能为负数", + "rule-engine-exceptions-ttl-days": "规则引擎异常TTL天数", + "rule-engine-exceptions-ttl-days-required": "需要指定规则引擎异常TTL天数", + "rule-engine-exceptions-ttl-days-range": "规则引擎异常TTL天数不能为负数", "max-rule-node-executions-per-message": "每条消息的最大规则节点执行数", "max-rule-node-executions-per-message-required": "每个消息的最大规则节点执行数必填。", "max-rule-node-executions-per-message-range": "每条消息的最大规则节点执行数不能为负", "max-emails": "最大电子邮件发送数", "max-emails-required": "最大电子邮件发送数必填。", "max-emails-range": "最大电子邮件发送数不能为负", + "sms-enabled": "启用短信", "max-sms": "最大短信发送数", "max-sms-required": "最大短信发送数必填。", "max-sms-range": "最大短信发送数不能为负", @@ -3740,16 +4151,24 @@ "days": "天" }, "timewindow": { + "timewindow": "时间窗口", "years": "{ years, plural, =1 {1 年 } other {# 年 } }", - "months": "{ months, plural, =1 { 月 } other {# 月 } }", - "weeks": "{ weeks, plural, =1 { 周 } other {# 周 } }", + "years-short": "{{ years }}y", + "months": "{ months, plural, =1 {1 月 } other {# 月 } }", + "months-short": "{{ months }}M", + "weeks": "{ weeks, plural, =1 {1 周 } other {# 周 } }", + "weeks-short": "{{ weeks }}w", "days": "{ days, plural, =1 {1 天 } other {# 天 } }", + "days-short": "{{ days }}d", "hours": "{ hours, plural, =0 {- 小时 } =1 {1 小时 } other {# 小时 } }", "hr": "{{ hr }} 时", + "hr-short": "{{ hr }}h", "minutes": "{ minutes, plural, =0 {- 分 } =1 {1 分 } other {# 分 } }", "min": "{{ min }} 分", + "min-short": "{{ min }}m", "seconds": "{ seconds, plural, =0 {- 秒 } =1 {1 秒 } other {# 秒 } }", "sec": "{{ sec }} 秒", + "sec-short": "{{ sec }}s", "short": { "days": "{ days, plural, =1 {1 天 } other {# 天 } }", "hours": "{ hours, plural, =1 {1 小时 } other {# 小时 } }", @@ -3768,7 +4187,426 @@ "hide": "隐藏", "interval": "区间", "just-now": "刚刚", - "ago": "之前" + "just-now-lower": "刚刚", + "ago": "之前", + "style": "时间窗口样式", + "icon": "图标", + "icon-position": "图标位置", + "icon-position-left": "左侧", + "icon-position-right": "右侧", + "font": "字体", + "color": "颜色", + "displayTypePrefix": "显示实时/历史前缀", + "preview": "预览" + }, + "tooltip": { + "value": "值", + "date": "日期", + "background-color": "背景颜色", + "background-blur": "背景模糊" + }, + "unit": { + "millimeter": "mm", + "centimeter": "cm", + "angstrom": "Å", + "nanometer": "nm", + "micrometer": "μm", + "meter": "m", + "kilometer": "km", + "inch": "in", + "foot": "ft", + "yard": "yd", + "mile": "mi", + "nautical-mile": "nmi", + "astronomical-unit": "au", + "reciprocal-metre": "m⁻¹", + "meter-per-meter": "m/m", + "steradian": "sr", + "thou": "th", + "barleycorn": "bc", + "hand": "hd", + "chain": "ch", + "furlong": "fur", + "league": "lea", + "fathom": "fath", + "cable": "cb", + "link": "li", + "rod": "rd", + "nanogram": "ng", + "microgram": "μg", + "milligram": "mg", + "gram": "g", + "kilogram": "kg", + "tonne": "t", + "ounce": "oz", + "pound": "lb", + "stone": "st", + "hundredweight-count": "cwt", + "short-tons": "s.t.", + "dalton": "Da", + "grain": "gr", + "drachm": "dr", + "quarter": "qr", + "slug": "slug", + "carat": "ct", + "cubic-millimeter": "mm³", + "cubic-centimeter": "cm³", + "cubic-meter": "m³", + "cubic-kilometer": "km³", + "microliter": "μL", + "milliliter": "mL", + "liter": "L", + "hectoliter": "hL", + "cubic-inch": "in³", + "cubic-foot": "ft³", + "cubic-yard": "yd³", + "fluid-ounce": "fl oz", + "pint": "pt", + "quart": "qt", + "gallon": "gal", + "oil-barrels": "bbl", + "cubic-meter-per-kilogram": "m³/kg", + "gill": "gi", + "hogshead": "hhd", + "teaspoon": "tsp", + "tablespoon": "tbsp", + "cup": "cup", + "celsius": "°C", + "kelvin": "K", + "rankine": "°R", + "fahrenheit": "°F", + "percent": "%", + "meter-per-second": "m/s", + "kilometer-per-hour": "km/h", + "foot-per-second": "ft/s", + "mile-per-hour": "mph", + "knot": "kn", + "millimeters-per-minute": "mm/min", + "kilometer-per-hour-squared": "km/h²", + "foot-per-second-squared": "ft/s²", + "pascal": "Pa", + "kilopascal": "kPa", + "megapascal": "MPa", + "gigapascal": "GPa", + "millibar": "mbar", + "bar": "bar", + "kilobar": "kbar", + "newton": "N", + "newton-meter": "N·m", + "foot-pounds": "ft·lbf", + "inch-pounds": "in·lbf", + "newton-per-meter": "N/m", + "atmospheres": "atm", + "pounds-per-square-inch": "psi", + "torr": "Torr", + "inches-of-mercury": "inHg", + "pascal-per-square-meter": "Pa/m²", + "pound-per-square-inch": "psi", + "newton-per-square-meter": "N/m²", + "kilogram-force-per-square-meter": "kgf/m²", + "pascal-per-square-centimeter": "Pa/cm²", + "ton-force-per-square-inch": "tonf/in²", + "kilonewton-per-square-meter": "kN/m²", + "newton-per-square-millimeter": "N/mm²", + "microjoule": "μJ", + "millijoule": "mJ", + "joule": "J", + "kilojoule": "kJ", + "megajoule": "MJ", + "gigajoule": "GJ", + "watt-hour": "Wh", + "kilowatt-hour": "kWh", + "electron-volts": "eV", + "joules-per-coulomb": "J/C", + "british-thermal-unit": "BTU", + "foot-pound": "ft·lb", + "calorie": "cal", + "small-calorie": "cal", + "kilocalorie": "kcal", + "joule-per-kelvin": "J/K", + "joule-per-kilogram-kelvin": "J/(kg·K)", + "joule-per-kilogram": "J/kg", + "watt-per-meter-kelvin": "W/(m·K)", + "joule-per-cubic-meter": "J/m³", + "therm": "thm", + "electric-dipole-moment": "Debye", + "magnetic-dipole-moment": "Am²", + "debye": "D", + "coulomb-per-square-meter-per-volt": "C/(m²·V)", + "milliwatt": "mW", + "microwatt": "μW", + "watt": "W", + "kilowatt": "kW", + "megawatt": "MW", + "gigawatt": "GW", + "metric-horsepower": "PS", + "milliwatt-per-square-centimeter": "mW/cm²", + "watt-per-square-centimeter": "W/cm²", + "kilowatt-per-square-centimeter": "kW/cm²", + "milliwatt-per-square-meter": "mW/m²", + "watt-per-square-meter": "W/m²", + "kilowatt-per-square-meter": "kW/m²", + "watt-per-square-inch": "W/in²", + "kilowatt-per-square-inch": "kW/in²", + "horsepower": "hp", + "btu-per-hour": "BTU/h", + "coulomb": "C", + "millicoulomb": "mC", + "microcoulomb": "μC", + "picocoulomb": "pC", + "coulomb-per-meter": "C/m", + "coulomb-per-cubic-meter": "C/m³", + "coulomb-per-square-meter": "C/m²", + "square-millimeter": "mm²", + "square-centimeter": "cm²", + "square-meter": "m²", + "hectare": "ha", + "square-kilometer": "km²", + "square-inch": "in²", + "square-foot": "ft²", + "square-yard": "yd²", + "acre": "ac", + "square-mile": "mi²", + "are": "a", + "barn": "b", + "circular-inch": "c in²", + "milliampere-hour": "mAh", + "ampere-hours": "Ah", + "kiloampere-hours": "kAh", + "nanoampere": "nA", + "picoampere": "pA", + "microampere": "μA", + "milliampere": "mA", + "ampere": "A", + "kiloamperes": "kA", + "microampere-per-square-centimeter": "μA/cm²", + "ampere-per-square-meter": "A/m²", + "ampere-per-meter": "A/m", + "oersted": "Oe", + "bohr-magneton": "μB", + "ampere-meter-squared": "A·m²", + "ampere-meter": "A·m", + "nanovolt": "nV", + "picovolt": "pV", + "millivolts": "mV", + "microvolts": "μV", + "volt": "V", + "kilovolts": "kV", + "dbmV": "dBmV", + "dbm": "dBm", + "volt-meter": "V·m", + "kilovolt-meter": "kV·m", + "megavolt-meter": "MV·m", + "microvolt-meter": "μV·m", + "millivolt-meter": "mV·m", + "nanovolt-meter": "nV·m", + "ohm": "Ω", + "microohm": "μΩ", + "milliohm": "mΩ", + "kilohm": "kΩ", + "megohm": "MΩ", + "gigohm": "GΩ", + "hertz": "Hz", + "kilohertz": "kHz", + "megahertz": "MHz", + "gigahertz": "GHz", + "rpm": "rpm", + "candela-per-square-meter": "cd/m²", + "candela": "cd", + "lumen": "lm", + "lux": "lx", + "foot-candle": "fc", + "lumen-per-square-meter": "lm/m²", + "lux-second": "lx·s", + "lumen-second": "lm·s", + "lumens-per-watt": "lm/W", + "absorbance": "AU", + "mole": "mol", + "nanomole": "nmol", + "micromole": "μmol", + "millimole": "mmol", + "kilomole": "kmol", + "mole-per-cubic-meter": "mol/m³", + "rssi": "RSSI", + "ppm": "ppm", + "ppb": "ppb", + "micrograms-per-cubic-meter": "μg/m³", + "aqi": "AQI", + "gram-per-cubic-meter": "g/m³", + "gram-per-kilogram": "g/kg", + "millimeters-per-second": "mm/s", + "neper": "Np", + "bel": "B", + "decibel": "dB", + "meters-per-second-squared": "m/s²", + "becquerel": "Bq", + "curie": "Ci", + "gray": "Gy", + "sievert": "Sv", + "roentgen": "R", + "cps": "cps", + "rad": "rad", + "rem": "rem", + "dps": "dps", + "rutherford": "Rd", + "coulombs-per-kilogram": "C/kg", + "becquerels-per-cubic-meter": "Bq/m³", + "curies-per-liter": "Ci/L", + "becquerels-per-second": "Bq/s", + "curies-per-second": "Ci/s", + "gy-per-second": "Gy/s", + "watt-per-steradian": "W/sr", + "watt-per-square-metre-steradian": "W/(m²·sr)", + "ph-level": "pH", + "turbidity": "NTU", + "mg-per-liter": "mg/L", + "microsiemens-per-centimeter": "μS/cm", + "millisiemens-per-meter": "mS/m", + "siemens-per-meter": "S/m", + "kilogram-per-cubic-meter": "kg/m³", + "gram-per-cubic-centimeter": "g/cm³", + "kilogram-per-square-meter": "kg/m²", + "milligram-per-milliliter": "mg/mL", + "pound-per-cubic-foot": "lb/ft³", + "ounces-per-cubic-inch": "oz/in³", + "tons-per-cubic-yard": "ton/yd³", + "particle-density": "PD", + "kilometers-per-liter": "km/L", + "miles-per-gallon": "mpg", + "liters-per-100-km": "L/100 km", + "gallons-per-mile": "gal/mi", + "liters-per-hour": "L/h", + "gallons-per-hour": "gal/h", + "beats-per-minute": "bpm", + "millimeters-of-mercury": "mmHg", + "milligrams-per-deciliter": "mg/dL", + "g-force": "G", + "kilonewton": "kN", + "kilogram-force": "kgf", + "pound-force": "lbf", + "kilopound-force": "kip", + "dyne": "dyn", + "poundal": "pdl", + "kip": "kip", + "gal": "Gal", + "gravity": "g₀", + "hectopascal": "hPa", + "atmosphere": "atm", + "millibars": "mbar", + "inch-of-mercury": "inHg", + "richter-scale": "Richter", + "second": "s", + "minute": "min", + "hour": "hr", + "day": "day", + "week": "wk", + "month": "mo", + "year": "yr", + "cubic-foot-per-minute": "ft³/min", + "cubic-meters-per-hour": "m³/h", + "cubic-meters-per-second": "m³/s", + "liter-per-second": "L/s", + "liter-per-minute": "L/min", + "gallons-per-minute": "GPM", + "cubic-foot-per-second": "ft³/s", + "milliliters-per-minute": "mL/min", + "bit": "bit", + "byte": "B", + "kilobyte": "KB", + "megabyte": "MB", + "gigabyte": "GB", + "terabyte": "TB", + "petabyte": "PB", + "exabyte": "EB", + "zettabyte": "ZB", + "yottabyte": "YB", + "bit-per-second": "bps", + "kilobit-per-second": "Kbps", + "megabit-per-second": "Mbps", + "gigabit-per-second": "Gbps", + "terabit-per-second": "Tbps", + "byte-per-second": "B/s", + "kilobyte-per-second": "KB/s", + "megabyte-per-second": "MB/s", + "gigabyte-per-second": "GB/s", + "degree": "°", + "radian": "rad", + "gradian": "grad", + "mil": "mil", + "revolution": "rev", + "siemens": "S", + "millisiemens": "mS", + "microsiemens": "μS", + "kilosiemens": "kS", + "megasiemens": "MS", + "gigasiemens": "GS", + "farad": "F", + "millifarad": "mF", + "microfarad": "μF", + "nanofarad": "nF", + "picofarad": "pF", + "kilofarad": "kF", + "megafarad": "MF", + "gigafarad": "GF", + "terfarad": "TF", + "farad-per-meter": "F/m", + "tesla": "T", + "gauss": "G", + "kilogauss": "kG", + "millitesla": "mT", + "microtesla": "μT", + "nanotesla": "nT", + "kilotesla": "kT", + "megatesla": "MT", + "millitesla-square-meters": "mT·m²", + "gamma": "γ", + "lambda": "λ", + "square-meter-per-second": "m²/s", + "square-centimeter-per-second": "cm²/s", + "stoke": "St", + "centistokes": "cSt", + "square-foot-per-second": "ft²/s", + "square-inch-per-second": "in²/s", + "pascal-second": "Pa·s", + "centipoise": "cP", + "poise": "P", + "reynolds": "Re", + "pound-per-foot-hour": "lb/(ft·hr)", + "newton-second-per-square-meter": "N·s/m²", + "dyne-second-per-square-centimeter": "dyn·s/cm²", + "kilogram-per-meter-second": "kg/(m·s)", + "tesla-square-meters": "T·m²", + "maxwell": "Mx", + "tesla-per-meter": "T/m", + "gauss-per-centimeter": "G/cm", + "weber": "Wb", + "microweber": "μWb", + "milliweber": "mWb", + "gauss-square-centimeter": "G·cm²", + "kilogauss-square-centimeter": "kG·cm²", + "henry": "H", + "millihenry": "mH", + "microhenry": "μH", + "nanohenry": "nH", + "henry-per-meter": "H/m", + "tesla-meter-per-ampere": "T·m/A", + "gauss-per-oersted": "G/Oe", + "kilogram-per-mole": "kg/mol", + "gram-per-mole": "g/mol", + "milligram-per-mole": "mg/mol", + "joule-per-mole": "J/mol", + "joule-per-mole-kelvin": "J/mol-K", + "millivolts-per-meter": "mV/m", + "volts-per-meter": "V/m", + "kilovolts-per-meter": "kV/m", + "radian-per-second": "rad/s", + "radian-per-second-squared": "rad/s^2", + "revolutions-per-minute-per-second": "rpm/s", + "revolutions-per-minute-per-second-squared": "rpm/s^2", + "deg-per-second": "deg/s", + "degrees-brix": "°Bx", + "katal": "kat", + "katal-per-cubic-metre": "kat/m^3" }, "user": { "user": "用户", @@ -3918,11 +4756,20 @@ "widget-bundle": "部件包", "all-bundles": "所有包", "select-widgets-bundle": "选择部件包", + "widgets": "部件", + "all-widgets": "所有部件", + "widget": "部件", + "select-widget": "选择部件", + "no-widgets-matching": "未找到与 '{{entity}}' 匹配的部件。", + "no-widgets": "暂无部件", + "no-widgets-text": "未找到部件", "management": "管理部件", "editor": "部件编辑器", + "confirm-to-exit-editor-html": "You have unsaved widget settings.
Are you sure you want to leave this page?", "widget-type-not-found": "加载部件配置出错。
可能关联的部件已经删除了。", "widget-type-load-error": "由于以下错误未加载部件:", "remove": "删除部件", + "delete": "Delete widget", "edit": "编辑部件", "remove-widget-title": "确定要删除 '{{widgetTitle}}'部件吗?", "remove-widget-text": "确认后,控件和所有相关数据将变得不可恢复。", @@ -3933,18 +4780,27 @@ "rpc": "控件部件", "alarm": "告警部件", "static": "静态部件", + "timeseries-short": "时序", + "latest-short": "最新", + "rpc-short": "控制", + "alarm-short": "告警", + "static-short": "静态", "select-widget-type": "选择窗口部件类型", "missing-widget-title-error": "部件标题必须指定!", "widget-saved": "部件已保存", "unable-to-save-widget-error": "无法保存部件!控件有错误!", "save": "保存部件", "saveAs": "部件另存为", - "save-widget-type-as": "部件类型另存为", - "save-widget-type-as-text": "请输入新的部件标题或选择目标部件包", + "move": "移动部件", + "save-widget-as": "另存部件为", + "save-widget-as-text": "请输入部件标题", "toggle-fullscreen": "切换全屏", "run": "运行部件", + "widget-title": "部件标题", "title": "部件标题", "title-required": "部件标题必填。", + "title-max-length": "标题应少于256个字符", + "system": "系统", "type": "部件类型", "resources": "资源", "resource-url": "JavaScript/CSS URL", @@ -3959,17 +4815,37 @@ "latest-datakey-settings-schema": "最新值数据键设置模式", "widget-settings": "部件设置", "description": "描述", + "tags": "标签", "image-preview": "图片预览", "settings-form-selector": "设置表单选择器", "data-key-settings-form-selector": "数据键设置表单选择器", "latest-data-key-settings-form-selector": "最新值数据键设置表单选择器", - "javascript": "Javascript", + "all": "全部", + "actual": "实际", + "deprecated": "已弃用", + "has-basic-mode": "具有基本模式", + "basic-mode-form-selector": "基本模式表单选择器", + "basic-mode": "基本", + "advanced-mode": "高级", + "javascript": "JavaScript", "js": "JS", - "add-widget-type": "添加部件类型", + "delete-widget-title": "确定要删除部件'{{widgetName}}'吗?", + "delete-widget-text": "确认后,部件及其所有相关数据将无法恢复。", + "delete-widgets-title": "确定要删除 { count, plural, =1 {1个部件} other {#个部件} }吗?", + "delete-widgets-text": "请谨慎操作,确认后,所有选定的部件将被删除,并且所有相关数据将无法恢复。", + "delete-widget": "删除部件", "widget-template-load-failed-error": "无法加载部件模板!", - "add": "添加部件", - "undo": "撤消部件更改", - "export": "导出部件", + "details": "详情", + "widget-details": "部件详情", + "add": "添加", + "add-existing-widget": "添加现有部件", + "add-new-widget": "添加新部件", + "search-widgets": "搜索部件", + "selected-widgets": "已选择 { count, plural, =1 {1 个部件} other {# 个部件} }", + "undo": "撤销", + "export": "导出", + "export-widgets": "导出部件", + "import": "导入部件", "no-data": "部件上没有要显示的数据", "data-overflow": "部件显示 {{count}} 条实体中的 {{total}} 条", "alarm-data-overflow": "部件显示了 {{allowedEntities}}(最大允许)实体中的告警,总共有 {{totalEntities}} 个实体", @@ -4038,6 +4914,7 @@ "widgets-bundle": { "current": "当前组", "widgets-bundles": "部件包", + "widgets-bundle-widgets": "包部件", "add": "添加部件包", "delete": "删除部件包", "title": "标题", @@ -4045,6 +4922,7 @@ "title-max-length": "标题长度应该少于256个字符。", "description": "描述", "image-preview": "图片预览", + "order": "其他", "add-widgets-bundle-text": "添加部件包", "no-widgets-bundles-text": "未找到部件包", "empty": "部件包是空的", @@ -4060,8 +4938,9 @@ "system": "系统", "import": "导入部件包", "export": "导出部件包", + "export-widgets-bundle-widgets-prompt": "在导出的数据中包含包部件(否则只会导出引用的部件完全限定名)", "export-failed-error": "无法导出部件包: {{error}}", - "create-new-widgets-bundle": "创建新的部件包", + "create-new-widgets-bundle": "创建部件包", "widgets-bundle-file": "部件包文件", "invalid-widgets-bundle-file-error": "无法导入部件包:无效的部件包数据结构。", "search": "查找部件包", @@ -4073,14 +4952,19 @@ "data": "数据", "settings": "设置", "advanced": "高级", + "appearance": "外观", + "widget-card": "部件卡片", + "mobile": "移动设备", "title": "标题", - "title-tooltip": "标题 Tooltip", - "general-settings": "基本设置", + "title-tooltip": "标题文字提示", + "general-settings": "常规设置", "display-title": "显示标题", - "drop-shadow": "阴影", + "card-title": "卡片标题", + "drop-shadow": "投影", "enable-fullscreen": "启用全屏", "background-color": "背景颜色", "text-color": "文字颜色", + "border-radius": "边框半径", "padding": "填充", "margin": "边缘", "widget-style": "部件样式", @@ -4092,13 +4976,21 @@ "mobile-hide": "在移动端隐藏部件", "desktop-hide": "在桌面端隐藏部件", "units": "特殊符号展示值", - "decimals": "浮点数后的位数", + "units-by-default": "默认单位", + "decimals": "小数位数", + "decimals-by-default": "默认小数位数", + "default-data-key-parameter-hint": "该参数适用于所有部件值,除非被数据键配置覆盖", + "units-short": "单位", + "decimals-short": "小数", + "decimals-suffix": "位小数", "timewindow": "时间窗口", - "use-dashboard-timewindow": "使用仪表板的时间窗口", + "use-dashboard-timewindow": "使用仪表板时间窗口", + "use-widget-timewindow": "使用部件时间窗口", "display-timewindow": "显示时间窗口", "legend": "图例", "display-legend": "显示图例", "datasources": "数据源", + "datasource": "数据源", "maximum-datasources": "最大允许 { count, plural, =1 {1 个数据源。} other {# 个数据源。} }", "timeseries-key-error": "需要至少指定一个 timeseries 数据键", "datasource-type": "类型", @@ -4127,26 +5019,84 @@ "delete-action-text": "确定要删除部件动作'{{actionName}}' 吗?", "title-icon": "标题图标", "display-icon": "显示标题图标", + "card-icon": "卡片图标", + "icon": "图标", "icon-color": "图标颜色", "icon-size": "图标大小", "advanced-settings": "高级设置", "data-settings": "数据设置", + "limits": "限制", "no-data-display-message": "\"没有数据可显示\" 替代信息", "data-page-size": "每个数据源的最大实体数", - "settings-component-not-found": "未找到设置的表单组件选择器 '{{selector}}'" + "settings-component-not-found": "未找到设置的表单组件选择器 '{{selector}}'", + "preview": "预览", + "set": "设置", + "set-message": "设置消息", + "advanced-title-style": "高级标题样式", + "card-style": "卡片样式", + "text": "文本", + "background": "背景", + "advanced-widget-style": "高级部件样式", + "card-buttons": "卡片按钮", + "show-card-buttons": "显示卡片按钮", + "card-border-radius": "卡片边框半径", + "card-appearance": "卡片外观", + "color": "颜色", + "tooltip": "文字提示", + "units-required": "单位是必须的。" }, "widget-type": { "import": "导入部件类型", "export": "导出部件类型", "export-failed-error": "无法导出部件类型: {{error}}", - "create-new-widget-type": "创建新的部件类型", - "widget-type-file": "部件类型文件", - "invalid-widget-type-file-error": "无法导入部件类型:无效的部件类型数据结构。" + "widget-file": "部件文件", + "invalid-widget-file-error": "无法导入部件:无效的部件数据结构。" }, "widgets": { + "background": { + "background": "背景", + "background-settings": "背景设置", + "background-type-image": "上传图像", + "background-type-image-url": "图像URL", + "background-type-color": "纯色背景", + "image-url": "图像URL", + "overlay": "覆盖", + "enable-overlay": "启用覆盖", + "blur": "模糊", + "preview": "预览" + }, + "battery-level": { + "layout": "布局", + "layout-vertical-solid": "垂直. 实心", + "layout-horizontal-solid": "水平. 实心", + "layout-vertical-divided": "垂直. 分割", + "layout-horizontal-divided": "水平. 分割", + "icon": "图标", + "value": "数值", + "auto-scale": "自动缩放", + "battery-level-color": "电池电量颜色", + "battery-shape-color": "电池形状颜色", + "battery-level-card-style": "电池电量卡片样式", + "sections-count": "分段数量" + }, + "signal-strength": { + "value": "数值", + "last-update": "上次更新", + "no-signal": "无信号", + "layout": "布局", + "layout-wifi": "Wi-Fi", + "layout-cellular-bar": "蜂窝网络条状", + "icon": "图标", + "date": "日期", + "active-bars-color": "活动信号条颜色", + "inactive-bars-color": "非活动信号条颜色", + "signal-strength-card-style": "信号强度卡片样式" + }, "chart": { "common-settings": "通用设置", "enable-stacking-mode": "启用堆叠模式", + "selection": "时间范围选择", + "enable-selection-mode": "启用选择模式", "line-shadow-size": "线条阴影大小", "display-smooth-lines": "显示平滑(曲线)线条", "default-bar-width": "非聚合数据的默认条形图宽度(毫秒)", @@ -4154,15 +5104,17 @@ "bar-alignment-left": "左", "bar-alignment-right": "右", "bar-alignment-center": "居中", + "default-font": "默认字体", "default-font-size": "默认字体大小", "default-font-color": "默认字体颜色", "thresholds-line-width": "所有阈值的默认线条宽度", - "tooltip-settings": "Tooltip 设置", - "show-tooltip": "显示 Tooltip", + "tooltip-settings": "文字提示设置", + "tooltip": "文字提示", + "show-tooltip": "显示文字提示", "hover-individual-points": "悬停在单个数据点上", "show-cumulative-values": "在堆叠模式下显示累积值", - "hide-zero-false-values": "Tooltip 隐藏 zero/false", - "tooltip-value-format-function": "Tooltip 值的格式化函数", + "hide-zero-false-values": "文字提示隐藏 zero/false", + "tooltip-value-format-function": "文字提示值的格式化函数", "grid-settings": "网格线设置", "show-vertical-lines": "显示垂直线条", "show-horizontal-lines": "显示水平线条", @@ -4235,6 +5187,7 @@ "add-threshold": "添加新阈值", "show-values-for-comparison": "显示历史比较值", "comparison-values-label": "历史值标签", + "comparison-line-color": "对比线颜色", "threshold-settings": "阈值设置", "use-as-threshold": "使用键值作为阈值", "threshold-line-width": "阈值线宽", @@ -4243,6 +5196,7 @@ "radius": "半径", "inner-radius": "内部半径", "tilt": "倾斜", + "common-pie-settings-range-error": "值应在0到1的范围内", "stroke-settings": "描边设置", "width-pixels": "宽度 (px)", "show-labels": "显示标签", @@ -4253,7 +5207,35 @@ "border-color": "边框颜色", "legend-settings": "图例设置", "display-legend": "显示图例", - "labels-font-color": "标签字体颜色" + "labels-font-color": "标签字体颜色", + "series": "系列", + "add-series": "添加系列", + "series-settings": "系列设置", + "remove-series": "删除系列", + "no-series": "未配置系列", + "no-series-error": "至少应指定一个系列", + "chart-appearance": "图表外观", + "vertical-grid-lines": "垂直网格线", + "horizontal-grid-lines": "水平网格线", + "chart-background": "图表背景", + "grid-lines-color": "网格线颜色", + "border": "边框", + "axis": "轴", + "vertical-axis": "垂直轴", + "ticks": "刻度", + "horizontal-axis": "水平轴" + }, + "color": { + "color-settings": "颜色设置", + "color-type-constant": "固定值", + "color-type-range": "数值范围", + "color-type-function": "函数", + "color": "颜色", + "value-range": "数值范围", + "from": "从", + "to": "至", + "color-function": "颜色函数", + "copy-color-settings-from": "从其他处复制颜色设置" }, "dashboard-state": { "dashboard-state-settings": "仪表板状态设置", @@ -4341,6 +5323,19 @@ "Ok": "Ok" } }, + "doughnut": { + "total": "总计", + "layout": "布局", + "layout-default": "默认", + "layout-with-total": "带总计", + "auto-scale": "自动缩放", + "clockwise-layout": "顺时针布局", + "sort-series": "按标签对系列排序", + "central-total-value": "中央总计值", + "tooltip-value-type-absolute": "绝对值", + "tooltip-value-type-percentage": "百分比", + "doughnut-card-style": "圆环样式" + }, "entities-hierarchy": { "hierarchy-data-settings": "层次数据设置", "relations-query-function": "关系查询函数", @@ -4369,7 +5364,12 @@ "read-only": "只读", "events-title": "事件标题", "events-filter": "事件过滤", - "event-key-contains": "包含事件key..." + "event-key-contains": "事件键包含...", + "show-connector": "显示连接器", + "connector-state-param-key": "连接器状态参数键", + "status": "状态", + "message": "消息", + "created-time": "创建时间" }, "gauge": { "default-color": "默认颜色", @@ -4377,10 +5377,14 @@ "ticks-settings": "刻度设置", "min-value": "最小值", "max-value": "最大值", + "min-value-short": "最小值", + "max-value-short": "最大值", "start-ticks-angle": "刻度起始角度", "ticks-angle": "刻度角度", + "major-ticks": "主刻度", "major-ticks-count": "主刻度数量", "major-ticks-color": "主刻度颜色", + "minor-ticks": "次刻度", "minor-ticks-count": "次刻度数量", "minor-ticks-color": "次刻度颜色", "tick-numbers-font": "刻度数字字体", @@ -4392,8 +5396,15 @@ "units-font": "单位文字字体", "value-box-settings": "数值框设置", "show-value-box": "显示数值框", - "value-int": "整数部分的位数", - "value-font": "数值文字字体", + "value-box": "数值框", + "value-int": "整数部位数", + "value-text": "数值文本", + "value-text-shadow": "数值文本阴影", + "value-font": "数值字体", + "rect-stroke-color-start": "矩形边框颜色 - 渐变起始", + "rect-stroke-color-end": "矩形边框颜色 - 渐变结束", + "background-color": "背景颜色", + "shadow-color": "阴影颜色", "value-box-rect-stroke-color": "数值框矩形描边颜色", "value-box-rect-stroke-color-end": "数值框矩形描边颜色 - 渐变结束", "value-box-background-color": "数值框背景颜色", @@ -4404,6 +5415,7 @@ "needle-settings": "指针设置", "needle-circle-size": "指针圆圈尺寸", "needle-color": "指针颜色", + "needle-color-start": "指针颜色 - 渐变起始", "needle-color-end": "指针颜色 - 渐变结束", "needle-color-shadow-up": "指针上半部分阴影颜色", "needle-color-shadow-down": "指针下半部分阴影颜色", @@ -4417,6 +5429,7 @@ "add-highlight": "添加高亮", "animation-settings": "动画设置", "enable-animation": "启用动画", + "animation-duration-rule": "动画持续时间和规则", "animation-duration": "动画持续时间", "animation-rule": "动画规则", "animation-linear": "线性", @@ -4431,17 +5444,21 @@ "animation-debounce": "弹跳反向", "animation-delastic": "弹性反向", "linear-gauge-settings": "线性量规设置", + "bar-stroke": "柱状图描边", "bar-stroke-width": "条形图描边宽度", "bar-stroke-color": "条形图描边颜色", "bar-background-color": "量规条形图背景颜色", "bar-background-color-end": "条形图背景颜色 - 渐变结束", "progress-bar-color": "进度条颜色", + "progress-bar": "进度条", + "progress-bar-color-start": "进度条颜色 - 渐变起始", "progress-bar-color-end": "进度条颜色 - 渐变结束", "major-ticks-names": "主刻度名称", "show-stroke-ticks": "显示刻度描边", "major-ticks-font": "主刻度字体", "border-color": "边框颜色", "border-width": "边框宽度", + "needle-circle": "指针圆圈", "needle-circle-color": "指针圆圈颜色", "animation-target": "动画目标", "animation-target-needle": "指针", @@ -4485,7 +5502,18 @@ "tick-color": "刻度颜色", "tick-values": "刻度值", "no-tick-values": "未配置刻度值", - "add-tick-value": "添加刻度值" + "add-tick-value": "添加刻度值", + "gauge-appearance": "仪表盘外观", + "units-title": "单位标题", + "value": "数值", + "ticks": "刻度", + "arrow-and-scale-color": "箭头和刻度默认颜色", + "scale-settings": "刻度设置", + "scale": "刻度尺寸", + "scale-color": "刻度颜色", + "compass-appearance": "指南针外观", + "labels": "标签", + "label-style": "标签样式" }, "gpio": { "pin": "引脚", @@ -4602,6 +5630,9 @@ "input-fields-alignment": "输入字段对齐方式", "input-fields-alignment-column": "列(默认)", "input-fields-alignment-row": "行", + "layout": "布局", + "row-gap": "行之间的间距(像素)", + "column-gap": "列之间的间距(像素)", "latitude-field-required": "纬度字段必填", "longitude-field-required": "经度字段必填", "attribute-settings": "属性设置", @@ -4650,12 +5681,19 @@ "datakey-value-type-date": "日期", "datakey-value-type-time": "时间", "datakey-value-type-select": "选择", + "datakey-value-type-color": "颜色", "value-is-required": "值必填", "ability-to-edit-attribute": "编辑属性的能力", "ability-to-edit-attribute-editable": "可编辑(默认)", "ability-to-edit-attribute-disabled": "禁用", "ability-to-edit-attribute-readonly": "只读", "disable-on-datakey-name": "在另一个数据键的值为假时禁用(指定数据键名称)", + "field-appearance": "字段外观", + "appearance-fill": "填充", + "appearance-outline": "轮廓", + "subscript-sizing": "下标大小", + "subscript-sizing-fixed": "固定", + "subscript-sizing-dynamic": "动态", "slide-toggle-settings": "滑动开关设置", "slide-toggle-label-position": "滑动开关标签位置", "slide-toggle-label-position-after": "之后", @@ -4771,6 +5809,14 @@ "no-columns-found": "找不到列", "no-columns-matching": "未找到 '{{column}}'。" }, + "range-chart": { + "chart": "图表", + "data-zoom": "数据缩放", + "range-colors": "范围颜色", + "out-of-range-color": "超出范围颜色", + "fill-area": "填充区域", + "range-chart-card-style": "范围图表卡片样式" + }, "rpc": { "value-settings": "值设置", "initial-value": "初始值", @@ -4930,17 +5976,17 @@ "use-label-function": "使用标签函数", "label-pattern": "标签 (模式示例:'${entityName}', '${entityName}: (Text ${keyName} units.)' )", "label-function": "标签函数", - "tooltip": "Tooltip", - "show-tooltip": "显示 Tooltip", - "show-tooltip-action": "显示 Tooltip 的操作", - "show-tooltip-action-click": "点击时显示 Tooltip(默认)", - "show-tooltip-action-hover": "悬停时显示 Tooltip", - "auto-close-tooltips": "自动关闭 Tooltip", - "use-tooltip-function": "使用 Tooltip 函数", - "tooltip-pattern": "Tooltip (例如 'Text ${keyName} units.' or Link text')", - "tooltip-function": "Tooltip 函数", - "tooltip-offset-x": "Tooltip X偏移相对于标记锚点乘以标记宽度", - "tooltip-offset-y": "Tooltip Y偏移相对于标记锚点乘以标记高度", + "tooltip": "文字提示", + "show-tooltip": "显示文字提示", + "show-tooltip-action": "显示文字提示的操作", + "show-tooltip-action-click": "点击时显示文字提示(默认)", + "show-tooltip-action-hover": "悬停时显示文字提示", + "auto-close-tooltips": "自动关闭文字提示", + "use-tooltip-function": "使用文字提示函数", + "tooltip-pattern": "文字提示 (例如 'Text ${keyName} units.' or Link text')", + "tooltip-function": "文字提示函数", + "tooltip-offset-x": "文字提示X偏移相对于标记锚点乘以标记宽度", + "tooltip-offset-y": "文字提示Y偏移相对于标记锚点乘以标记高度", "color": "颜色", "use-color-function": "使用颜色函数", "color-function": "颜色函数", @@ -4959,12 +6005,12 @@ "use-polygon-label-function": "使用多边形标签函数", "polygon-label-pattern": "多边形标签 (模板示例:'${entityName}', '${entityName}: (Text ${keyName} units.)' )", "polygon-label-function": "多边形标签函数", - "polygon-tooltip": "多边形 Tooltip", - "show-polygon-tooltip": "显示多边形 Tooltip", - "auto-close-polygon-tooltips": "自动关闭多边形 Tooltip", - "use-polygon-tooltip-function": "使用多边形 Tooltip 函数", - "polygon-tooltip-pattern": "Tooltip (例如 'Text ${keyName} units.' or Link text')", - "polygon-tooltip-function": "多边形 Tooltip 函数", + "polygon-tooltip": "多边形文字提示", + "show-polygon-tooltip": "显示多边形文字提示", + "auto-close-polygon-tooltips": "自动关闭多边形文字提示", + "use-polygon-tooltip-function": "使用多边形文字提示函数", + "polygon-tooltip-pattern": "文字提示(例如 'Text ${keyName} units.' or Link text')", + "polygon-tooltip-function": "多边形文字提示函数", "polygon-color": "多边形颜色", "polygon-opacity": "多边形不透明度", "use-polygon-color-function": "使用多边形颜色函数", @@ -4984,12 +6030,12 @@ "use-circle-label-function": "使用圆标签函数", "circle-label-pattern": "圆标签 (模板示例:'${entityName}', '${entityName}: (Text ${keyName} units.)' )", "circle-label-function": "圆标签函数", - "circle-tooltip": "圆 Tooltip", - "show-circle-tooltip": "显示圆 Tooltip", - "auto-close-circle-tooltips": "自动关闭圆 Tooltip", - "use-circle-tooltip-function": "使用圆 Tooltip 函数", - "circle-tooltip-pattern": "Tooltip (例如 'Text ${keyName} units.' or Link text')", - "circle-tooltip-function": "圆 Tooltip 函数", + "circle-tooltip": "圆文字提示", + "show-circle-tooltip": "显示圆文字提示", + "auto-close-circle-tooltips": "自动关闭圆文字提示", + "use-circle-tooltip-function": "使用圆文字提示函数", + "circle-tooltip-pattern": "文字提示 (例如 'Text ${keyName} units.' or Link text')", + "circle-tooltip-function": "圆文字提示函数", "circle-fill-color": "圆填充颜色", "circle-fill-color-opacity": "圆填充颜色不透明度", "use-circle-fill-color-function": "使用圆填充颜色函数", @@ -5018,10 +6064,10 @@ "route-map-settings": "路线地图设置", "trip-animation-settings": "行程动画设置", "normalization-step": "数据标准化步骤(毫秒)", - "tooltip-background-color": "Tooltip 背景颜色", - "tooltip-font-color": "Tooltip 字体颜色", - "tooltip-opacity": "Tooltip 不透明度(0-1)", - "auto-close-tooltip": "自动关闭 Tooltip", + "tooltip-background-color": "文字提示背景颜色", + "tooltip-font-color": "文字提示字体颜色", + "tooltip-opacity": "文字提示不透明度(0-1)", + "auto-close-tooltip": "自动关闭文字提示", "rotation-angle": "设置标记的附加旋转角度(度)", "path-settings": "路径设置", "path-color": "路径颜色", @@ -5046,7 +6092,7 @@ "point-color-function": "点颜色函数", "use-point-as-anchor": "使用点作为锚点", "point-as-anchor-function": "点作为锚点函数", - "independent-point-tooltip": "独立点 Tooltip", + "independent-point-tooltip": "独立点文字提示", "clustering-markers": "标记聚类", "use-icon-create-function": "使用标记颜色函数", "marker-color-function": "标记颜色函数" @@ -5059,10 +6105,137 @@ "markdown-css": "Markdown/HTML CSS" }, "simple-card": { + "label": "标签", "label-position": "标签位置", "label-position-left": "左侧", "label-position-top": "顶部" }, + "value-card": { + "layout": "布局", + "layout-square": "正方形", + "layout-vertical": "垂直", + "layout-centered": "居中", + "layout-simplified": "简化", + "layout-horizontal": "水平", + "layout-horizontal-reversed": "水平翻转", + "label": "标签", + "icon": "图标", + "value": "数值", + "date": "日期", + "value-card-style": "数值卡片样式", + "auto-scale": "自动缩放" + }, + "liquid-level-card": { + "layout-simple": "简单", + "layout-percentage": "百分比", + "layout-absolute": "绝对值", + "layout": "布局", + "background-overlay": "值背景叠加", + "total-volume": "总体积", + "tank": "储罐", + "shape": "形状", + "datasource-units": "数据源单位", + "widget-units": "小部件单位", + "decimals": "小数位数", + "liquid": "液体", + "liquid-color": "液体颜色", + "value": "值", + "value-font": "值字体", + "level": "水位", + "last-update": "最后更新", + "shape-by-attribute": "按属性名称设置储罐形状", + "tooltip-background": "背景颜色", + "background-blur": "背景模糊", + "tank-color": "储罐颜色", + "static": "静态", + "see-examples": "查看示例", + "attribute": "属性", + "shape-type": "类型", + "v-oval": "垂直椭圆", + "v-cylinder": "垂直圆柱体", + "v-capsule": "垂直胶囊", + "rectangle": "矩形", + "h-oval": "水平椭圆", + "h-ellipse": "水平椭圆", + "h-dish-ends": "水平盘形", + "h-cylinder": "水平圆柱体", + "h-capsule": "水平胶囊", + "h-elliptical_2_1": "水平2:1椭圆", + "icon": "卡片图标", + "title": "卡片标题", + "units": "单位", + "color-and-font": "颜色和字体", + "shape-attribute-name": "属性名称", + "total-volume-required": "需要总体积。", + "attribute-name-required": "需要属性名称。", + "attribute-key-not-set": "未设置属性 '{{attributeName}}' 键", + "attribute-key-invalid": "属性 '{{attributeName}}' 键无效" + }, + "aggregated-value-card": { + "subtitle": "副标题", + "chart": "图表", + "values": "数值", + "value-appearance": "数值外观", + "position": "位置", + "position-center": "中心", + "position-right-top": "右上", + "position-right-bottom": "右下", + "position-left-top": "左上", + "position-left-bottom": "左下", + "font": "字体", + "color": "颜色", + "arrow": "箭头", + "display-up-down-arrow": "显示向上/向下箭头", + "add-value": "添加数值", + "remove-value": "移除数值", + "no-values": "未配置数值", + "aggregation": "聚合", + "aggregated-value-card-style": "聚合数值卡片样式", + "auto-scale": "自动缩放" + }, + "value-chart-card": { + "layout": "布局", + "layout-left": "左侧", + "layout-right": "右侧", + "auto-scale": "自动缩放", + "icon": "图标", + "value": "数值", + "chart": "图表", + "value-chart-card-style": "数值图表卡片样式" + }, + "progress-bar": { + "layout": "布局", + "layout-default": "默认", + "layout-simplified": "简化", + "auto-scale": "自动缩放", + "icon": "图标", + "value": "数值", + "range": "范围", + "min": "最小", + "max": "最大", + "range-ticks": "范围刻度", + "bar": "进度条", + "bar-color": "进度条颜色", + "bar-background": "进度条背景", + "progress-bar-card-style": "进度条卡片样式" + }, + "alarm-count": { + "alarm-count-card-style": "告警计数卡片样式" + }, + "entity-count": { + "entity-count-card-style": "实体计数卡片样式" + }, + "count": { + "layout": "布局", + "layout-column": "列", + "layout-row": "行", + "label": "标签", + "icon": "图标", + "icon-background": "图标背景", + "value": "数值", + "chevron": "箭头", + "auto-scale": "自动缩放" + }, "table": { "common-table-settings": "常规表格设置", "enable-search": "启用搜索", @@ -5072,7 +6245,6 @@ "show-empty-space-hidden-action": "显示空白区域而不是隐藏单元格按钮操作", "dont-reserve-space-hidden-action": "不为隐藏的操作按钮预留空间", "display-timestamp": "显示时间戳列", - "display-milliseconds": "显示时间戳毫秒", "display-pagination": "显示分页", "default-page-size": "默认页面大小", "use-entity-label-tab-name": "在选项卡名称中使用实体标签", @@ -5113,7 +6285,43 @@ "allow-alarms-ack": "允许确认告警", "allow-alarms-clear": "允许清除告警", "display-alarm-activity": "显示告警活动", - "allow-alarms-assign": "允许分配告警" + "allow-alarms-assign": "允许分配告警", + "columns": "列", + "column-settings": "列设置", + "remove-column": "移除列", + "add-column": "添加列", + "no-columns": "没有配置列", + "columns-to-display": "显示的列", + "table-header": "表头", + "header-buttons": "表头按钮", + "table-buttons": "表格按钮", + "pagination": "分页", + "rows": "行", + "timeseries-column-error": "至少应指定一个时间序列列", + "alarm-column-error": "至少应指定一个告警列", + "table-tabs": "表格标签", + "show-cell-actions-menu-mobile": "在移动模式下显示单元格操作下拉菜单" + }, + "wind-speed-direction": { + "layout": "布局", + "layout-default": "默认", + "layout-advanced": "高级", + "layout-simplified": "简化", + "values": "数值", + "wind-direction": "风向", + "center-value": "中心数值", + "icon": "图标", + "arrow": "箭头", + "ticks": "刻度", + "labels-type": "标签类型", + "directional-names": "方向名称", + "degrees": "度数", + "major-ticks": "主要刻度", + "minor-ticks": "次要刻度", + "wind-speed-direction-card-style": "风速和风向卡片样式", + "ticks-color": "刻度颜色", + "ticks-labels-type": "刻度标签类型", + "arrow-color": "箭头颜色" }, "value-source": { "value-source": "值来源", @@ -5124,6 +6332,7 @@ "source-entity-attribute": "源实体属性" }, "widget-font": { + "font-settings": "字体设置", "font-family": "字体", "size": "大小", "relative-font-size": "相对字体大小(百分比)", @@ -5137,7 +6346,10 @@ "font-weight-bolder": "更粗", "font-weight-lighter": "更轻", "color": "颜色", - "shadow-color": "阴影颜色" + "shadow-color": "阴影颜色", + "preview": "预览", + "line-height": "行高", + "auto": "自动" }, "home": { "no-data-available": "暂无数据" @@ -5225,7 +6437,7 @@ "alarms": "告警", "dashboards": "仪表盘", "entities-and-relations": "实体和关系", - "profiles": "配置文件", + "profiles": "配置", "advanced-features": "高级功能", "notification-center": "通知中心", "api-usage": "API 使用情况", @@ -5240,21 +6452,111 @@ }, "devices": { "view-docs": "查看文档", - "inactive": "活动", - "active": "未活动", + "inactive": "非活动", + "active": "活动", "total": "总数" }, "alarms": { "critical": "严重", "assigned-to-me": "分配给我", "total": "总数" + }, + "getting-started": { + "get-started": "开始", + "finish": "完成", + "done-welcome-title": "欢迎加入我们", + "done-welcome-text": "你做得很好!", + "sys-admin": { + "step1": { + "title": "创建租户和租户管理员", + "content": "

租户是拥有或生产设备和资产的个人或组织,租户可以有多个租户管理员用户、客户、设备和资产。

租户管理员可以在租户账户中创建和管理设备、资产、客户和仪表板。

请按照文档进行操作:

", + "how-to-create-tenant": "如何创建租户和租户管理员" + }, + "step2": { + "title": "配置功能:邮件服务", + "content": "

邮件服务配置对于用户激活、密码恢复和报警通知的发送非常重要。

请按照文档进行操作:

", + "how-to-configure-mail-server": "如何配置邮件服务器" + }, + "step3": { + "title": "配置功能:短信提供商", + "content": "

配置短信提供商,通过短信向客户发送报警通知。

请按照文档进行操作:

", + "how-to-configure-sms-provider": "如何配置短信提供商" + }, + "step4": { + "title": "配置功能:双因素认证", + "content": "

通过双因素认证提高平台账户的安全性。

请按照文档进行操作:

", + "how-to-configure-2fa": "如何配置双因素认证" + }, + "step5": { + "title": "配置功能:OAuth 2", + "content": "

通过OAuth 2.0的单点登录功能,简化租户和客户用户的登录过程。

请按照文档进行操作:

", + "how-to-configure-oauth2": "如何配置OAuth 2" + }, + "step6": { + "title": "配置功能:Slack", + "content": "

根据设置的通知规则,通过Slack向租户和客户用户发送通知。

请按照文档进行操作:

", + "how-to-configure-notifications": "如何配置Slack" + } + }, + "tenant-admin": { + "step1": { + "title": "创建设备", + "content": "

让我们通过用户界面将您的第一个设备添加到平台。请按照文档进行操作:

", + "how-to-create-device": "如何创建设备" + }, + "step2": { + "title": "连接设备", + "content-before": "

要连接设备,您需要获取设备凭据。我们建议在本指南中使用默认生成的凭据,即访问令牌。

  • 转到设备表
  • 点击设备行以打开设备详情
  • 点击“复制访问令牌”按钮

使用简单的命令通过HTTP发布数据。不要忘记将$ACCESS_TOKEN替换为您的设备访问令牌:

", + "ubuntu": { + "install-curl": "Ubuntu上安装cURL:" + }, + "macos": { + "install-curl": "MacOS上安装cURL:" + }, + "windows": { + "install-curl": "从Windows 10 b17063开始,cURL已默认可用。" + }, + "replace-access-token": "将$ACCESS_TOKEN替换为您的设备令牌:", + "content-after": "

您还可以使用其他协议,如MQTT、CoAP等。

请按照文档进行操作:

", + "how-to-connect-device": "如何连接设备" + }, + "step3": { + "title": "创建仪表板", + "content": "

创建一个仪表板,用于可视化来自实体(如资产、设备等)的数据。

请按照文档进行操作:

", + "how-to-create-dashboard": "如何创建仪表板" + }, + "step4": { + "title": "配置报警规则", + "alarm-rules": "报警规则", + "content": "

当温度达到25°C时,让我们触发一个报警。请按照文档进行操作:

", + "how-to-configure-alarm-rules": "如何配置报警规则" + }, + "step5": { + "title": "创建报警", + "content-before": "

要触发报警,请发送一个新的温度值,该值为26℃或更高。

", + "replace-access-token": "将$ACCESS_TOKEN替换为您的设备令牌:", + "content-after": "

请按照文档进行操作:

", + "how-to-create-alarm": "如何创建报警" + }, + "step6": { + "title": "创建客户并分配仪表板", + "content": "

通过创建终端用户仪表板,客户用户只能查看自己的设备,另一个客户的数据将被隐藏。

请按照文档进行操作:

", + "how-to-create-customer-and-assign-dashboard": "如何创建客户并分配仪表板" + } + } } }, + "color": { + "color": "颜色" + }, "icon": { "icon": "图标", + "icons": "图标", "select-icon": "选择图标", "material-icons": "素材图标", - "show-all": "显示所有图标" + "show-all": "显示所有图标", + "search-icon": "搜索图标", + "no-icons-found": "没有找到符合'{{iconSearch}}'的图标" }, "phone-input": { "phone-input-label": "手机号码", @@ -5267,14 +6569,15 @@ "widget-action": { "action-cell-button": "动作单元格按钮", "row-click": "点击行时", - "polygon-click": "单击多边形", + "polygon-click": "点击多边形时", "marker-click": "点击标记时", - "circle-click": "在圆圈上单击", - "tooltip-tag-action": "Tooltip tag action", + "circle-click": "点击圆圈时", + "tooltip-tag-action": "文字提示标签操作", "node-selected": "选择节点时", "element-click": "点击HTML元素时", "pie-slice-click": "点击切片时", - "row-double-click": "双击行时" + "row-double-click": "双击行时", + "card-click": "点击卡片时" } }, "paginator": { diff --git a/ui-ngx/src/assets/locale/locale.constant-zh_TW.json b/ui-ngx/src/assets/locale/locale.constant-zh_TW.json index 85c9181ae8..5b415558a1 100644 --- a/ui-ngx/src/assets/locale/locale.constant-zh_TW.json +++ b/ui-ngx/src/assets/locale/locale.constant-zh_TW.json @@ -4476,7 +4476,6 @@ "show-empty-space-hidden-action": "顯示空格而不是隱藏儲存格的按鈕動作", "dont-reserve-space-hidden-action": "不要為隱藏的動作按鈕保留空格", "display-timestamp": "顯示時間戳列", - "display-milliseconds": "顯示毫秒時間戳", "display-pagination": "顯示分頁", "default-page-size": "預設頁面尺寸", "use-entity-label-tab-name": "在分頁標籤名稱中使用實體標籤", diff --git a/ui-ngx/src/assets/metadata/units.json b/ui-ngx/src/assets/metadata/units.json index 3237d6620b..53744cecb7 100644 --- a/ui-ngx/src/assets/metadata/units.json +++ b/ui-ngx/src/assets/metadata/units.json @@ -1316,6 +1316,11 @@ "symbol": "mg/mL", "tags": ["concentration","mass per volume","mg/mL"] }, +{ + "name": "unit.milligram-per-cubic-meter", + "symbol": "mg/m³", + "tags": ["concentration","mass per volume","mg/m³"] +}, { "name": "unit.pound-per-cubic-foot", "symbol": "lb/ft³", diff --git a/ui-ngx/src/environments/environment.prod.ts b/ui-ngx/src/environments/environment.prod.ts index f724eb6687..b76f84da34 100644 --- a/ui-ngx/src/environments/environment.prod.ts +++ b/ui-ngx/src/environments/environment.prod.ts @@ -1,5 +1,5 @@ /// -/// Copyright © 2016-2023 The Thingsboard Authors +/// Copyright © 2016-2024 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. diff --git a/ui-ngx/src/environments/environment.ts b/ui-ngx/src/environments/environment.ts index 82d426e95c..adee999496 100644 --- a/ui-ngx/src/environments/environment.ts +++ b/ui-ngx/src/environments/environment.ts @@ -1,5 +1,5 @@ /// -/// Copyright © 2016-2023 The Thingsboard Authors +/// Copyright © 2016-2024 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. diff --git a/ui-ngx/src/form.scss b/ui-ngx/src/form.scss index 3b29fe986c..ee6d4167cd 100644 --- a/ui-ngx/src/form.scss +++ b/ui-ngx/src/form.scss @@ -1,5 +1,5 @@ /** - * Copyright © 2016-2023 The Thingsboard Authors + * Copyright © 2016-2024 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. @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - @import './scss/constants'; @mixin form-row-column() { @@ -523,6 +522,7 @@ right: 0; background: $tb-primary-color; opacity: 0.04; + pointer-events: none; } } diff --git a/ui-ngx/src/index.html b/ui-ngx/src/index.html index 5b0ca17cd6..7b0a5987c3 100644 --- a/ui-ngx/src/index.html +++ b/ui-ngx/src/index.html @@ -1,6 +1,6 @@